#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
COBOL → JSON（跳过 FILLER）

使用方式：
    $ python cobol2json.py your_file.cob > out.json
"""

import re
import json
from pathlib import Path
from typing import List, Dict, Any

from pilot.job.impl.base_job import BaseJob

# ----------------------------------------------------------------------
# 正则：匹配一条完整的数据描述语句
# ----------------------------------------------------------------------
FIELD_RE = re.compile(
    r"""^\s*
        (?P<level>\d{1,2})\s+                              # 01‑77
        (?P<name>[A-Z0-9\-]+)                              # 字段名
        (?:\s+REDEFINES\s+(?P<redefines>[A-Z0-9\-]+))?    # REDEFINES（可选）
        (?:\s+OCCURS\s+(?P<occurs>\d+)(?:\s+TIMES)?)?       # OCCURS（可选）
        (?:\s+PIC\s+(?P<pic>[^.\s]+))?                    # PIC（可选）
        (?:\s+USAGE\s+(?P<usage>[A-Z0-9\-]+))?            # USAGE（可选）
        (?:\s+VALUE\s+(?P<value>'.*?'|".*?"|\S+))?        # VALUE（可选）
        .*                                                # 其余忽略
    $""",
    re.IGNORECASE | re.VERBOSE,
)
class ParsingDataTOJsonJobBase(BaseJob):
    json_file_path:str = ''
    # ----------------------------------------------------------------------
    # 读取文件（不做任何注释/行号剥离，因为你的示例已经干净）
    # ----------------------------------------------------------------------
    @staticmethod
    def _read_source(path: Path) -> List[str]:
        return [ln.rstrip("\n") for ln in path.read_text(encoding="utf-8").splitlines()
                if ln.strip()]


    # ----------------------------------------------------------------------
    # 只保留 DATA DIVISION → (WORKING‑STORAGE|LINKAGE|LOCAL) SECTION
    # 中以 LEVEL 开头的描述语句
    # ----------------------------------------------------------------------
    @staticmethod
    def _extract_data_section(lines: List[str]) -> List[str]:
        in_data = False
        in_section = False
        result: List[str] = []

        for line in lines:
            u = line.upper()
            if not in_data and "DATA DIVISION" in u:
                in_data = True
                continue
            if in_data and ("PROCEDURE DIVISION" in u or "IDENTIFICATION DIVISION" in u):
                break

            if in_data and ("WORKING-STORAGE SECTION" in u
                           or "LINKAGE SECTION" in u
                           or "LOCAL-STORAGE SECTION" in u):
                in_section = True
                continue

            if in_section:
                # 只保留以数字开头的行（LEVEL 行）
                if re.match(r"^\s*\d{1,2}\b", line):
                    result.append(line)

        return result


    # ----------------------------------------------------------------------
    # 把每条描述语句转成字典（这里直接过滤掉 FILLER）
    # ----------------------------------------------------------------------
    @staticmethod
    def _parse_fields(lines: List[str]) -> List[Dict[str, Any]]:
        fields = []
        for raw in lines:
            m = FIELD_RE.match(raw)
            if not m:
                # 可能是 COPY、EXEC 等非数据描述语句，直接跳过
                continue

            d = m.groupdict()
            name = d["name"].upper()

            # ----- 关键：跳过所有 FILLER -----
            if "FILLER" in name:
                continue

            field = {
                "level": int(d["level"]),                     # 仍保留 level，后面构建层级需要
                "cobol_field_name": name,
                "redefines": d["redefines"].upper() if d["redefines"] else None,
                "occurs": int(d["occurs"]) if d["occurs"] else None,
                "pic": d["pic"].upper() if d["pic"] else None,
                "usage": d["usage"].upper() if d["usage"] else None,
                "value": d["value"][1:-1] if d["value"] else None,   # 去掉外层引号
                "is_copy": False,                                 # 预留字段，当前始终 false
            }
            fields.append(field)
        return fields


    # ----------------------------------------------------------------------
    # 根据 LEVEL 编号建立父‑子层次，并一次性生成最终的 JSON 记录
    # ----------------------------------------------------------------------
    @staticmethod
    def pic_to_java_type(pic: str | None, usage: str | None) -> str:
        """极简的 PIC → Java 类型映射（可自行扩展）"""
        if not pic:
            return "Object"

        pic = pic.upper()
        base = re.sub(r"\(.*?\)", "", pic)          # 去掉括号里的数字

        if "X" in base or "A" in base:
            return "String"
        if "9" in base:
            digits = len(re.sub(r"[^\d]", "", pic))
            if digits <= 9:
                return "int"
            elif digits <= 18:
                return "long"
            else:
                return "java.math.BigDecimal"
        if base.startswith("G"):
            # G(…) DISPLAY‑1 在本例中我们统一当成 String
            return "String"
        if usage and "POINTER" in usage.upper():
            return "Long"

        return "Object"

    @staticmethod
    def java_field_name(cobol_name: str) -> str:
        """COBOL‑NAME → 小驼峰 Java 字段名"""
        parts = cobol_name.lower().split("-")
        return parts[0] + "".join(p.title() for p in parts[1:])

    @staticmethod
    def class_name_from_root(root_name: str) -> str:
        """根记录的名字 → Java 类名（去掉连字符、首字母大写 + “Arg” 后缀）"""
        parts = root_name.lower().split("-")
        camel = "".join(p.title() for p in parts)
        return camel

    def build_hierarchy(self, flat: List[Dict[str, Any]]):
        stack: List[Dict[str, Any]] = []
        roots: List[Dict[str, Any]] = []

        for node in flat:
            # ① 找到正确的父层级（弹出所有 level >= 当前 level 的节点）
            while stack and stack[-1]["level"] >= node["level"]:
                stack.pop()

            parent = stack[-1] if stack else None
            node["parent_name"] = parent["cobol_field_name"] if parent else None

            # ② 生成 java 名称、类型
            node["java_field_name"] = self.java_field_name(node["cobol_field_name"])
            node["type"] = self.pic_to_java_type(node.get("pic"), node.get("usage"))

            # ③ 确定所属的 java_class（根节点决定）
            if parent is None:
                node["java_class"] = self.class_name_from_root(node["cobol_field_name"])
            else:
                node["java_class"] = parent["java_class"]

            # ④ 把子节点挂到父节点的 children（如果以后想要树形结构可保留）
            if parent is None:
                roots.append(node)
            else:
                parent.setdefault("children", []).append(node)

            stack.append(node)

        # --------------------------------------------------------------
        # 把层次树展开为扁平列表（根 + 所有子节点），并去掉内部不需要的键
        # --------------------------------------------------------------
        result: List[Dict[str, Any]] = []
        field_list = []
        def walk(n: Dict[str, Any]):
            # 复制一份，只保留最终需要的字段
            out = {
                "java_class": n["java_class"],
                "java_field_name": n["java_field_name"],
                "cobol_field_name": n["cobol_field_name"],
                "cobol_field_name_jp":"",
                "parent_name": n["parent_name"],
                "redefines": n["redefines"],
                "occurs": n["occurs"],
                "type": n["type"],
                "is_copy": n["is_copy"],
                "value": n["value"],
            }
            result.append(out)
            cobol_field_name =n["cobol_field_name"]

            if cobol_field_name not in field_list:
                field_list.append(n["cobol_field_name"])

            for c in n.get("children", []):
                walk(c)

        for r in roots:
            walk(r)

        return result, field_list


    def merge_by_dot_no_blank(self, lines):
        """
        合并被拆开的 COBOL 语句，并删除空行。
        """
        merged = []
        buffer = ""

        for raw in lines:
            line = raw.rstrip("\n")  # 去掉换行符，保留其它空格

            # ---- 跳过完全空白的行（删除空行）----
            if line.strip() == "":
                continue

            if not buffer:  # 没有正在构建的语句
                buffer = line
            else:
                # 前一行未以句点结束，需要继续合并
                buffer += " " + line.lstrip()  # 去掉本行前导空格，只加一个普通空格

            # ---- 判断是否已经完整（以句点结束）----
            if buffer.rstrip().endswith('.'):
                merged.append(buffer)
                buffer = ""

        # 文件结束时若还有残余（理论上不应出现），也写出
        if buffer:
            merged.append(buffer)

        return merged

    # ----------------------------------------------------------------------
    # 主入口：读取 → 解析 → 层级化 → JSON 输出
    # ----------------------------------------------------------------------
    def main(self):
        lines = self._read_source(Path(self.file_path))
        _edit_lines = self.merge_by_dot_no_blank(lines)
        data_section = self._extract_data_section(_edit_lines)
        flat_fields = self._parse_fields(data_section)          # 已经去掉 FILLER
        final_items, field_list = self.build_hierarchy(flat_fields)

        # 按 java_class、cobol_field_name 排序（可选）
        final_items.sort(key=lambda x: (x["java_class"], x["cobol_field_name"]))

        # ② 中間情報を flat_info.json として保存
        flat_info_file = Path(self.file_path).with_suffix('.json')
        flat_info_file.parent.mkdir(parents=True, exist_ok=True)
        flat_info_file.write_text(
            json.dumps(final_items, indent=4, ensure_ascii=False, default=str),
            encoding='utf-8'
        )

        field_info_file = Path(self.file_path).with_suffix('.field')
        field_info_file.write_text(
            json.dumps(field_list, indent=4, ensure_ascii=False, default=str),
            encoding='utf-8'
        )

        self.json_file_path = str(flat_info_file)

    def run(self):
        self.main()
        super().run()
