"""Extract useful collection metadata from In-Stock Kitchen Catalog 2026 spreads PDF."""
from __future__ import annotations

import json
import re
from pathlib import Path

from pypdf import PdfReader

PDF = Path(r"C:/Users/Mohsin.Abbas/Downloads/In-Stock-Kitchen-Catalog-2026-spreads.pdf")
TAX = Path(r"E:/2026/plytixmage_dbs_data/kitchen_cabinets_taxonomy.json")
BROCHURE = Path(r"E:/2026/plytixmage_dbs_data/Brochure_Data")
GENERAL_GAP = Path(r"E:/2026/plytixmage_dbs_data/audit_reports/general_catalog_collections_gap.json")
OUT_TXT = Path(r"E:/2026/plytixmage_dbs_data/audit_reports/_instock_kitchen_2026_full.txt")
OUT_JSON = Path(r"E:/2026/plytixmage_dbs_data/audit_reports/instock_kitchen_2026_extract.json")

# Known / suspected kitchen collection names (expanded)
KNOWN = [
    "Harriet Pearl White",
    "Anna Snow White",
    "Anna Stone Gray",
    "Anna Natural Rift White Oak",
    "Anna Caramel Harvest",
    "Eleanor Snow White",
    "Eleanor Ocean Blue",
    "Maya Snow White",
    "Maya Natural Rift White Oak",
    "Maya Black Rift White Oak",
    "Cooper Slate Gray",
    "Merrill Polar White",
    "Merrill Slate",
    "Hurston Midnight Espresso",
    "Johnson Sandstone",
    "Johnson White",
    "Belmont Drift White",
    "Belmont Toffee Pecan",
    "Chesapeake Golden Oak",
    "Metro Mist",
    "Metro Frost",
    "Galaxy Horizon",
    "Hallmark Frost",
    "Riley",
    "Sanibel",
    "Plymouth Espresso Maple",
    "Grace Snow White",
    "Coronet Honey",
    "Whitney",
    "Williamson",
    "Quest Metro Frost",
    "Fabuwood Metro Mist",
    "Fabuwood Galaxy Horizon",
    "Fabuwood Hallmark Frost",
]


def norm(s: str) -> str:
    s = re.sub(r"\s+", " ", str(s or "").strip().lower())
    s = s.replace("&", "and")
    return re.sub(r"[^a-z0-9 ]+", "", s)


