from __future__ import annotations

from pathlib import Path
from typing import Any

from .constants import CHUNK_SIZES
from .metadata_builders import build_file_metadata
from .text_utils import compact_text, slugify


def chunk_text(text: str, chunk_size: int, overlap: int) -> list[str]:
    cleaned = compact_text(text)
    if not cleaned:
        return []
    chunks: list[str] = []
    start = 0
    while start < len(cleaned):
        end = min(len(cleaned), start + chunk_size)
        chunks.append(cleaned[start:end])
        if end >= len(cleaned):
            break
        start = max(0, end - overlap)
    return chunks


def load_text(path: Path) -> str:
    suffix = path.suffix.lower()
    if suffix == ".docx":
        import zipfile

        fragments: list[str] = []
        with zipfile.ZipFile(path) as archive:
            xml_bytes = archive.read("word/document.xml")
        xml_text = xml_bytes.decode("utf-8", errors="ignore")
        for raw in xml_text.replace("</w:p>", "\n").split("<"):
            if raw.startswith("w:t") and ">" in raw:
                fragments.append(raw.split(">", 1)[1])
        text = " ".join(fragment.strip() for fragment in fragments if fragment.strip())
        if text.strip():
            return text
    if suffix in {".pdf", ".doc", ".xls", ".xlsx", ".pages"}:
        try:
            from markitdown import MarkItDown

            result = MarkItDown().convert(str(path))
            text = getattr(result, "text_content", "") or ""
            if text.strip():
                return text
        except Exception:
            pass
    return path.read_text(encoding="utf-8", errors="ignore")


def build_chunk_payload(
    entry: dict[str, Any], schema: dict[str, Any], root_dir: Path
) -> tuple[list[dict[str, Any]], dict[str, Any]]:
    path = root_dir / str(entry["relative_path"])
    file_metadata = build_file_metadata(entry, schema)
    summary = {
        "file": str(path),
        "relative_path": str(entry["relative_path"]),
        "document_type": file_metadata["document_type"],
        "package_label": file_metadata["package_label"],
        "status": "skipped",
        "chunks": 0,
        "reason": "",
    }

    if not file_metadata["is_ingest_candidate"]:
        summary["reason"] = "manifest_marked_non_candidate"
        return [], summary
    if not path.exists():
        summary["status"] = "missing"
        summary["reason"] = "file_not_found"
        return [], summary

    text = load_text(path)
    if not compact_text(text):
        summary["status"] = "empty"
        summary["reason"] = "no_extractable_text"
        return [], summary

    chunk_config = CHUNK_SIZES.get(
        file_metadata["source_format"], {"chunk_size": 1400, "overlap": 180}
    )
    chunks = chunk_text(
        text, chunk_size=chunk_config["chunk_size"], overlap=chunk_config["overlap"]
    )
    file_slug = slugify(Path(file_metadata["source_filename"]).stem)
    payload = [
        {
            "text": chunk,
            "metadata": {
                **file_metadata,
                "chunk_index": index,
                "id": f"{file_metadata['project_code']}::{file_metadata['document_type']}::{file_slug}::chunk-{index}",
            },
        }
        for index, chunk in enumerate(chunks, start=1)
    ]
    summary["status"] = "ready"
    summary["chunks"] = len(payload)
    return payload, summary
