from __future__ import annotations

from uuid import UUID, uuid4

from acquisition.domain import CandidateItem, MediaAsset
from decode_content import gates
from decode_content.contracts import load_decode_contracts
from decode_content.models import (
    ContractSnapshot,
    DecodeJob,
    DecodeResult,
    KnowledgeParticle,
    PayloadDraft,
    ReadResult,
    ScopeResult,
)
from decode_content.scoping import NORMALIZE
from decode_content.service import DecodeService
from pipeline.decode_runner import run_decode_stage


class CandidateRepo:
    def __init__(self, item_id: UUID):
        self.item = CandidateItem(
            id=item_id,
            platform="xiaohongshu",
            platform_item_id="xhs-1",
            canonical_url="https://xhs.test/1",
            content_type="图文",
            title="脚本开头教程",
            author_name="作者",
            raw_summary="先定受众，再写开头钩子",
            source_payload={"topic_list": ["脚本"]},
        )
        self.media = [
            MediaAsset(
                id=uuid4(),
                item_id=item_id,
                media_type="image",
                source_url="https://origin.test/1.jpg",
                oss_url="https://oss.test/1.jpg",
                cdn_url="https://cdn.test/1.jpg",
                position=1,
                status="done",
            )
        ]

    def list_creation_candidate_items(self, *, run_id=None, limit=100):
        return [self.item]

    def list_media_assets_for_item(self, item_id):
        assert item_id == self.item.id
        return self.media


class DecodeRepo:
    def __init__(self):
        self.jobs: list[DecodeJob] = []
        self.results: list[DecodeResult] = []
        self.particles: list[KnowledgeParticle] = []
        self.scopes: list[ScopeResult] = []
        self.payloads: list[PayloadDraft] = []
        self.snapshots: list[ContractSnapshot] = []

    def create_decode_job(self, *, item_id: UUID, status: str = "pending", metadata=None):
        job = DecodeJob(id=uuid4(), item_id=item_id, status=status, metadata=metadata or {})
        self.jobs.append(job)
        return job

    def save_decode_result(self, **kwargs):
        result = DecodeResult(id=uuid4(), **kwargs)
        self.results.append(result)
        return result

    def save_knowledge_particle(self, **kwargs):
        particle = KnowledgeParticle(id=uuid4(), **kwargs)
        self.particles.append(particle)
        return particle

    def save_scope_result(self, **kwargs):
        scope = ScopeResult(id=uuid4(), **kwargs)
        self.scopes.append(scope)
        return scope

    def save_payload_draft(self, **kwargs):
        payload = PayloadDraft(id=uuid4(), **kwargs)
        self.payloads.append(payload)
        return payload

    def save_contract_snapshot(self, **kwargs):
        snapshot = ContractSnapshot(id=uuid4(), **kwargs)
        self.snapshots.append(snapshot)
        return snapshot


def _fake_chat(contract):
    def chat(system, user, timeout=None):
        if system == gates.GATE_ADMIT:
            return {"in_scope": True}
        if system == gates.GATE_REFUTE:
            return {"out_of_scope": False}
        if system == gates.GATE_HOW_ADMIT:
            return {"is_real_how": True}
        if system == gates.GATE_HOW_REFUTE:
            return {"is_fake": False}
        if system == gates.GATE_WHY_REFUTE:
            return {"not_why": False}
        if system == NORMALIZE:
            return {"映射": {}}
        if system == contract.phase1:
            return {
                "knowledges": [
                    {
                        "id": "k1",
                        "type": "how",
                        "role": "主",
                        "title": "脚本开头的受众钩子",
                        "purpose": "提升开头吸引力",
                        "业务阶段": ["脚本"],
                        "steps": [
                            {
                                "id": "s1",
                                "input": "目标受众",
                                "directive": "先说出痛点",
                                "output": "开头钩子",
                                "创作阶段": "开头",
                            }
                        ],
                    }
                ]
            }
        if system == contract.phase2:
            return {
                "scopes": [
                    {
                        "knowledge_id": "k1",
                        "step_id": "s1",
                        "items": [{"scope_type": "intent", "value": "吸引注意"}],
                    }
                ]
            }
        raise AssertionError(system[:80])

    return chat


def test_decode_stage_connects_candidate_media_to_payload_drafts():
    item_id = uuid4()
    candidate_repo = CandidateRepo(item_id)
    decode_repo = DecodeRepo()
    contract = load_decode_contracts()
    seen_posts = []

    def reader(post):
        seen_posts.append(post)
        return ReadResult(text="这条帖子讲脚本开头创作方法")

    service = DecodeService(
        repository=decode_repo,
        contract=contract,
        chat_json_fn=_fake_chat(contract),
        reader=reader,
    )

    batch = run_decode_stage(candidate_repo=candidate_repo, decode_service=service)

    assert batch.total == 1
    assert batch.decoded == 1
    assert seen_posts[0].image_urls == ["https://cdn.test/1.jpg"]
    assert decode_repo.results[0].status == "decoded"
    assert decode_repo.particles[0].title == "脚本开头的受众钩子"
    assert decode_repo.scopes[0].scope_value == "吸引注意"
    assert decode_repo.payloads[0].payload["title"] == "脚本开头的受众钩子"
