from __future__ import annotations

import argparse
import json
import sys
import time
from pathlib import Path

import yaml

SCRIPT_DIR = Path(__file__).resolve().parent
if str(SCRIPT_DIR) not in sys.path:
    sys.path.insert(0, str(SCRIPT_DIR))

from runtime_config import add_config_source_args, load_runtime_config


def parse_month_number(raw: object) -> int:
    if raw is None:
        return 1
    text = str(raw).strip()
    digits = "".join(ch for ch in text if ch.isdigit())
    if digits:
        m = int(digits[-2:] if len(digits) > 2 else digits)
        return max(1, min(12, m))
    return 1


def parse_args() -> argparse.Namespace:
    p = argparse.ArgumentParser(description="Run flow18 rejection pipeline in one command.")
    p.add_argument("--python", default=sys.executable, help="Python executable path")
    add_config_source_args(p, default_config=Path(r"D:\projects\skills\vip-report\config.yaml"))
    p.add_argument("--session", default="vip-report-monthly-sales")
    p.add_argument("--download-dir", default=r"C:\vipdata")
    p.add_argument("--report-year", type=int, default=0)
    p.add_argument("--report-month", default="")
    p.add_argument("--max-retries", type=int, default=15)
    p.add_argument("--scene-file", default="")
    p.add_argument("--goods-file", default="")
    p.add_argument("--skip-compose", action="store_true")
    return p.parse_args()


def run_step(step_index: int, total: int, cmd: list[str]) -> tuple[str, dict[str, object] | None]:
    import subprocess

    print(f"[STEP {step_index}/{total}] {' '.join(cmd)}")
    result = subprocess.run(cmd, text=True, capture_output=True)
    stdout_text = result.stdout or ""
    if stdout_text.strip():
        print(stdout_text)
    if result.returncode != 0:
        err = (result.stderr or "").strip()
        out = stdout_text.strip()
        err_tail = err[-4000:] if len(err) > 4000 else err
        out_tail = out[-2000:] if len(out) > 2000 else out
        raise RuntimeError(
            "STEP_FAILED\n"
            f"step={step_index}\n"
            f"command={' '.join(cmd)}\n"
            f"returncode={result.returncode}\n"
            f"stdout_tail=\n{out_tail}\n"
            f"stderr_tail=\n{err_tail}\n"
        )

    parsed_json: dict[str, object] | None = None
    for line in stdout_text.splitlines():
        s = line.strip()
        if s.startswith("{") and s.endswith("}"):
            try:
                parsed_json = json.loads(s)
            except Exception:
                pass
    return stdout_text, parsed_json


def build_month_values(cfg: dict[str, object], report_year_arg: int, report_month_arg: str) -> tuple[int, str]:
    report_cfg = cfg.get("report", {}) if isinstance(cfg.get("report"), dict) else {}
    year = int(report_year_arg or report_cfg.get("year", 2026))
    month_num = parse_month_number(report_month_arg or report_cfg.get("month_cn", "1"))
    return year, f"{month_num:02d}"


def main() -> None:
    args = parse_args()

    default_config_path = Path(args.config or r"D:\projects\skills\vip-report\config.yaml").resolve()
    cfg = load_runtime_config(args, default_config=default_config_path)
    workdir = Path(cfg["paths"]["workdir"]).resolve()
    year, month = build_month_values(cfg, args.report_year, args.report_month)

    tmp_config_path: Path | None = None
    common_cfg_args: list[str]
    if args.config_source == "yaml":
        common_cfg_args = ["--config", str(default_config_path)]
    else:
        tmp_config_path = workdir / f"tmp-flow18-config-{year}{month}-{time.time_ns()}.yaml"
        tmp_config_path.write_text(yaml.safe_dump(cfg, allow_unicode=True, sort_keys=False), encoding="utf-8")
        common_cfg_args = ["--config", str(tmp_config_path)]

    download_dir = Path(args.download_dir).resolve()
    download_dir.mkdir(parents=True, exist_ok=True)

    try:
        steps: list[list[str]] = [
            [
                args.python,
                str(SCRIPT_DIR / "sync_compass_rejection_analysis_capture.py"),
                *common_cfg_args,
                "--session",
                args.session,
                "--report-year",
                str(year),
                "--report-month",
                month,
            ],
            [
                args.python,
                str(SCRIPT_DIR / "sync_compass_rejection_scene_download.py"),
                *common_cfg_args,
                "--session",
                args.session,
                "--report-year",
                str(year),
                "--report-month",
                month,
                "--download-dir",
                str(download_dir),
                "--max-retries",
                str(int(args.max_retries)),
            ],
        ]

        total_steps = 7 if args.skip_compose else 8

        _, step2_json = run_step(1, total_steps, steps[0])
        _, step_scene_json = run_step(2, total_steps, steps[1])
        scene_file = str(args.scene_file or ((step_scene_json or {}).get("savedAs") or ""))

        step3_cmd = [
            args.python,
            str(SCRIPT_DIR / "load_compass_rejection_scene_to_mysql.py"),
            *common_cfg_args,
            "--download-dir",
            str(download_dir),
            "--report-year",
            str(year),
            "--report-month",
            month,
        ]
        if scene_file:
            step3_cmd.extend(["--file", scene_file])
        run_step(3, total_steps, step3_cmd)

        run_step(
            4,
            total_steps,
            [
                args.python,
                str(SCRIPT_DIR / "sync_cep_rejection_lfl_assets.py"),
                *common_cfg_args,
                "--report-year",
                str(year),
                "--report-month",
                month,
            ],
        )

        _, step_goods_json = run_step(
            5,
            total_steps,
            [
                args.python,
                str(SCRIPT_DIR / "sync_compass_rejection_goods_download.py"),
                *common_cfg_args,
                "--session",
                args.session,
                "--report-year",
                str(year),
                "--report-month",
                month,
                "--download-dir",
                str(download_dir),
                "--max-retries",
                str(int(args.max_retries)),
            ],
        )
        goods_file = str(args.goods_file or ((step_goods_json or {}).get("savedAs") or ""))
        if not goods_file:
            raise RuntimeError("STEP_FAILED\nstep=6\ngoods download output missing savedAs path")

        run_step(
            6,
            total_steps,
            [
                args.python,
                str(SCRIPT_DIR / "load_compass_rejection_goods_cn_to_mysql.py"),
                *common_cfg_args,
                "--file",
                goods_file,
                "--report-year",
                str(year),
                "--report-month",
                month,
            ],
        )

        run_step(
            7,
            total_steps,
            [
                args.python,
                str(SCRIPT_DIR / "sync_cep_rejection_goods_top_assets.py"),
                *common_cfg_args,
                "--report-year",
                str(year),
                "--report-month",
                month,
            ],
        )

        if not args.skip_compose:
            run_step(
                8,
                total_steps,
                [
                    args.python,
                    str(SCRIPT_DIR / "compose_rejection_report.py"),
                    *common_cfg_args,
                ],
            )

        final_image = workdir / "assets" / "cep-rejection-analysis" / f"cep-rejection-combined-{year}{month}.png"
        print(f"FINAL_IMAGE={final_image}")
        print("FLOW18_PIPELINE_OK")
    finally:
        if tmp_config_path:
            try:
                tmp_config_path.unlink()
            except FileNotFoundError:
                pass


if __name__ == "__main__":
    main()

