"""Deactivate master taxonomy nodes and their local publishing links."""

from __future__ import annotations

from datetime import datetime, timezone
from typing import Any, Dict, List, Optional

from sqlalchemy import select
from sqlalchemy.orm import Session

from channel.url_canonical import normalize_plp_path
from db.models import (
    ChannelListingPath,
    ChannelListingPathTarget,
    CollectionLandingPage,
    ListingIntersectionRule,
    MasterTaxonomyChannelLink,
    MasterTaxonomyNode,
    ProductChannelTaxonomyAssignment,
    ProductListingPathAssignment,
)


ACTIVE = "active"
INACTIVE = "inactive"


def deactivate_taxonomy_node(
    session: Session,
    node_id: int,
    *,
    cascade: bool = False,
    note: Optional[str] = None,
    purge_remote: bool = False,
    magento_api: Optional[Any] = None,
    shopify_client: Optional[Any] = None,
    dry_run: bool = False,
) -> Dict[str, Any]:
    """Soft-delete a taxonomy node from the backend source of truth.

    This intentionally deactivates local nodes/links/assignments; it does not
    hard-delete remote Magento categories or Shopify collections.
    """
    node = session.get(MasterTaxonomyNode, int(node_id))
    if node is None or not node.is_active:
        raise ValueError("Taxonomy node not found")

    nodes = _nodes_to_deactivate(session, node, cascade=cascade)
    slugs = [str(item.path_slug) for item in nodes if str(item.path_slug or "").strip()]
    node_ids = [int(item.id) for item in nodes]
    now_note = note or f"deactivated from dashboard at {datetime.now(timezone.utc).isoformat()}"

    active_children = [
        item
        for item in _active_direct_children(session, node.id)
        if int(item.id) not in set(node_ids)
    ]
    if active_children:
        raise ValueError("Node has active children; use cascade=true or move/delete children first")

    listing_paths = list(
        session.scalars(select(ChannelListingPath).where(ChannelListingPath.path_slug.in_(slugs))).all()
    )
    listing_path_ids = [int(path.id) for path in listing_paths]
    remote_links = list(
        session.scalars(
            select(MasterTaxonomyChannelLink)
            .where(MasterTaxonomyChannelLink.taxonomy_node_id.in_(node_ids))
            .where(MasterTaxonomyChannelLink.is_active.is_(True))
        ).all()
    )

    stats: Dict[str, Any] = {
        "node_ids": node_ids,
        "path_slugs": slugs,
        "deactivated_nodes": 0,
        "deactivated_listing_paths": 0,
        "deactivated_listing_path_targets": 0,
        "deactivated_listing_assignments": 0,
        "deactivated_collection_landing_pages": 0,
        "deactivated_intersections": 0,
        "deactivated_channel_links": 0,
        "deactivated_channel_assignments": 0,
        "remote_links": [
            {
                "channel_code": link.channel_code,
                "connection_id": link.connection_id,
                "taxonomy_kind": link.taxonomy_kind,
                "remote_id": link.remote_id,
                "remote_path": link.remote_path,
            }
            for link in remote_links
        ],
        "remote_delete_performed": False,
        "remote_delete_note": "Remote Magento/Shopify entities were not hard-deleted; local publish links were deactivated.",
        "remote_purge": None,
    }

    for item in nodes:
        if item.is_active:
            item.is_active = False
            item.notes = _append_note(item.notes, now_note)
            stats["deactivated_nodes"] += 1

    for path in listing_paths:
        if path.is_active:
            path.is_active = False
            path.notes = _append_note(path.notes, now_note)
            stats["deactivated_listing_paths"] += 1

    if listing_path_ids:
        for target in session.scalars(
            select(ChannelListingPathTarget)
            .where(ChannelListingPathTarget.listing_path_id.in_(listing_path_ids))
            .where(ChannelListingPathTarget.is_active.is_(True))
        ).all():
            target.is_active = False
            stats["deactivated_listing_path_targets"] += 1

        for assignment in session.scalars(
            select(ProductListingPathAssignment)
            .where(ProductListingPathAssignment.listing_path_id.in_(listing_path_ids))
            .where(ProductListingPathAssignment.assignment_status == ACTIVE)
        ).all():
            assignment.assignment_status = INACTIVE
            assignment.notes = _append_note(assignment.notes, now_note)
            stats["deactivated_listing_assignments"] += 1

    for page in session.scalars(
        select(CollectionLandingPage)
        .where(CollectionLandingPage.path_slug.in_(slugs))
        .where(CollectionLandingPage.is_active.is_(True))
    ).all():
        page.is_active = False
        page.notes = _append_note(page.notes, now_note)
        stats["deactivated_collection_landing_pages"] += 1

    for rule in session.scalars(
        select(ListingIntersectionRule).where(
            ListingIntersectionRule.is_active.is_(True),
            (
                ListingIntersectionRule.group_path_slug.in_(slugs)
                | ListingIntersectionRule.base_path_slug.in_(slugs)
                | ListingIntersectionRule.seo_path_slug.in_(slugs)
            ),
        )
    ).all():
        rule.is_active = False
        rule.notes = _append_note(rule.notes, now_note)
        stats["deactivated_intersections"] += 1

    for link in remote_links:
        link.is_active = False
        stats["deactivated_channel_links"] += 1
        for assignment in session.scalars(
            select(ProductChannelTaxonomyAssignment)
            .where(ProductChannelTaxonomyAssignment.channel_code == link.channel_code)
            .where(ProductChannelTaxonomyAssignment.taxonomy_kind == link.taxonomy_kind)
            .where(ProductChannelTaxonomyAssignment.remote_id == str(link.remote_id))
            .where(ProductChannelTaxonomyAssignment.assignment_status == ACTIVE)
        ).all():
            if link.connection_id is not None and assignment.connection_id != link.connection_id:
                continue
            assignment.assignment_status = INACTIVE
            assignment.notes = _append_note(assignment.notes, now_note)
            stats["deactivated_channel_assignments"] += 1

    if purge_remote and remote_links:
        from db.master_taxonomy_remote_purge import purge_remote_taxonomy_links

        purge_result = purge_remote_taxonomy_links(
            session,
            remote_links,
            magento_api=magento_api,
            shopify_client=shopify_client,
            dry_run=dry_run,
        )
        stats["remote_purge"] = purge_result
        stats["remote_delete_performed"] = bool(
            (purge_result.get("magento_deleted") or 0) + (purge_result.get("shopify_deleted") or 0)
        ) and not dry_run
        if stats["remote_delete_performed"]:
            stats["remote_delete_note"] = "Remote Magento categories and Shopify collections deleted where possible."

    from db.start_shopping_config_prune import (
        path_rewrites_for_removed_slugs,
        prune_start_shopping_configs,
    )

    stats["start_shopping_prune"] = prune_start_shopping_configs(
        session,
        path_rewrites=path_rewrites_for_removed_slugs(slugs),
        dry_run=False,
        refresh_intersections=True,
    )

    session.flush()
    return stats


