import sys
import re
from collections import defaultdict
from typing import List, Dict
from pathlib import Path

from pilot.job.impl.base_job import BaseJob

class SplitProcedureBaseJob(BaseJob):
    """
    COBOLソースを行単位で解析し、特定のコメントヘッダー
    (* ... *) を区切りとして別ファイルに分割保存するジョブ。
    """

    SECTION_HEADER_PATTERN_CBL = re.compile(
        r"^\s*([A-Z0-9\-_]+)\s+SECTION",
        re.IGNORECASE
    )

    _SECTION_TITLE_CHAR = (
        r"["
        # ASCII 大写、数字、下划线、半角连字符
        r"A-Z0-9\-_"
        # 全角英字母、全角数字（U+FF10‑FF19, U+FF21‑FF3A）
        r"Ａ-Ｚ０-９"
        # 平假名、片假名
        r"\u3040-\u309F\u30A0-\u30FF"
        # 常用汉字（CJK统一汉字）
        r"\u4E00-\u9FFF"
        # 全角标点/字母（包括全角下划线、全角破折号等）
        r"\uFF01-\uFF5E"
        # 常见的半/全角破折号、长横线等
        r"\u2010-\u2015\u2212"
        r"]"
    )

    # --------------------------------------------------------------
    # 2️⃣ 完整的 SECTION 标题正则
    # --------------------------------------------------------------
    SECTION_HEADER_PATTERN_IPO = re.compile(
        rf"""^                     # 行首（忽略前导空白）
            \s*                   # 任意数量的空格/制表符（可选）
            (                     # ← 捕获组 1：节标题本体
                {_SECTION_TITLE_CHAR}+   # 至少一个合法字符
            )
            \s*                   # 标题与关键字之间的可选空白
            SECTION               # 固定关键字（不区分大小写）
            [\.\:]*               # “SECTION” 后可出现句点、冒号或其它标点（0‑多次）
            $                     # 行尾
        """,
        re.IGNORECASE | re.VERBOSE
    )

    section_order_list = []
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # 分割結果ファイルのパスリストを保持
        self.generated_files: List[Path] = []

    def run(self):
        """
        ジョブ実行メイン処理
        """
        try:
            section_flg = self.__getattribute__('section_flg')
            src_path = Path(self.file_path)
            
            # 1. 読み込み
            if not src_path.is_file():
                print(f"Error: Source file not found -> {src_path}", file=sys.stderr)
                return

            encoding = 'utf-8'
            lines = src_path.read_text(encoding=encoding).splitlines(keepends=True)

            # 2. 分割ロジック実行
            if section_flg:
                blocks, section_order_list = self._split_procedure_sections(lines)
            else:
                blocks, section_order_list = self._split_by_line(lines)

            if blocks:
                # 3. 出力先ディレクトリ
                _file_name = Path(self.file_path).name.split('.')[0]
                out_dir = Path(self.file_path).parent / _file_name
                
                # 4. 書き出し
                self.generated_files = self._write_blocks(blocks, out_dir)

                self.section_order_list = section_order_list
            else:
                print("Warning: No blocks detected.", file=sys.stderr)

        except Exception as e:
            # エラーハンドリング
            self.logger.error(f"{__name__}異常終了. {e}")
            return

        # 親クラスのrunを実行
        super().run()

    def _split_by_line(self, lines: List[str]):
        """
        タイトル行に基づいてコードをブロック分割し、
        { sanitized_title : block_lines } の形式で返却する。
        """
        blocks: Dict[str, List[str]] = {}
        cur_name: str | None = None
        cur_body: List[str] = []
        section_order_list = []

        for raw in lines:
            if self._is_title_line(raw):
                # 前のブロックの処理を終了
                if cur_name is not None:
                    blocks[cur_name] = cur_body

                # 新しいブロックの開始
                raw_title = self._extract_title(raw)
                cur_name = self._sanitize_filename(raw_title)
                cur_body = []
            else:
                # ブロック内部の処理
                if cur_name is not None:
                    cur_body.append(raw)
                    # 元のロジックを維持: 本文の1行目を使ってファイル名を再決定している処理
                    if cur_body:
                        # cur_body[0] は常にブロックの先頭行
                        cur_name = cur_body[0].translate(str.maketrans("", "", ".\n")).replace("-", "_").strip()

        # 最後のブロックを保存
        if cur_name is not None:
            blocks[cur_name] = cur_body
            if cur_name not in section_order_list:
                section_order_list.append(cur_name)
        return blocks, section_order_list

    def _write_blocks(self, blocks: Dict[str, List[str]], out_dir: Path) -> List[Path]:
        """
        各ブロックを個別の *.cob* ファイルとして書き出す。
        同名ファイルの競合は自動的に処理（連番付与）する。
        """
        out_dir.mkdir(parents=True, exist_ok=True)
        counter = defaultdict(int)
        created_files = []

        for title, lines in blocks.items():
            if not lines:
                continue
            
            counter[title] += 1
            suffix = f"_{counter[title]}" if counter[title] > 1 else ""
            # ファイル名生成
            if Path(self.file_path).name.endswith('.ipo'):
                filename = out_dir / f"{title}{suffix}.ipo"
            else:
                filename = out_dir / f"{title}{suffix}.cob"
            
            with filename.open("w", encoding="utf-8", newline="\n") as fp:
                fp.writelines(lines)
            
            created_files.append(filename)
        
        return created_files

    def _is_title_line(self, line: str) -> bool:
        """
        対象の行がブロックタイトル（区切り行）であるかを判定する。
        """
        stripped = line.strip()
        # 先頭と末尾が '*' で囲まれているか
        if not (stripped.startswith("*") and stripped.endswith("*")):
            return False
        # 両端の '*' を除いた内部にさらに '*' が含まれていないか確認
        inner = stripped[1:-1]
        return "*" not in inner

    def _extract_title(self, line: str) -> str:
        """
        タイトル行から実際のブロック名を抽出する。
        """
        inner = line.strip()[1:-1]
        return inner.strip()

    def _sanitize_filename(self, name: str) -> str:
        """
        ファイル名として不正な文字を置換し、安全な文字列にする。
        """
        name = name.strip()
        # ファイル名に使えない記号をアンダースコアに置換
        for ch in r'\/:*?"<>|':
            name = name.replace(ch, "_")
        # 連続する空白をアンダースコアに置換
        name = re.sub(r"\s+", "_", name)
        return name

    def _split_procedure_sections(self, procedure_lines: List[str]):

        """
        PROCEDURE DIVISION 内容を SECTION ごとに分割
        """
        self.logger.debug("PROCEDURE DIVISION を SECTION に分割中")

        blocks: Dict[str, List[str]] = {}

        # SECTION で分割
        current_section = None
        current_lines = []

        section_order_list = []

        file_name = Path(self.file_path).name

        for line in procedure_lines:
            # SECTION 開始を確認
            if file_name.endswith('.ipo'):
                match = self.SECTION_HEADER_PATTERN_IPO.match(line.strip())
            else:
                match = self.SECTION_HEADER_PATTERN_CBL.match(line)
            if match:
                # 新しい SECTION を開始
                current_section = match.group(1).upper()
                current_lines = [line]
                self.logger.debug(f"SECTION '{current_section}' を発見しました")
            else:
                # SECTION 内の行を追加
                if current_section is not None:
                    current_lines.append(line)

            # 最後の SECTION を保存
            if current_section is not None and current_lines:
                if current_section not in section_order_list:
                    section_order_list.append(current_section)
                blocks[current_section] = current_lines.copy()

        return blocks, section_order_list