from __future__ import annotations

import contextlib
import io
import json
import os
import tempfile
import unittest
from pathlib import Path
from unittest.mock import patch

from src.cli import main


DEAL_ID = 123
DEAL_TITLE = "Event X"
VENUE_NAME = "Venue Y"
PLACE = "Amsterdam"
REGION = "Noord-Holland"


def _write_audit_jsonl(path: Path, records: list[dict[str, object]]) -> None:
    text = "".join([json.dumps(r, sort_keys=True, ensure_ascii=True) + "\n" for r in records])
    path.write_text(text, encoding="utf-8", newline="\n")

def _make_audit_record(*, tmp: str, out: Path, name: str, confidence: float, sha: str) -> dict[str, object]:
    return {
        "photo_sha256": sha,
        "source_path": str(Path(tmp) / "inbox" / name),
        "source_relpath": name,
        "deal_id": DEAL_ID,
        "deal_title": DEAL_TITLE,
        "venue_name": VENUE_NAME,
        "place": PLACE,
        "region": REGION,
        "confidence": confidence,
        "match_reason": "matched",
        "website_webp_path": str(out / "website" / Path(name).with_suffix(".webp")),
        "website_webp_exists": False,
        "website_webp_bytes": None,
        "gbp_jpg_path": str(out / "gbp" / name),
        "gbp_jpg_exists": True,
        "gbp_jpg_bytes": 1,
        "gbp_png_path": str(out / "gbp" / Path(name).with_suffix(".png")),
        "gbp_png_exists": False,
        "gbp_png_bytes": None,
    }


def _write_gbp_jpgs(out: Path, names: list[str]) -> None:
    for name in names:
        p = out / "gbp" / name
        p.parent.mkdir(parents=True, exist_ok=True)
        p.write_bytes(b"x")


class TestGbpGenerate(unittest.TestCase):
    def test_dry_run_prints_payload_and_selects_top_photos_without_writing(self) -> None:
        with tempfile.TemporaryDirectory() as tmp:
            out = Path(tmp) / "out"
            run_dir = out / "audit" / "RUN1"
            run_dir.mkdir(parents=True, exist_ok=True)

            photos = [("a.jpg", 0.90, "a" * 64), ("b.jpg", 0.80, "b" * 64), ("c.jpg", 0.70, "c" * 64), ("d.jpg", 0.60, "d" * 64)]
            _write_gbp_jpgs(out, [n for n, _c, _s in photos])
            records = [_make_audit_record(tmp=tmp, out=out, name=n, confidence=c, sha=s) for n, c, s in photos]
            records.append({"deal_id": 999, "gbp_jpg_exists": True, "gbp_jpg_path": str(out / "gbp" / "z.jpg")})
            _write_audit_jsonl(run_dir / "audit.jsonl", records)

            stdout = io.StringIO()
            with (
                patch.dict(os.environ, {"OUTPUT_ROOT": str(out)}, clear=True),
                contextlib.redirect_stdout(stdout),
            ):
                code = main(["gbp", "generate", "--deal-id", str(DEAL_ID), "--run-id", "RUN1", "--dry-run"])

            self.assertEqual(code, 0)
            payload = json.loads(stdout.getvalue())
            self.assertEqual(payload["deal_id"], DEAL_ID)
            self.assertEqual(payload["deal_title"], DEAL_TITLE)
            self.assertEqual(payload["venue_name"], VENUE_NAME)
            self.assertEqual(payload["place"], PLACE)
            self.assertIn("text", payload)
            self.assertEqual(payload["text"].count(VENUE_NAME), 1)
            self.assertEqual(payload["text"].count(PLACE), 1)
            self.assertEqual(len(payload["photos"]), 3)
            self.assertEqual([p["photo_sha256"] for p in payload["photos"]], ["a" * 64, "b" * 64, "c" * 64])
            self.assertFalse((out / "gbp" / "posts").exists())

    def test_run_mode_writes_payload_file(self) -> None:
        with tempfile.TemporaryDirectory() as tmp:
            out = Path(tmp) / "out"
            run_dir = out / "audit" / "RUN1"
            run_dir.mkdir(parents=True, exist_ok=True)
            _write_gbp_jpgs(out, ["a.jpg"])

            _write_audit_jsonl(
                run_dir / "audit.jsonl",
                [
                    _make_audit_record(tmp=tmp, out=out, name="a.jpg", confidence=0.9, sha="a" * 64)
                ],
            )

            stdout = io.StringIO()
            with (
                patch.dict(os.environ, {"OUTPUT_ROOT": str(out)}, clear=True),
                contextlib.redirect_stdout(stdout),
            ):
                code = main(["gbp", "generate", "--deal-id", str(DEAL_ID), "--run-id", "RUN1"])

            self.assertEqual(code, 0)
            self.assertTrue((out / "gbp" / "posts" / f"deal_{DEAL_ID}.json").exists())
