# -*- coding: utf-8 -*-
"""end-to-end 推論（利用システム）。

入力: 動画ファイル ＋ 濃度(任意) ＋ 時間帯
フロー（開発環境＝学習時と同一の上流を再利用）:
    動画
     └ 上流 DensityResolver（local_batch_api/density_resolver.py）
          多フレーム抽出 → 湯気除外 → RF-DETRスープ抽出（可読性判定）
          → 最良フレーム選択 → 濃度確定（実測優先 / 無ければ濃度推定AI）
     └ 採点ゲート①: readable=False → 要確認（LLMに送らない）
     └ LLM画像評価（local_batch_api/batch_process.py / 学習時と同じプロンプト・同じAPI）
          最良フレーム + 濃度ノート → 固定JSON（visual/water/oil/boiling/photo/image_score）
     └ 採点ゲート②: assessable=0（4軸が判定不可）→ 要確認
     └ 後段スコアリング（scoring_engine：線形回帰 visual_plus_brix_slot）
出力: status / total・soup スコア・グレード ＋ 上流・LLM中間結果

※ GPU・ffmpeg・BytePlus APIキー（secrets/byteplus.key か 環境変数 ARK_API_KEY）が必要。
"""
from __future__ import annotations

import sys
from pathlib import Path

import scoring_engine as E

HERE = Path(__file__).resolve().parent
ROOT = HERE.parent
LBA = ROOT / "local_batch_api"
sys.path.insert(0, str(LBA))

import batch_process as B            # noqa: E402  上流のLLM呼び出し・パース等を再利用
from density_resolver import DensityResolver  # noqa: E402

CONFIG_PATH = LBA / "config.test10.yaml"


class FullPipeline:
    """動画1本を end-to-end で推論する。モデルは初期化時に一度だけ読み込む。"""

    def __init__(self, model_dir: str | Path | None = None) -> None:
        self.config = B.load_config(CONFIG_PATH)
        d = self.config.get("density", {}) or {}
        self.resolver = DensityResolver(
            conf_keep=float(d.get("conf_keep", 0.50)),
            crop_threshold=float(d.get("crop_threshold", 0.10)),
            frames=int(d.get("frames", 16)),
            multi_min=int(d.get("multi_min", 4)),
            vote_min=float(d.get("vote_min", 0.70)),
            high_mean_conf=float(d.get("high_mean_conf", 0.72)),
            device_name=str(d.get("device", "auto")),
        )
        self.prompt = B.build_prompt(B.POLICY_PATH)
        self.models = E.load_models(model_dir or (HERE / "models"))

    def run(self, video_path: str | Path, brix=None, slot=None, store=None) -> dict:
        video_path = Path(video_path)
        meta: dict = {}
        if brix not in (None, ""):
            meta["スープ濃度"] = brix

        # --- 上流: 可読性・最良フレーム・濃度 ---
        res = self.resolver.resolve(video_path, meta)
        readable = bool(res.get("readable"))
        best_frame = res.get("best_frame_path") or ""
        density_value = res.get("value")

        # --- LLM送信可否（不可読かつ湯気多はスキップ）---
        skip, reason = B.decide_skip_llm(res, self.config)
        if skip or not best_frame:
            assessment = B.synthetic_unassessable(res, reason or "最良フレームが得られない")
            llm_used = False
        else:
            note = B.density_input_note(res)
            payload = B.build_request_payload(self.config, self.prompt, Path(best_frame), note)
            api_response = B.call_byteplus(self.config, payload)
            assessment = B.parse_assessment(api_response)
            llm_used = True
            if not isinstance(assessment, dict):
                assessment = B.synthetic_unassessable(res, "LLM応答のパースに失敗")
                llm_used = False

        # --- 後段スコアリング用レコード（学習時の flatten と同一マッピング）---
        record = {
            "video_path": str(video_path),
            "frame_path": best_frame,
            "store": store,
            "slot": slot,
            "brix_raw": density_value if density_value is not None else (brix or None),
            "visual_density": (assessment.get("visual_density") or {}).get("value"),
            "water_level": (assessment.get("water_level") or {}).get("state"),
            "oil_emulsification": (assessment.get("oil_emulsification") or {}).get("state"),
            "boiling_heat_state": assessment.get("boiling_heat_state"),
            "photo_quality": assessment.get("photo_quality"),
            "image_condition_score": assessment.get("image_condition_score"),
            "readable": readable,
        }
        result = E.score_record(record, self.models)

        # 中間結果を添付（画面表示・監査用）
        result["_upstream"] = {
            "readable": readable,
            "assessable_upstream": res.get("assessable"),
            "density_value": density_value,
            "density_source": res.get("source"),
            "density_confidence": res.get("confidence"),
            "best_frame_path": best_frame,
            "steam_mean": res.get("steam_mean"),
            "frames_used": res.get("frames_used"),
            "llm_used": llm_used,
            "llm_skip_reason": reason if skip else "",
            "note": res.get("note"),
        }
        result["_llm_eval"] = {
            "visual_density": record["visual_density"],
            "water_level": record["water_level"],
            "oil_emulsification": record["oil_emulsification"],
            "boiling_heat_state": record["boiling_heat_state"],
            "photo_quality": record["photo_quality"],
            "image_condition_score": record["image_condition_score"],
        }
        return result


def main() -> None:
    import argparse
    import json
    ap = argparse.ArgumentParser()
    ap.add_argument("--video", required=True)
    ap.add_argument("--brix", default=None)
    ap.add_argument("--slot", default=None)
    ap.add_argument("--store", default=None)
    args = ap.parse_args()
    pipe = FullPipeline()
    print(json.dumps(pipe.run(args.video, brix=args.brix, slot=args.slot, store=args.store),
                     ensure_ascii=False, indent=2))


if __name__ == "__main__":
    main()