def main() -> None:
    reader = PdfReader(str(PDF))
    parts = []
    for i, page in enumerate(reader.pages):
        parts.append(f"--- PAGE {i+1} ---\n{page.extract_text() or ''}")
    text = "\n".join(parts)
    OUT_TXT.write_text(text, encoding="utf-8")

    # Prefix codes like ACH-_, HPW-_, SRL_, LPE_
    prefixes = sorted(set(re.findall(r"\b([A-Z]{2,5})[_-]?\s*_?\b", text)))
    prefix_hits = sorted(set(re.findall(r"\b([A-Z]{2,5})-_\b", text)))
    prefix_hits2 = sorted(set(re.findall(r"\b([A-Z]{2,5})_\b", text)))

    # ALL CAPS multi-word headings
    caps = []
    for ln in text.splitlines():
        ln = ln.strip()
        if re.match(r"^[A-Z][A-Z0-9'&\- ]{5,80}$", ln) and len(ln.split()) >= 2:
            if ln.lower() not in {
                "other features",
                "base cabinets",
                "wall cabinets",
                "tall cabinets",
                "special bases",
                "special wall",
                "basic bases",
                "basic wall",
                "bridge wall",
                "corner wall",
                "corner bases",
                "drawer bases",
                "sink bases",
                "panels fillers",
                "panels & fillers",
                "moldings",
                "mouldings",
                "accessories",
                "miscellaneous",
                "specifications",
                "construction",
                "matching styles",
                "kitchen cabinets",
                "made in the usa",
                "limited warranty",
            }:
                caps.append(ln)

    # Find known collection mentions (case-insensitive)
    found = []
    for name in KNOWN:
        # allow flexible whitespace
        pat = re.compile(re.escape(name).replace(r"\ ", r"\s+"), re.I)
        ms = list(pat.finditer(text))
        if not ms:
            continue
        # nearby context snippets
        contexts = []
        for m in ms[:3]:
            start = max(0, m.start() - 80)
            end = min(len(text), m.end() + 120)
            contexts.append(re.sub(r"\s+", " ", text[start:end]).strip())
        found.append({"name": name, "mentions": len(ms), "contexts": contexts})

    # Matching Styles blocks
    matching_blocks = []
    lines = [ln.strip() for ln in text.splitlines()]
    for i, ln in enumerate(lines):
        if ln.lower() in {"matching styles", "matching style"}:
            block = []
            for nxt in lines[i + 1 : i + 15]:
                if not nxt:
                    continue
                low = nxt.lower()
                if low in {"style", "construction", "other features", "specifications", "cabinetry"}:
                    break
                if "additional items" in low:
                    break
                block.append(nxt)
            matching_blocks.append(block)

    # Stock / availability keywords
    stock_terms = {}
    for term in [
        "Grab & Go",
        "GRAB & GO",
        "Special Order",
        "AVAILABLE",
        "In-Stock",
        "In Stock",
        "Take Home",
        "Keyport",
        "North Bergen",
        "Bellmawr",
    ]:
        stock_terms[term] = len(re.findall(re.escape(term), text, flags=re.I))

    # SKU-like tokens
    sku_samples = sorted(set(re.findall(r"\b(?:[A-Z]{2,5}-)?[A-Z]{1,6}\d{2,4}[A-Z0-9-]*\b", text)))[:80]

    tax = json.loads(TAX.read_text(encoding="utf-8"))
    tax_names = {
        norm(v.get("display_name") or v.get("name") or k): {"code": k, "name": v.get("display_name") or v.get("name")}
        for k, v in (tax.get("collections") or {}).items()
    }
    brochure_files = [p.name for p in sorted(BROCHURE.glob("*.json"))]

    general = {}
    if GENERAL_GAP.exists():
        general = json.loads(GENERAL_GAP.read_text(encoding="utf-8"))
    general_missing_tax = [r["name"] for r in general.get("missing_in_taxonomy") or []]

    rows = []
    for item in found:
        key = norm(item["name"])
        # alias normalize
        aliases = {
            "quest metro frost": "metro frost",
            "fabuwood metro mist": "metro mist",
            "fabuwood galaxy horizon": "galaxy horizon",
            "fabuwood hallmark frost": "hallmark frost",
        }
        lookup_key = aliases.get(key, key)
        in_tax = lookup_key in tax_names or key in tax_names
        rows.append({**item, "in_taxonomy": in_tax, "taxonomy": tax_names.get(lookup_key) or tax_names.get(key)})

    new_vs_general = []
    for item in rows:
        if item["name"] not in [r.get("name") for r in (general.get("pdf_collections") or [])]:
            # also check norm
            gkeys = {norm(r["name"]) for r in (general.get("pdf_collections") or [])}
            if norm(item["name"]) not in gkeys and norm(item["name"]).replace("quest ", "").replace("fabuwood ", "") not in gkeys:
                new_vs_general.append(item)

    # Unique primary caps cleaned
    caps_clean = []
    seen = set()
    for c in caps:
        name = re.sub(r"\s+", " ", c).title() if c.isupper() else c
        name = name.replace("Whit E", "White").replace("W Ood", "Wood")
        key = norm(name)
        if key in seen:
            continue
        if any(x in key for x in ("warranty", "limited", "grab", "available", "special order")):
            continue
        seen.add(key)
        caps_clean.append({"raw": c, "name": name})

    report = {
        "pdf": str(PDF),
        "pages": len(reader.pages),
        "collection_mentions": rows,
        "collections_not_in_general_catalog_parse": new_vs_general,
        "still_missing_taxonomy_from_either_catalog": sorted(
            set(general_missing_tax)
            | {
                r["name"]
                for r in rows
                if not r["in_taxonomy"]
                and norm(r["name"])
                not in {
                    "quest metro frost",
                    "fabuwood metro mist",
                    "fabuwood galaxy horizon",
                    "fabuwood hallmark frost",
                    "johnson white",
                    "merrill slate",
                    "coronet honey",
                    "whitney",
                    "williamson",
                    "grace snow white",
                }
                or (
                    not r["in_taxonomy"]
                    and r["name"]
                    in {
                        "Metro Mist",
                        "Metro Frost",
                        "Riley",
                        "Sanibel",
                        "Quest Metro Frost",
                        "Fabuwood Metro Mist",
                    }
                )
            }
        ),
        "prefix_codes_underscore": prefix_hits2,
        "prefix_codes_dash_underscore": prefix_hits,
        "matching_styles_blocks": matching_blocks,
        "stock_term_counts": stock_terms,
        "caps_headings": caps_clean,
        "sku_samples": sku_samples,
        "brochure_files": brochure_files,
        "full_text_path": str(OUT_TXT),
    }

    # Cleaner missing list
    missing = []
    for name in [
        "Metro Mist",
        "Metro Frost",
        "Riley",
        "Sanibel",
        "Plymouth Espresso Maple",
        "Grace Snow White",
        "Johnson White",
        "Merrill Slate",
        "Coronet Honey",
        "Whitney",
        "Williamson",
    ]:
        hit = next((r for r in rows if norm(r["name"]) == norm(name)), None)
        in_tax = norm(name) in tax_names or any(norm(name) in k or k in norm(name) for k in tax_names)
        # brochure fuzzy
        bro_hit = any(norm(name).replace(" ", "") in norm(f).replace(" ", "") for f in brochure_files)
        missing.append(
            {
                "name": name,
                "mentioned_in_instock_pdf": bool(hit),
                "mentions": hit["mentions"] if hit else 0,
                "in_taxonomy": bool(in_tax),
                "in_brochure_files": bro_hit,
            }
        )
    report["gap_checklist"] = missing

    OUT_JSON.write_text(json.dumps(report, indent=2), encoding="utf-8")

    print(f"pages={len(reader.pages)} wrote {OUT_TXT}")
    print("\nCollections mentioned:")
    for r in rows:
        print(f"  {r['name']:35} mentions={r['mentions']:<3} tax={'Y' if r['in_taxonomy'] else 'N'}")
    print("\nPrefix codes (*-_ / *_):", prefix_hits, prefix_hits2)
    print("\nMatching Styles blocks:")
    for i, b in enumerate(matching_blocks, 1):
        print(f"  #{i}: {b}")
    print("\nGap checklist:")
    for g in missing:
        print(
            f"  {g['name']:30} instock={g['mentioned_in_instock_pdf']} tax={g['in_taxonomy']} brochure={g['in_brochure_files']}"
        )
    print("\nStock terms:", stock_terms)
    print("wrote", OUT_JSON)


if __name__ == "__main__":
    main()
