"""Seed canonical collection filter profiles from brochure JSON payloads."""

from __future__ import annotations

import json
from pathlib import Path
from typing import Any, Dict, Iterable, List, Optional, Sequence

from sqlalchemy import select
from sqlalchemy.orm import Session

from db.canonical_attributes import canonicalize_attribute_fields
from db.collection_filter_backfill import derive_filter_color_from_collection
from db.collection_landing_pages import canonical_collection
from db.models import MasterCollectionRegistry


DEFAULT_FILTER_CODES: Sequence[str] = (
    "door_style",
    "color",
    "finish",
    "cabinet_construction",
    "cabinet_door_overlay",
    "wood_species",
    "drawer_front_style",
    "soft_close",
    "cabinet_box_finish",
    "carcass_material",
)


def load_brochure_payload(path: str | Path) -> Dict[str, Any]:
    return json.loads(Path(path).read_text(encoding="utf-8"))


def seed_collection_filter_profiles(
    session: Session,
    payloads: Iterable[Dict[str, Any]],
    *,
    overwrite: bool = True,
    create_missing_registry: bool = False,
    dry_run: bool = True,
) -> Dict[str, Any]:
    results: List[Dict[str, Any]] = []
    updated = 0
    skipped = 0

    for payload in payloads:
        extracted = extract_brochure_filter_profile(payload)
        collection_name = extracted["collection_name"]
        collection_code = extracted.get("collection_code")
        if not collection_name:
            skipped += 1
            results.append({"status": "skipped", "reason": "missing_collection_name"})
            continue

        registry = _find_registry(session, collection_code=collection_code, collection_name=collection_name)
        if registry is None and create_missing_registry and collection_code:
            registry = MasterCollectionRegistry(
                code=collection_code,
                name=collection_name,
                path_slug=extracted.get("path_slug"),
                aliases={},
                is_active=True,
            )
            if not dry_run:
                session.add(registry)
                session.flush()

        if registry is None:
            skipped += 1
            results.append(
                {
                    "status": "skipped",
                    "reason": "registry_not_found",
                    "collection_name": collection_name,
                    "collection_code": collection_code,
                }
            )
            continue

        merged = _merged_aliases(registry.aliases, extracted, overwrite=overwrite)
        results.append(
            {
                "status": "updated",
                "registry_id": registry.id,
                "collection_name": collection_name,
                "collection_code": collection_code,
                "filter_attributes": merged.get("filter_attributes") or {},
                "filter_attribute_sources": merged.get("filter_attribute_sources") or {},
            }
        )
        if not dry_run:
            registry.aliases = merged
        updated += 1

    return {
        "status": "ok",
        "dry_run": dry_run,
        "updated": 0 if dry_run else updated,
        "would_update": updated if dry_run else 0,
        "skipped": skipped,
        "results": results,
    }


