import os
import re
from pathlib import Path
from typing import List, Set, Any, Dict

import xml.etree.ElementTree as ET

from pilot.base.file_operation import read_json_file_lines


def load_cobol_keywords_list() -> List[str]:
    """
    XMLファイルからキーワードをロードする
    """
    cwd = os.getcwd()
    # パス構成はプロジェクト構成に合わせて適宜変更してください
    xml_file = os.path.join(cwd, 'input', 'xml', 'cobol_keywords.xml')

    if not os.path.exists(xml_file):
        # ファイルが見つからない場合のフォールバックやエラーログなど
        print(f"Warning: Keywords file not found at {xml_file}")
        return []

    tree = ET.parse(xml_file)
    root = tree.getroot()
    keywords = [keyword.text.upper() for keyword in root.findall('keyword')]
    return keywords

# ----------------------------------------------------------------------
# 1️⃣ 加载关键字（XML）
# ----------------------------------------------------------------------
def load_cobol_keywords_set() -> Set[str]:
    """
    XMLファイルからキーワードをロードする
    """
    cwd = os.getcwd()
    # パス構成はプロジェクト構成に合わせて適宜変更してください
    xml_file = os.path.join(cwd, 'input', 'xml', 'cobol_keywords.xml')

    if not os.path.exists(xml_file):
        # ファイルが見つからない場合のフォールバックやエラーログなど
        print(f"Warning: Keywords file not found at {xml_file}")

    tree = ET.parse(xml_file)
    root = tree.getroot()
    return {kw.text.strip().upper() for kw in root.findall(".//keyword") if kw.text}

# ----------------------------------------------------------------------
# 2️⃣ 正则：捕获单个标识符或 “FIELD OF RECORD”
# ----------------------------------------------------------------------
IDENTIFIER_RE = re.compile(
    r"""(?<!['"])               # 前面不是单引号，防止匹配常量内部
        \b([A-Z][A-Z0-9-]*)     # 第一个标识符（字段或变量）
        (?:\s+OF\s+\b([A-Z][A-Z0-9-]*))?  # 可选的 “OF RECORD” 部分
    """,
    re.IGNORECASE | re.VERBOSE,
)

def extract_variables(text: str, keywords: Set[str]) -> Set[str]:
    """
    抽取变量，遇到 OF 时返回完整的 “FIELD OF RECORD”。
    """
    result: Set[str] = set()

    for m in IDENTIFIER_RE.finditer(text):
        field = m.group(1)          # 必定存在
        record = m.group(2)         # 可能为 None

        if record:   # 出现了 OF
            whole = f"{field} OF {record}"
            # 整体如果恰好是关键字（极少见）则不加入
            if whole.upper() not in keywords:
                result.add(whole)
        else:        # 只有单个标识符
            if field.strip().upper() not in keywords:
                result.add(field)

    return result


# --------------------------------------------------------------
# 1️⃣ 工具函式
# --------------------------------------------------------------

def to_camel_case(s: str) -> str:
    """
    把全大寫、以 '-' 或 '_' 分隔的 Cobol 名稱
    轉成 Java 常用的 lowerCamelCase。
    示例:  'WSV2-TEKIO3' -> 'wsv2Tekio3'
    """
    parts = s.replace('-', ' ').replace('_', ' ').split()
    if not parts:
        return ""
    first = parts[0].lower()                     # 首個單詞全小寫
    rest  = [p.title() for p in parts[1:]]       # 後續單詞首字母大寫
    return first + "".join(rest)

def find_by_field(json_list, target_str, field_key):
    for item in json_list:
        _value = item.get(field_key).strip()
        if target_str.strip().upper() == _value.upper():
            return item
    return None


def merge_json_files(json_paths: List[Path]) -> List[Any]:
    """
    把多个 JSON 文件合并为一个列表。
    - 如果文件根对象是 dict，自动包装成长度为 1 的 list。
    - 如果是 list，则直接 extend。
    """
    merged: List[Any] = []
    for p in json_paths:
        data = read_json_file_lines(p)

        if isinstance(data, dict):
            data = [data]
        elif not isinstance(data, list):
            raise TypeError(f"{p} 的根对象既不是 list 也不是 dict")

        merged.extend(data)
    return merged


def find_target_files(root_dir: Path) -> List[Path]:
    """
    在 root_dir（包括子目录）中递归查找所有以 'sub_method.json' 结尾的文件。
    返回按字典序排序后的 Path 列表，保证顺序可重复。
    """

    json_files = [
        p for p in root_dir.rglob("*")
        if p.is_file() and p.suffix.lower() == ".json"
    ]
    return json_files

def add_indent_from_code(item, reference_key, edited_key):
    """
    把 `code` 前面的空格数复制到 `comment` 前面。

    参数
    ----
    item: dict
        必须包含 `code` 与 `comment` 两个键，且值都是字符串。

    返回
    ----
    dict
        同一个字典，只是 `comment` 已被加上前导空格。
    """
    code = item.get(reference_key, "")
    comment = item.get(edited_key, "")

    # 统计 code 开头的空格数（只算普通空格，不算 Tab）
    leading_spaces = len(code) - len(code.lstrip(" "))

    # 把空格加到 comment 前面
    item[edited_key] = (" " * leading_spaces) + comment
    return item

