"""Reparent known polluted active taxonomy nodes before v2 backfill/import.

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

This file intentionally starts with an empty plan until a node is explicitly
confirmed as structurally wrong. Naming-only cleanup belongs in the dedicated
display-name normalization job.

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

from __future__ import annotations

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

from sqlalchemy import select

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


DEFAULT_REPARENT_PLAN: list[dict[str, str]] = []


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

    with get_session() as session:
        for item in DEFAULT_REPARENT_PLAN:
            summary["moves"].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["node_path_slug"])
        .where(MasterTaxonomyNode.is_active.is_(True))
        .limit(1)
    )
    parent = session.scalar(
        select(MasterTaxonomyNode)
        .where(MasterTaxonomyNode.path_slug == plan["target_parent_path_slug"])
        .where(MasterTaxonomyNode.is_active.is_(True))
        .limit(1)
    )
    if node is None:
        return {
            "status": "missing_source",
            "node_path_slug": plan["node_path_slug"],
            "target_parent_path_slug": plan["target_parent_path_slug"],
            "reason": plan["reason"],
        }
    if parent is None:
        return {
            "status": "missing_target_parent",
            "node_path_slug": plan["node_path_slug"],
            "target_parent_path_slug": plan["target_parent_path_slug"],
            "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),
        "name": node.name,
        "old_parent_id": int(node.parent_id) if node.parent_id is not None else None,
        "old_parent_path_slug": _path_slug_for_id(session, node.parent_id),
        "old_path_slug": node.path_slug,
        "active_listing_assignment_count": len(active_listing_assignments),
        "active_listing_assignment_sample": [row.master_sku for row in active_listing_assignments[:10]],
    }

    result = reparent_taxonomy_node(session, int(node.id), parent_id=int(parent.id))
    updated_node = result["node"]
    return {
        "status": "reparented" if apply else "would_reparent",
        "reason": plan["reason"],
        "before": before,
        "after": {
            "node_id": updated_node["id"],
            "new_parent_id": updated_node["parent_id"],
            "new_parent_path_slug": _path_slug_for_id(session, updated_node["parent_id"]),
            "new_path_slug": updated_node["path_slug"],
        },
        "path_cascade": result.get("path_cascade") or {},
    }


def _path_slug_for_id(session, node_id: Optional[int]) -> Optional[str]:
    if not node_id:
        return None
    row = session.get(MasterTaxonomyNode, int(node_id))
    return row.path_slug if row is not None else None


def main(argv: Optional[Sequence[str]] = None) -> int:
    parser = argparse.ArgumentParser(description="Reparent obvious polluted active taxonomy nodes")
    parser.add_argument("--apply", action="store_true", help="Commit the reparenting changes")
    args = parser.parse_args(list(argv) if argv is not None else None)
    result = run_fix_taxonomy_pollution_candidates(apply=args.apply)
    if not DEFAULT_REPARENT_PLAN:
        result["note"] = "No candidate moves are configured yet. Add only user-confirmed pollution cases."
    print(json.dumps(result, indent=2))
    return 0


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