#!/usr/bin/env python3

from pathlib import Path
from collections import defaultdict
import sys
from typing import Optional

HEADER = '''
# This file has been generated by src/utils/osc_paths/path_makers.py.
# Do not edit it, edit 'all_paths' file and run 'path_makers.py'.'''


class OscPath:
    def __init__(self, line: str):
        value, _, types = line.partition(' ')
        self.value = value.strip()
        self.types = types.strip()
        self.key = self.value.rpartition('/')[2].upper()
        self.input_comments = ''
    
    def add_comment(self, line: str):
        if self.input_comments:
            self.input_comments += '\n'
        self.input_comments += line.strip()
        
    def export(self) -> str:
        if not self.input_comments and not self.types:
            return f"{self.key} = '{self.value}'"
        
        types_str = ''
        if self.types:
            types_str = f' (arg types: {self.types})'

        if "'" in self.input_comments or '\n' in self.input_comments:
            return (f"{self.key} = '{self.value}'\n"
                    f"'''{self.input_comments}{types_str}'''\n")
        return (f"{self.key} = '{self.value}'\n"
                f"'{self.input_comments}{types_str}'\n")


class FilePrepare:
    def __init__(self):
        self.imports = set[str]()
        self.defines = dict[str, str]()
        self.osc_paths = list[OscPath]()
    
    @property
    def contents(self) -> str:
        imports = '\n'.join([
            f'from . import {m}' for m in sorted(self.imports)])
        defines = '\n'.join([op.export() for op in self.osc_paths])
        return '\n\n'.join([HEADER, imports, defines])


if __name__ == '__main__':
    paths_file = Path(__file__).parent / 'all_paths'

    with open(paths_file, 'r') as f:
        contents = f.read()

    all_paths = contents.splitlines()

    code_root = paths_file.parent
    while code_root.name != 'RaySession':
        code_root = code_root.parent
        if code_root.name == '/':
            print('this file is not in a RaySession folder, exit.')
            sys.exit(1)

    root = code_root / 'src' / 'shared' / 'osc_paths'
    root.mkdir(exist_ok=True)

    file_prepares = defaultdict[Path, FilePrepare](FilePrepare)
    current_osc_path: Optional[OscPath] = None

    for osc_str in all_paths:
        osc_str = osc_str.strip()
        if not osc_str.startswith('/'):
            if current_osc_path is not None:
                current_osc_path.add_comment(osc_str)
            continue

        p = root / osc_str[1:]
        pdir = p.parent

        current_osc_path = OscPath(osc_str)
        file_prepares[pdir].osc_paths.append(current_osc_path)
        
        while root in pdir.parents or root == pdir.parent:
            file_prepares[pdir.parent].imports.add(pdir.name)
            pdir = pdir.parent

    for path, file_prepare in file_prepares.items():
        path.mkdir(exist_ok=True, parents=True)
        
        init_py = path / '__init__.py'
        with open (init_py, 'w') as f:
            f.write(file_prepare.contents)