"""Scan channel catalogs and link remote SKUs to master products (channel-first)."""

from __future__ import annotations

from typing import Any, Dict, Iterable, List, Optional

from sqlalchemy import select
from sqlalchemy.orm import Session

from db.channel_assignments import assign_skus
from db.channel_exports import resolve_pipeline_channel_code
from db.channel_sku_mapping import (
    link_channel_catalog_to_masters,
    reconcile_connection_id_for_channel,
)
from db.compat_connections import compat_connection_id
from db.models import ChannelConnection, MagentoConnection, MasterProduct, ShopifyConnection


DEFAULT_CHANNELS = ("magento", "shopify", "plytix")


def _active_connections(session: Session) -> Dict[str, Dict[str, Any]]:
    out: Dict[str, Dict[str, Any]] = {}
    magento = session.scalars(select(MagentoConnection).order_by(MagentoConnection.id)).first()
    if magento:
        out["magento"] = {
            "native_id": magento.id,
            "connection_id": compat_connection_id("magento", magento.id),
        }
    shopify = session.scalars(
        select(ShopifyConnection).where(ShopifyConnection.status == "active").order_by(ShopifyConnection.id)
    ).first()
    if shopify is None:
        shopify = session.scalars(select(ShopifyConnection).order_by(ShopifyConnection.id)).first()
    if shopify:
        out["shopify"] = {
            "native_id": shopify.id,
            "connection_id": compat_connection_id("shopify", shopify.id),
        }
    plytix = session.scalars(
        select(ChannelConnection)
        .where(ChannelConnection.channel_type == "plytix")
        .order_by(ChannelConnection.id)
    ).first()
    if plytix:
        out["plytix"] = {
            "native_id": plytix.id,
            "connection_id": compat_connection_id("generic", plytix.id),
        }
    return out


def assign_all_active_masters(
    session: Session,
    *,
    channels: Iterable[str] = DEFAULT_CHANNELS,
    reason: str = "link_master_skus_cli",
) -> Dict[str, Any]:
    """Ensure every active master SKU is assigned to each requested channel (for later push scope)."""
    skus = [
        str(sku).strip()
        for (sku,) in session.execute(
            select(MasterProduct.sku).where(MasterProduct.is_active.is_(True)).order_by(MasterProduct.sku)
        ).all()
        if str(sku).strip()
    ]
    summary: Dict[str, Any] = {"master_count": len(skus), "channels": {}}
    for channel in channels:
        channel_code = resolve_pipeline_channel_code(channel)
        try:
            with session.begin_nested():
                summary["channels"][channel_code] = assign_skus(
                    session,
                    skus=skus,
                    channel_code=channel_code,
                    reason=reason,
                )
        except Exception as exc:
            summary["channels"][channel_code] = {"status": "failed", "error": str(exc)}
    return summary


def scan_and_link_channels(
    session: Session,
    *,
    channels: Optional[Iterable[str]] = None,
    only_assigned: bool = False,
    assign_all: bool = False,
    dry_run: bool = False,
    magento_connection_id: Optional[int] = None,
    shopify_connection_id: Optional[int] = None,
) -> Dict[str, Any]:
    """Link channel catalog SKUs to master products (channel-first, prefix-aware)."""
    selected = [resolve_pipeline_channel_code(ch) for ch in (channels or DEFAULT_CHANNELS)]
    connections = _active_connections(session)

    summary: Dict[str, Any] = {
        "status": "ok",
        "link_mode": "channel_first",
        "dry_run": dry_run,
        "only_assigned": only_assigned,
        "assign_all": assign_all,
        "channels": {},
    }

    if only_assigned:
        summary["note"] = (
            "only_assigned is ignored for channel-first linking; "
            "all remote catalog SKUs are scanned. Use --assign-all to seed push assignments."
        )

    if assign_all and not dry_run:
        summary["assignments"] = assign_all_active_masters(session, channels=selected)

    for channel in selected:
        conn = connections.get(channel, {})
        native_id = magento_connection_id if channel == "magento" else None
        if channel == "magento" and native_id is None:
            native_id = conn.get("native_id")
        compat_id = shopify_connection_id if channel == "shopify" else None
        if channel == "shopify" and compat_id is None:
            compat_id = conn.get("connection_id")
        plytix_compat = conn.get("connection_id") if channel == "plytix" else None

        reconcile_id = reconcile_connection_id_for_channel(
            channel,
            compat_connection_id=compat_id or plytix_compat,
            native_connection_id=native_id,
        )

        channel_result: Dict[str, Any] = {
            "connection_id": reconcile_id,
        }

        if not reconcile_id and channel != "plytix":
            channel_result["status"] = "skipped"
            channel_result["reason"] = "no_connection_configured"
            summary["channels"][channel] = channel_result
            continue

        try:
            with session.begin_nested():
                link_result = link_channel_catalog_to_masters(
                    session,
                    channel,
                    connection_id=reconcile_id,
                    native_connection_id=native_id or conn.get("native_id"),
                    compat_connection_id=compat_id or plytix_compat,
                    dry_run=dry_run,
                )
                channel_result.update(link_result)
                if not link_result.get("remote_sku_count"):
                    channel_result["warning"] = (
                        "Remote catalog is empty — run channel pull first "
                        "(magento_pull / shopify API / plytix ingest)."
                    )
        except Exception as exc:
            channel_result["status"] = "failed"
            channel_result["error"] = str(exc)
            summary["status"] = "partial"

        summary["channels"][channel] = channel_result

    return summary