def extract_brochure_filter_profile(payload: Dict[str, Any]) -> Dict[str, Any]:
    collection = payload.get("collection") if isinstance(payload.get("collection"), dict) else {}
    source_document = payload.get("source_document") if isinstance(payload.get("source_document"), dict) else {}
    specs = payload.get("specifications") if isinstance(payload.get("specifications"), dict) else {}
    style = specs.get("style") if isinstance(specs.get("style"), dict) else {}
    construction = specs.get("construction") if isinstance(specs.get("construction"), dict) else {}
    hardware = specs.get("hardware_features") if isinstance(specs.get("hardware_features"), dict) else {}

    collection_name = canonical_collection(collection.get("display_name") or collection.get("name"))
    fields: Dict[str, Any] = {
        "collection": collection_name,
        "door_style": style.get("door_style"),
        "cabinet_door_style": style.get("door_style"),
        "color": collection.get("color_label"),
        "finish": style.get("finish_type"),
        "cabinet_door_overlay": style.get("overlay"),
        "cabinet_construction_type": style.get("cabinet_frame_style"),
        "cabinet_box_finish": specs.get("cabinet_box_finish"),
    }

    wood_species = style.get("wood_species")
    if wood_species:
        fields["wood_species"] = wood_species

    drawer_front_style = style.get("drawer_front_style")
    if drawer_front_style:
        fields["drawer_front_style"] = drawer_front_style

    cabinet_box = construction.get("cabinet_box") if isinstance(construction.get("cabinet_box"), dict) else {}
    carcass_material = cabinet_box.get("side_panel_material") or cabinet_box.get("back_panel_material")
    if carcass_material:
        fields["carcass_material"] = carcass_material

    drawer_slides = hardware.get("drawer_slides") if isinstance(hardware.get("drawer_slides"), dict) else {}
    door_hinges = hardware.get("door_hinges") if isinstance(hardware.get("door_hinges"), dict) else {}
    if bool(drawer_slides.get("soft_close")) or bool(door_hinges.get("soft_close")):
        fields["soft_close"] = "Yes"

    canonical = canonicalize_attribute_fields(fields)
    color_value = derive_filter_color_from_collection(collection_name or "") or str(canonical.get("color") or "").strip()
    out_fields: Dict[str, Any] = {}
    sources: Dict[str, str] = {}

    _take(out_fields, sources, "door_style", canonical.get("door_style"), "specifications.style.door_style")
    _take(out_fields, sources, "color", color_value, "collection.color_label")
    _take(out_fields, sources, "finish", _broad_finish_label(fields.get("finish")), "specifications.style.finish_type")
    _take(
        out_fields,
        sources,
        "cabinet_construction",
        canonical.get("cabinet_construction"),
        "specifications.style.cabinet_frame_style",
    )
    _take(
        out_fields,
        sources,
        "cabinet_door_overlay",
        canonical.get("cabinet_door_overlay"),
        "specifications.style.overlay",
    )
    _take(out_fields, sources, "wood_species", fields.get("wood_species"), "specifications.style.wood_species")
    _take(
        out_fields,
        sources,
        "drawer_front_style",
        fields.get("drawer_front_style"),
        "specifications.style.drawer_front_style",
    )
    _take(out_fields, sources, "soft_close", fields.get("soft_close"), "specifications.hardware_features")
    _take(
        out_fields,
        sources,
        "cabinet_box_finish",
        fields.get("cabinet_box_finish"),
        "specifications.cabinet_box_finish",
    )
    _take(
        out_fields,
        sources,
        "carcass_material",
        fields.get("carcass_material"),
        "specifications.construction.cabinet_box.side_panel_material",
    )

    return {
        "collection_name": collection_name,
        "collection_code": _clean(collection.get("collection_code") or source_document.get("collection_code")),
        "path_slug": _clean(collection.get("path_slug")),
        "brochure_file_name": _clean(source_document.get("file_name")),
        "brochure_source_url": _clean(source_document.get("source_url")),
        "filter_attributes": out_fields,
        "filter_attribute_sources": sources,
    }


def _find_registry(
    session: Session,
    *,
    collection_code: Optional[str],
    collection_name: Optional[str],
) -> Optional[MasterCollectionRegistry]:
    if collection_code:
        row = session.scalar(select(MasterCollectionRegistry).where(MasterCollectionRegistry.code == collection_code))
        if row is not None:
            return row
    if collection_name:
        return session.scalar(
            select(MasterCollectionRegistry).where(MasterCollectionRegistry.name.ilike(collection_name)).limit(1)
        )
    return None


def _merged_aliases(existing: Any, extracted: Dict[str, Any], *, overwrite: bool) -> Dict[str, Any]:
    aliases = dict(existing or {})
    filter_attributes = dict(aliases.get("filter_attributes") or {})
    filter_sources = dict(aliases.get("filter_attribute_sources") or {})
    brochure_profile = dict(aliases.get("brochure_filter_attributes") or {})
    brochure_sources = dict(aliases.get("brochure_filter_attribute_sources") or {})

    for code, value in (extracted.get("filter_attributes") or {}).items():
        if overwrite or not str(filter_attributes.get(code) or "").strip():
            filter_attributes[code] = value
        brochure_profile[code] = value

    for code, source in (extracted.get("filter_attribute_sources") or {}).items():
        if overwrite or not str(filter_sources.get(code) or "").strip():
            filter_sources[code] = source
        brochure_sources[code] = source

    aliases["filter_attributes"] = filter_attributes
    aliases["filter_attribute_sources"] = filter_sources
    aliases["brochure_filter_attributes"] = brochure_profile
    aliases["brochure_filter_attribute_sources"] = brochure_sources
    if extracted.get("brochure_file_name"):
        aliases["brochure_file_name"] = extracted["brochure_file_name"]
    if extracted.get("brochure_source_url"):
        aliases["brochure_source_url"] = extracted["brochure_source_url"]
    return aliases


def _take(target: Dict[str, Any], sources: Dict[str, str], code: str, value: Any, source: str) -> None:
    text = _clean(value)
    if not text:
        return
    target[code] = text
    sources[code] = source


def _broad_finish_label(value: Any) -> Optional[str]:
    text = _clean(value)
    if not text:
        return None
    norm = text.lower()
    if "paint" in norm:
        return "Painted"
    if "stain" in norm:
        return "Stained"
    if "wire-brushed" in norm or "wire brushed" in norm:
        return "Wire-Brushed"
    return text


def _clean(value: Any) -> Optional[str]:
    if value is None:
        return None
    text = str(value).strip()
    return text or None
