from __future__ import annotations

from pathlib import Path

from rdflib import Graph, URIRef

from worai.errors import UsageError

from .models import UrlRecord

SCHEMA_URL = URIRef("http://schema.org/url")
SEOVOC_HTML = URIRef("https://w3id.org/seovoc/html")


def _iter_ttl_files(path: Path) -> list[Path]:
    if path.is_file():
        if path.suffix.lower() != ".ttl":
            raise UsageError(f"Debug-cloud source file must be .ttl: {path}")
        return [path]
    if not path.exists():
        raise UsageError(f"Debug-cloud source path does not exist: {path}")
    if not path.is_dir():
        raise UsageError(f"Debug-cloud source must be a .ttl file or a directory: {path}")
    return sorted(item for item in path.rglob("*.ttl") if item.is_file())


def _first_entity_record(ttl_path: Path) -> UrlRecord | None:
    graph = Graph()
    graph.parse(ttl_path, format="turtle")

    fallback: UrlRecord | None = None
    for subject in graph.subjects(unique=True):
        url_value = graph.value(subject=subject, predicate=SCHEMA_URL)
        html_value = graph.value(subject=subject, predicate=SEOVOC_HTML)
        if url_value is None:
            continue
        url_text = str(url_value).strip()
        html_text = str(html_value) if html_value is not None else None
        if not url_text:
            continue
        record = UrlRecord(
            url=url_text,
            html=html_text,
            source_type="debug-cloud",
            source_ref=str(ttl_path),
            metadata={"subject": str(subject)},
        )
        # Prefer entities that include cached HTML. Some debug-cloud files
        # contain duplicate schema:url subjects where only one has seovoc:html.
        if html_text:
            return record
        if fallback is None:
            fallback = record

    return fallback


def load_records_from_debug_cloud(source: str) -> list[UrlRecord]:
    records: list[UrlRecord] = []
    for ttl_file in _iter_ttl_files(Path(source).expanduser()):
        record = _first_entity_record(ttl_file)
        if record is not None:
            records.append(record)
    return records
