"""Manifest I/O for reference discovery and crawl results."""

from __future__ import annotations

import json
from datetime import datetime
from pathlib import Path

from refcurator.models import CrawlResult, CrawlResultEntry, Manifest, ManifestURL
from refcurator.utils import normalize_url


def read_manifest(path: Path) -> Manifest:
    """Read a manifest JSON file."""
    data = json.loads(path.read_text())
    return Manifest(**data)


def write_manifest(manifest: Manifest, path: Path) -> None:
    """Write a manifest to a JSON file."""
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text(manifest.model_dump_json(indent=2))


def merge_manifests(manifests: list[Manifest]) -> Manifest:
    """Merge multiple manifests, deduplicating URLs."""
    seen: dict[str, ManifestURL] = {}
    topic_parts = []

    for m in manifests:
        if m.topic:
            topic_parts.append(m.topic)
        for url_entry in m.urls:
            normalized = normalize_url(url_entry.url)
            existing = seen.get(normalized)
            if existing is None or (
                url_entry.credibility_score
                and (existing.credibility_score or 0) < url_entry.credibility_score
            ):
                seen[normalized] = url_entry

    urls = list(seen.values())
    return Manifest(
        discovery_date=datetime.now().isoformat(),
        topic=" + ".join(topic_parts) if topic_parts else None,
        total_urls=len(urls),
        urls=urls,
    )


def dedup_manifest_urls(manifest: Manifest, existing_urls: set[str]) -> Manifest:
    """Remove URLs already in the existing set (normalized comparison)."""
    existing_normalized = {normalize_url(u) for u in existing_urls}
    filtered = [u for u in manifest.urls if normalize_url(u.url) not in existing_normalized]
    return Manifest(
        discovery_date=manifest.discovery_date,
        topic=manifest.topic,
        total_urls=len(filtered),
        urls=filtered,
    )


def read_crawl_result(path: Path) -> CrawlResult:
    """Read a crawl result JSON file."""
    data = json.loads(path.read_text())
    return CrawlResult(**data)


def write_crawl_result(result: CrawlResult, path: Path) -> None:
    """Write a crawl result to a JSON file."""
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text(result.model_dump_json(indent=2))


def create_crawl_result(
    entries: list[dict],
    crawler: str = "firecrawl",
) -> CrawlResult:
    """Create a CrawlResult from a list of crawl entry dicts."""
    docs = [CrawlResultEntry(**e) for e in entries]
    completed = [d for d in docs if d.status == "completed"]
    failed = [d for d in docs if d.status != "completed"]

    return CrawlResult(
        crawl_date=datetime.now().isoformat(),
        crawler_used=crawler,
        total_crawled=len(completed),
        total_failed=len(failed),
        documents=docs,
    )
