"""Normalize confirmed master taxonomy display names without changing structure.

Default mode is dry-run and rolls the transaction back.

Examples:
  python -m app.jobs.normalize_taxonomy_display_names
  python -m app.jobs.normalize_taxonomy_display_names --apply
"""

from __future__ import annotations

import argparse
import json
from typing import Any, Dict, Optional, Sequence

from sqlalchemy import select

from db.master_taxonomy_sync import upsert_taxonomy_node
from db.models import ChannelListingPath, MasterTaxonomyNode, ProductListingPathAssignment
from db.session import get_session


DEFAULT_NAME_NORMALIZATION_PLAN = [
    {
        "path_slug": "kitchen-cabinets/moldings",
        "new_name": "Kitchen Cabinets / Moldings",
        "reason": "Normalize top-level kitchen category display naming.",
    },
    {
        "path_slug": "kitchen-cabinets/moldings/quarter-round",
        "new_name": "Kitchen Cabinets / Moldings / Quarter Round",
        "reason": "Normalize child category display naming.",
    },
    {
        "path_slug": "kitchen-cabinets/accessories/valance-straight",
        "new_name": "Kitchen Cabinets / Accessories / Valance Straight",
        "reason": "Normalize child category display naming.",
    },
    {
        "path_slug": "kitchen-cabinets/wall-cabinets/diagonal-corner-glass",
        "new_name": "Kitchen Cabinets / Wall Cabinets / Diagonal Corner Glass",
        "reason": "Normalize child category display naming.",
    },
]


def run_normalize_taxonomy_display_names(*, apply: bool = False) -> Dict[str, Any]:
    summary: Dict[str, Any] = {
        "status": "ok",
        "applied": bool(apply),
        "updates": [],
    }

    with get_session() as session:
        for item in DEFAULT_NAME_NORMALIZATION_PLAN:
            summary["updates"].append(_execute_one(session, item, apply=apply))
        if apply:
            session.commit()
        else:
            session.rollback()
    return summary


def _execute_one(session, plan: Dict[str, str], *, apply: bool) -> Dict[str, Any]:
    node = session.scalar(
        select(MasterTaxonomyNode)
        .where(MasterTaxonomyNode.path_slug == plan["path_slug"])
        .where(MasterTaxonomyNode.is_active.is_(True))
        .limit(1)
    )
    if node is None:
        return {
            "status": "missing_node",
            "path_slug": plan["path_slug"],
            "new_name": plan["new_name"],
            "reason": plan["reason"],
        }

    listing_path = session.scalar(
        select(ChannelListingPath).where(ChannelListingPath.path_slug == node.path_slug).limit(1)
    )
    active_listing_assignments = list(
        session.scalars(
            select(ProductListingPathAssignment)
            .where(ProductListingPathAssignment.listing_path_id == (listing_path.id if listing_path else -1))
            .where(ProductListingPathAssignment.assignment_status == "active")
        )
    )

    before = {
        "node_id": int(node.id),
        "path_slug": node.path_slug,
        "old_name": node.name,
        "active_listing_assignment_count": len(active_listing_assignments),
        "active_listing_assignment_sample": [row.master_sku for row in active_listing_assignments[:10]],
    }
    if node.name == plan["new_name"]:
        return {
            "status": "already_normalized",
            "reason": plan["reason"],
            "before": before,
        }

    result = upsert_taxonomy_node(
        session,
        {
            "id": int(node.id),
            "name": plan["new_name"],
            "parent_id": node.parent_id,
            "node_kind": node.node_kind,
            "path_slug": node.path_slug,
            "collection_registry_id": node.collection_registry_id,
            "sort_order": node.sort_order,
            "is_active": node.is_active,
            "notes": node.notes,
        },
        sync_listing_path=True,
        allow_invent=True,
    )
    updated_node = result["node"]
    return {
        "status": "renamed" if apply else "would_rename",
        "reason": plan["reason"],
        "before": before,
        "after": {
            "node_id": updated_node["id"],
            "path_slug": updated_node["path_slug"],
            "new_name": updated_node["name"],
        },
        "changed_remote_fields": result.get("changed_remote_fields") or {},
    }


def main(argv: Optional[Sequence[str]] = None) -> int:
    parser = argparse.ArgumentParser(description="Normalize confirmed master taxonomy display names")
    parser.add_argument("--apply", action="store_true", help="Commit the display-name normalization changes")
    args = parser.parse_args(list(argv) if argv is not None else None)
    print(json.dumps(run_normalize_taxonomy_display_names(apply=args.apply), indent=2))
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
