from __future__ import annotations

from uuid import uuid4

from core.config import IngestApiConfig
from decode_content.ingest import KnowledgeIngestClient, ingest_payload_draft
from decode_content.models import IngestRecord, PayloadDraft


class FakeRepo:
    def __init__(self):
        self.marked = []
        self.records = []

    def mark_payload_draft_ingested(self, payload_draft_id):
        self.marked.append(payload_draft_id)
        return PayloadDraft(
            id=payload_draft_id,
            payload=_payload(),
            review_status="approved",
            ingest_ready=True,
            status="ingested",
        )

    def save_ingest_record(self, **kwargs):
        record = IngestRecord(id=uuid4(), **kwargs)
        self.records.append(record)
        return record


class FakeResponse:
    def __init__(self, status_code, payload):
        self.status_code = status_code
        self._payload = payload
        self.text = str(payload)

    def json(self):
        return self._payload


def _payload():
    return {
        "source": {"id": "xhs_1", "source_type": "post", "title": "帖子", "author": "作者"},
        "title": "拍照姿势",
        "content": "拍照时用手部动作制造自然感。",
        "dim_attributes": ["how"],
        "dim_creations": ["创作"],
        "scopes": [{"scope_type": "intent", "value": "自然感"}],
        "custom_ext": [{"key": "业务阶段", "type": "str", "value": "脚本"}],
    }


def test_dry_run_ingest_validates_and_does_not_call_http():
    repo = FakeRepo()
    draft_id = uuid4()
    draft = PayloadDraft(id=draft_id, payload=_payload(), review_status="pending", ingest_ready=False, status="draft")

    record = ingest_payload_draft(repo, draft, dry_run=True)

    assert repo.marked == [draft_id]
    assert record.target_system == "dry-run"
    assert record.status == "ingested"
    assert record.response_payload["dry_run"] is True


def test_real_ingest_posts_and_records_knowledge_id():
    calls = []

    def fake_post(url, **kwargs):
        calls.append((url, kwargs))
        return FakeResponse(201, {"knowledge_id": "k-1", "source_id": "xhs_1"})

    repo = FakeRepo()
    draft_id = uuid4()
    draft = PayloadDraft(id=draft_id, payload=_payload(), review_status="pending", ingest_ready=False, status="draft")
    client = KnowledgeIngestClient(
        IngestApiConfig(url="https://ingest.test/api/v1/knowledge/ingest", retry_delays_seconds=()),
        post_fn=fake_post,
        sleep_fn=lambda _delay: None,
    )

    record = ingest_payload_draft(repo, draft, dry_run=False, client=client)

    assert calls and calls[0][0] == "https://ingest.test/api/v1/knowledge/ingest"
    assert record.target_system == "knowledge-ingest-api"
    assert record.target_id == "k-1"
    assert record.response_payload["source_id"] == "xhs_1"
    assert repo.marked == [draft_id]


def test_real_ingest_failure_is_recorded_without_marking_draft():
    def fake_post(url, **kwargs):
        return FakeResponse(502, {"detail": "embedding down"})

    repo = FakeRepo()
    draft = PayloadDraft(id=uuid4(), payload=_payload(), review_status="pending", ingest_ready=False, status="draft")
    client = KnowledgeIngestClient(
        IngestApiConfig(url="https://ingest.test/api/v1/knowledge/ingest", retry_delays_seconds=()),
        post_fn=fake_post,
        sleep_fn=lambda _delay: None,
    )

    record = ingest_payload_draft(repo, draft, dry_run=False, client=client)

    assert record.status == "failed"
    assert record.target_system == "knowledge-ingest-api"
    assert record.response_payload["http_status"] == 502
    assert repo.marked == []


def test_real_ingest_retries_before_success():
    calls = []
    sleeps = []

    def fake_post(url, **kwargs):
        calls.append(url)
        if len(calls) == 1:
            return FakeResponse(502, {"detail": "embedding down"})
        return FakeResponse(201, {"knowledge_id": "k-2", "source_id": "xhs_1"})

    repo = FakeRepo()
    draft = PayloadDraft(id=uuid4(), payload=_payload(), review_status="pending", ingest_ready=False, status="draft")
    client = KnowledgeIngestClient(
        IngestApiConfig(url="https://ingest.test/api/v1/knowledge/ingest", retry_delays_seconds=(0.01,)),
        post_fn=fake_post,
        sleep_fn=lambda delay: sleeps.append(delay),
    )

    record = ingest_payload_draft(repo, draft, dry_run=False, client=client)

    assert len(calls) == 2
    assert sleeps == [0.01]
    assert record.status == "ingested"
    assert record.attempt_count == 2
    assert record.target_id == "k-2"