def deactivate_taxonomy_node_by_path(
    session: Session,
    path_slug: str,
    *,
    cascade: bool = False,
    note: Optional[str] = None,
    purge_remote: bool = False,
    magento_api: Optional[Any] = None,
    shopify_client: Optional[Any] = None,
    dry_run: bool = False,
) -> Dict[str, Any]:
    slug = normalize_plp_path(path_slug)
    if not slug:
        raise ValueError("path_slug is required")
    node = session.scalar(
        select(MasterTaxonomyNode)
        .where(MasterTaxonomyNode.path_slug == slug)
        .where(MasterTaxonomyNode.is_active.is_(True))
        .limit(1)
    )
    if node is None:
        raise ValueError("Taxonomy node not found for path")
    return deactivate_taxonomy_node(
        session,
        int(node.id),
        cascade=cascade,
        note=note,
        purge_remote=purge_remote,
        magento_api=magento_api,
        shopify_client=shopify_client,
        dry_run=dry_run,
    )


def _nodes_to_deactivate(session: Session, node: MasterTaxonomyNode, *, cascade: bool) -> List[MasterTaxonomyNode]:
    if not cascade:
        return [node]
    slug = normalize_plp_path(node.path_slug)
    return list(
        session.scalars(
            select(MasterTaxonomyNode)
            .where(MasterTaxonomyNode.is_active.is_(True))
            .where(
                (MasterTaxonomyNode.id == node.id)
                | (MasterTaxonomyNode.path_slug.like(f"{slug}/%"))
            )
            .order_by(MasterTaxonomyNode.path_slug.desc())
        ).all()
    )


def _active_direct_children(session: Session, node_id: int) -> List[MasterTaxonomyNode]:
    return list(
        session.scalars(
            select(MasterTaxonomyNode)
            .where(MasterTaxonomyNode.parent_id == int(node_id))
            .where(MasterTaxonomyNode.is_active.is_(True))
        ).all()
    )


def _append_note(existing: Optional[str], note: str) -> str:
    current = str(existing or "").strip()
    return f"{current}\n{note}".strip() if current else note
