import os
from pathlib import Path

class PilotGenerator:
    def __init__(self):
        self.work_space = ""
        self.sub_project_name = ""
        self.sub_source_folder = ""
        self.sub_sub_source_folder_1 = ""

    def generate_code(self, base_work_space: str, sub_project_no: str, sub_project_name: str, sub_source_folder: str, sub_sub_source_folder_1: str):
        project_dir = sub_project_name
        if "design" in sub_project_name and "_design" not in sub_project_name:
            project_dir = sub_project_name.replace("design", "_design")

        self.work_space = f"{base_work_space.rstrip('/')}/{project_dir}/{sub_project_no}_{sub_source_folder}_{sub_sub_source_folder_1}"
        self.sub_project_name = sub_project_name
        self.sub_source_folder = sub_source_folder
        self.sub_sub_source_folder_1 = sub_sub_source_folder_1

        # マインコンバート
        cwd = Path(os.path.dirname(os.path.abspath(__file__)))

        import sys
        # 呼び出し元（実行中のメインスクリプト）のルートパスを特定
        target_project_root_path = Path(os.path.dirname(os.path.abspath(sys.argv[0])))
        
        # コントローラーの相対パスを先に計算
        target_project_sub_project_path = os.path.join(target_project_root_path, 'src', self.sub_project_name, self.sub_source_folder, self.sub_sub_source_folder_1)
        target_project_sub_controller_path = os.path.join(target_project_sub_project_path, self.sub_source_folder + '_' + self.sub_sub_source_folder_1 + '_control.py')
        rel_controller_path = os.path.relpath(target_project_sub_controller_path, target_project_root_path).replace('\\', '/')

        # サンプルファイル作成
        print('CONFIGファイルを作成する')
        sample_config_file_path = os.path.join(cwd, 'template_create', 'config', 'properties.py')
        replacements = {
            "WORK_SPACE": self.work_space,
            "PROJECT_NAME": os.path.basename(target_project_root_path),
            "CONTROLLER_FILE": rel_controller_path,
            "STEP_NAME": "step_000,step_010,step_011"
        }
        target_project_config_path = os.path.join(target_project_root_path, 'config', sub_project_no + '_' + self.sub_project_name + '_' + self.sub_source_folder + '_' + self.sub_sub_source_folder_1+'.properties')
        self.read_replace_create_file(sample_config_file_path, replacements, Path(target_project_config_path))

        print('Main Jobファイルを作成する')
        # サブファイルコントロール、ジョブ、ユニットファイルの作成
        # (target_project_sub_project_path は上で定義済み)
        # サンプルサブコントロールファイルの作成
        sample_job_file_path = os.path.join(cwd, 'template_create', 'children_template', 'job.py')
        replacements_job = {}
        target_project_sub_job_path = os.path.join(target_project_sub_project_path, self.sub_source_folder + '_' + self.sub_sub_source_folder_1 + '_job.py')
        self.read_replace_create_file(sample_job_file_path, replacements_job, Path(target_project_sub_job_path))

        print('Main Unitファイルを作成する')
        sample_unit_file_path = os.path.join(cwd, 'template_create', 'children_template', 'unit.py')
        replacements_unit = {
            "JOB_PACKAGE":  self.sub_project_name + '.'+ self.sub_source_folder + '.' + self.sub_sub_source_folder_1 + '.' + os.path.basename(target_project_sub_job_path).split('.')[0],
            "GYOMU_JOB_PACKAGE_000":  self.sub_project_name + '.' + self.sub_source_folder + '.' + self.sub_sub_source_folder_1 + '.jobs.job_000',
            "GYOMU_JOB_PACKAGE_010":  self.sub_project_name + '.' + self.sub_source_folder + '.' + self.sub_sub_source_folder_1 + '.jobs.job_010',
            "GYOMU_JOB_PACKAGE_011":  self.sub_project_name + '.' + self.sub_source_folder + '.' + self.sub_sub_source_folder_1 + '.jobs.job_011'
        }
        target_project_unit_path = os.path.join(target_project_sub_project_path, self.sub_source_folder + '_' + self.sub_sub_source_folder_1 + '_unit.py' )
        self.read_replace_create_file(sample_unit_file_path, replacements_unit, Path(target_project_unit_path))

        print('Main Controllerファイルを作成する')
        sample_controller_file_path = os.path.join(cwd, 'template_create', 'children_template', 'controller.py')
        replacements_control = {
            "UNIT_PACKAGE": self.sub_project_name + '.'+ self.sub_source_folder + '.'+ self.sub_sub_source_folder_1 + '.' + os.path.basename(target_project_unit_path).split('.')[0]
        }
        # (target_project_sub_controller_path は上で定義済み)
        self.read_replace_create_file(sample_controller_file_path, replacements_control, Path(target_project_sub_controller_path))

        init_file_path = Path(os.path.join(target_project_sub_project_path, '__init__.py'))
        self.create_file(init_file_path,'')

        print('業務Job用フォルダを作成する')
        job_file_path = Path(os.path.join(target_project_sub_project_path,'jobs'))
        job_file_path.mkdir(parents=True, exist_ok=True)
        sample_job000_file_path = os.path.join(cwd, 'template_create', 'children_template', 'job', 'job_000.py')
        sample_job010_file_path = os.path.join(cwd, 'template_create', 'children_template', 'job', 'job_010.py')
        sample_job011_file_path = os.path.join(cwd, 'template_create', 'children_template', 'job', 'job_011.py')
        sample_add_job_file_path = os.path.join(cwd, 'template_create', 'children_template', 'job', 'add_job.py')
        replacements_job000 = {
            'JOB_PACKAGE': self.sub_project_name + '.'+ self.sub_source_folder + '.' + self.sub_sub_source_folder_1 + '.'  + os.path.basename(target_project_sub_job_path).split('.')[0]
        }
        target_project_job000_path = os.path.join(target_project_sub_project_path, 'jobs','job_000.py')
        target_project_job010_path = os.path.join(target_project_sub_project_path, 'jobs','job_010.py')
        target_project_job011_path = os.path.join(target_project_sub_project_path, 'jobs', 'job_011.py')
        self.read_replace_create_file(sample_job000_file_path, replacements_job000, Path(target_project_job000_path))
        replacements_job010 = {
            'JOB_NAME':'Job_010',
            'JOB_PACKAGE': self.sub_project_name + '.'+ self.sub_source_folder + '.' + self.sub_sub_source_folder_1 + '.'  + os.path.basename(target_project_sub_job_path).split('.')[0],
            'SUB_SOURCE_FOLDER': self.sub_source_folder,
            'SUB_SUB_SOURCE_FOLDER_1': self.sub_sub_source_folder_1
        }
        self.read_replace_create_file(sample_job010_file_path, replacements_job010, Path(target_project_job010_path))
        replacements_job011 = {
            'JOB_NAME': 'Job_011',
            'JOB_PACKAGE': self.sub_project_name + '.'+ self.sub_source_folder + '.' + self.sub_sub_source_folder_1 + '.'  + os.path.basename(target_project_sub_job_path).split('.')[0]
        }
        self.read_replace_create_file(sample_job011_file_path, replacements_job011, Path(target_project_job011_path))

        target_project_add_job_path = os.path.join(target_project_sub_project_path, 'jobs', 'add_job.py')
        rel_pilot_generator_path = os.path.relpath(target_project_root_path, os.path.dirname(target_project_add_job_path)).replace('\\', '/')
        rel_properties_file_path = os.path.relpath(target_project_config_path, os.path.dirname(target_project_add_job_path)).replace('\\', '/')
        replacements_add_job = {
            'PILOT_GENERATOR_PATH': rel_pilot_generator_path,
            'PROPERTIES_FILE_REL_PATH': rel_properties_file_path
        }
        self.read_replace_create_file(sample_add_job_file_path, replacements_add_job, Path(target_project_add_job_path))

        init_job_file_path = Path(os.path.join(target_project_sub_project_path, 'jobs', '__init__.py'))
        self.create_file(init_job_file_path,'')

        print('input用フォルダ、テンプレートファイルを作成する')
        input_folder_path = os.path.join(target_project_root_path, 'input', self.sub_source_folder, self.sub_sub_source_folder_1, 'step_010')
        Path(input_folder_path).mkdir(parents=True, exist_ok=True)
        template_prompt_path = Path(os.path.join(input_folder_path, 'template.prompt'))
        self.create_file(template_prompt_path, '')

        print('Main controllerファイルを作成する')
        # サンプルパス
        sample_main_controller_file_path = os.path.join(cwd, 'template_create', 'main_convert.py')
        # パラメーター
        replacements = {
            "CONTROLLER_PACKAGE": self.sub_project_name + '.' + self.sub_source_folder + '.' + self.sub_sub_source_folder_1 +'.' + os.path.basename(target_project_sub_controller_path).split('.')[0],
            "PYTHON_CONFIG_PROPERTIES": sub_project_no + '_' + self.sub_project_name + '_' + self.sub_source_folder + '_' + self.sub_sub_source_folder_1 + '.properties'
        }
        # 目標ファイルパス
        target_project_main_controller_path = Path(os.path.join(target_project_root_path, self.sub_project_name + '_'
                                                                + self.sub_source_folder + '_' + self.sub_sub_source_folder_1 +'_controller.py'))
        self.read_replace_create_file(sample_main_controller_file_path, replacements, target_project_main_controller_path)


    def add_job(self, properties_file: str, job_no: str, base_class_type: str, unit_file: str = None):
        properties_file = os.path.abspath(properties_file)

        if not os.path.exists(properties_file):
            print(f"Properties file not found: {properties_file}")
            return

        with open(properties_file, 'r', encoding='utf-8') as f:
            prop_content = f.read()

        import re
        ctrl_match = re.search(r'^controller_file=(.*)$', prop_content, flags=re.MULTILINE)
        if not ctrl_match:
            print("Could not find controller_file in properties file.")
            return

        controller_rel_path = ctrl_match.group(1).strip()
        config_dir = os.path.dirname(properties_file)
        project_root = os.path.dirname(config_dir)

        controller_file = os.path.abspath(os.path.join(project_root, controller_rel_path))

        if not os.path.exists(controller_file):
            print(f"Controller file not found: {controller_file}")
            return

        with open(controller_file, 'r', encoding='utf-8') as f:
            controller_content = f.read()

        match = re.search(r'from\s+([\w\.]+)\s+import\s+Unit', controller_content)
        if not match:
            print("Could not find Unit import in Controller.")
            return

        unit_module_full = match.group(1)
        parts = unit_module_full.split('.')
        if len(parts) < 4:
            print("Unexpected module structure.")
            return

        sub_project_name = parts[0]
        sub_source_folder = parts[1]
        sub_sub_source_folder_1 = parts[2]
        
        last_part = parts[-1].replace('_unit', '_job')
        job_package = '.'.join(parts[:-1]) + '.' + last_part

        if unit_file:
            unit_path = os.path.abspath(unit_file)
            target_sub_project_dir = os.path.dirname(unit_path)
        else:
            # src ディレクトリから探す
            src_dir_match = re.search(r'(.*?[\\/]src[\\/])', controller_file)
            if src_dir_match:
                src_dir = src_dir_match.group(1)
                unit_path = os.path.join(src_dir, *parts) + '.py'
                target_sub_project_dir = os.path.dirname(unit_path)
            else:
                controller_dir = os.path.dirname(controller_file)
                unit_path = os.path.join(controller_dir, parts[-1] + '.py')
                target_sub_project_dir = controller_dir

        job_folder = os.path.join(target_sub_project_dir, 'jobs')
        Path(job_folder).mkdir(parents=True, exist_ok=True)
        job_file = os.path.join(job_folder, f'job_{job_no}.py')

        if os.path.exists(job_file):
            print(f"job_{job_no} が既に存在するため、生成をスキップします。")
            return

        print(f"Adding Job {job_no} with base class {base_class_type}...")

        cwd = Path(os.path.dirname(os.path.abspath(__file__)))
        # 1. Select template
        if base_class_type == 'prompt':
            sample_path = os.path.join(cwd, 'template_create', 'children_template', 'job', 'job_010.py')
        elif base_class_type == 'generateJson':
            sample_path = os.path.join(cwd, 'template_create', 'children_template', 'job', 'job_011.py')
        elif base_class_type == 'generateText':
            sample_path = os.path.join(cwd, 'template_create', 'children_template', 'job', 'job_011.py')
        elif base_class_type == 'Job':
            sample_path = os.path.join(cwd, 'template_create', 'children_template', 'job', 'job_sample.py')
        else:
            print(f"不明な base_class_type です: {base_class_type}")
            return

        import importlib.util
        spec = importlib.util.spec_from_file_location("template_module", sample_path)
        template_module = importlib.util.module_from_spec(spec)
        spec.loader.exec_module(template_module)
        file_content = template_module.create_file.detail_prompt

        # For generateText, patch the generateJson template
        if base_class_type == 'generateText':
            file_content = file_content.replace('GenerateJsonBaseJob', 'GenerateTextBaseJob')
            file_content = file_content.replace('generateJsonBaseJob', 'generateTextBaseJob')

        replacements = {
            'JOB_NAME': f'Job_{job_no}',
            'JOB_PACKAGE': job_package,
            'SUB_SOURCE_FOLDER': sub_source_folder,
            'SUB_SUB_SOURCE_FOLDER_1': sub_sub_source_folder_1
        }
        
        after_replace_content = self.replace_template_vars(file_content, replacements)
        self.create_file(Path(job_file), after_replace_content)
        print(f"[Done] Created Job file: {job_file}")

        if base_class_type == 'prompt':
            input_folder_path = os.path.join(project_root, 'input', sub_source_folder, sub_sub_source_folder_1, f'step_{job_no}')
            Path(input_folder_path).mkdir(parents=True, exist_ok=True)
            template_prompt_path = Path(os.path.join(input_folder_path, 'template.prompt'))
            if not os.path.exists(template_prompt_path):
                self.create_file(template_prompt_path, '')
                print(f"[Done] Created template file: {template_prompt_path}")

        # 2. Update unit.py
        
        if os.path.exists(unit_path):
            with open(unit_path, 'r', encoding='utf-8') as f:
                unit_content = f.read()

            import_stmt = f"from {sub_project_name}.{sub_source_folder}.{sub_sub_source_folder_1}.jobs.job_{job_no} import Job_{job_no}"
            if import_stmt not in unit_content:
                matches = list(re.finditer(r'^from .* import Job_\d+', unit_content, flags=re.MULTILINE))
                if matches:
                    insert_pos = matches[-1].end()
                    unit_content = unit_content[:insert_pos] + '\n' + import_stmt + unit_content[insert_pos:]
                else:
                    unit_content = import_stmt + '\n' + unit_content

            elif_stmt = f"        elif current_step == 'step_{job_no}':\n            return Job_{job_no}()\n"
            if f"Job_{job_no}()" not in unit_content:
                else_match = re.search(r'^(\s*)else:', unit_content, flags=re.MULTILINE)
                if else_match:
                    insert_pos = else_match.start()
                    unit_content = unit_content[:insert_pos] + elif_stmt + unit_content[insert_pos:]
                else:
                    print("Warning: could not find 'else:' block in unit.py to inject the job")

            self.create_file(Path(unit_path), unit_content)
            print(f"[Done] Updated unit file: {unit_path}")
        else:
            print(f"Warning: Unit file not found at {unit_path}")

        # 3. Update properties file
        # properties_file is already resolved and read into prop_content
        steps_match = re.search(r'^steps=(.*)$', prop_content, flags=re.MULTILINE)
        if steps_match:
            steps_list = [s for s in steps_match.group(1).split(',') if s.strip()]
            new_step = f'step_{job_no}'
            if new_step not in steps_list:
                inserted = False
                for i, step in enumerate(steps_list):
                    match = re.search(r'step_(\d+)', step)
                    if match:
                        if int(job_no) < int(match.group(1)):
                            steps_list.insert(i, new_step)
                            inserted = True
                            break
                if not inserted:
                    if 'step_end' in steps_list:
                        steps_list.insert(steps_list.index('step_end'), new_step)
                    else:
                        steps_list.append(new_step)
                
                new_steps_str = 'steps=' + ','.join(steps_list)
                prop_content = prop_content[:steps_match.start()] + new_steps_str + prop_content[steps_match.end():]
                self.create_file(Path(properties_file), prop_content)
                print(f"[Done] Updated properties file: {properties_file}")

    def read_replace_create_file(self, sample_file_path:str, replacements, target_file_path):
        import importlib.util
        spec = importlib.util.spec_from_file_location("template_module", sample_file_path)
        template_module = importlib.util.module_from_spec(spec)
        spec.loader.exec_module(template_module)
        file_content = template_module.create_file.detail_prompt

        after_replace_content = self.replace_template_vars(file_content, replacements)
        self.create_file(target_file_path, after_replace_content)

    @staticmethod
    def replace_template_vars(template: str, replacements: dict) -> str:
        result = template
        if replacements:
            for key, value in replacements.items():
                placeholder = f"{{{{{key}}}}}"
                result = result.replace(placeholder, str(value))
        return result

    @staticmethod
    def create_file(target_path, target_file_content):
        target_path.parent.mkdir(parents=True, exist_ok=True)
        with open(target_path, 'w', encoding='utf-8') as f:
            f.write(target_file_content)
