"""Shared helpers for master-catalog image push (Magento + Shopify)."""

from __future__ import annotations

from typing import Any, Dict, List, Optional

from sqlalchemy import select
from sqlalchemy.orm import Session

from db.channel_exports import resolve_pipeline_channel_code, resolve_push_skus
from db.image_urls import normalize_external_image_url
from db.master_product_images import image_fields_by_sku
from db.models import MasterProduct
from magento.sync_hashes import compute_images_hash


def images_hash_for_urls(urls: List[str], *, label: str = "") -> str:
    row = {
        "sku": label or "images",
        "base_image": urls[0] if urls else "",
        "additional_images": ",".join(urls[1:]) if len(urls) > 1 else "",
        "name": label,
    }
    return compute_images_hash(row)


def image_urls_from_fields(fields: Dict[str, str]) -> List[str]:
    urls: List[str] = []
    base = str(fields.get("base_image") or fields.get("base_image_url") or "").strip()
    if base:
        urls.append(base)
    addl = str(fields.get("additional_images") or fields.get("additional_images_url") or "").strip()
    if addl:
        for part in addl.split(","):
            url = part.strip()
            if url and url not in urls:
                urls.append(url)
    raw = str(fields.get("image_urls") or "").strip()
    if raw:
        for part in raw.split(","):
            url = part.strip()
            if url and url not in urls:
                urls.append(url)
    seen: set[str] = set()
    normalized: List[str] = []
    for url in urls:
        clean = normalize_external_image_url(url)
        if clean and clean not in seen:
            seen.add(clean)
            normalized.append(clean)
    return normalized


def build_image_push_items(
    session: Session,
    channel_code: str,
    *,
    skus: Optional[List[str]] = None,
    limit: Optional[int] = None,
    only_assigned: bool = True,
    connection_id: Optional[int] = None,
) -> List[Dict[str, Any]]:
    """One item per master SKU with gallery URLs ready for channel media upload."""
    channel = resolve_pipeline_channel_code(channel_code)
    wanted = resolve_push_skus(
        session,
        channel,
        skus=skus,
        only_assigned=only_assigned,
    )
    if limit and len(wanted) > limit:
        wanted = set(sorted(wanted)[:limit])
    if not wanted:
        return []

    from db.channel_sku_mapping import mapping_by_master

    image_fields = image_fields_by_sku(session, sorted(wanted))
    sku_map = mapping_by_master(session, channel, sorted(wanted), connection_id=connection_id)

    names: Dict[str, str] = {}
    for sku, name in session.execute(
        select(MasterProduct.sku, MasterProduct.name).where(MasterProduct.sku.in_(sorted(wanted)))
    ).all():
        names[str(sku)] = str(name or sku)

    items: List[Dict[str, Any]] = []
    for master_sku in sorted(wanted):
        fields = image_fields.get(master_sku) or {}
        urls = image_urls_from_fields(fields)
        if not urls:
            continue
        channel_sku = sku_map.get(master_sku, master_sku)
        label = names.get(master_sku) or master_sku
        items.append(
            {
                "master_sku": master_sku,
                "channel_sku": channel_sku,
                "channel_code": channel,
                "image_urls": urls,
                "images_hash": images_hash_for_urls(urls, label=label),
                "name": label,
            }
        )
    return items


def summarize_image_push_items(items: List[Dict[str, Any]]) -> Dict[str, Any]:
    return {
        "total": len(items),
        "image_count": sum(len(item.get("image_urls") or []) for item in items),
        "skus_with_images": len(items),
    }


def summarize_image_push_scope(
    session: Session,
    channel_code: str,
    *,
    skus: Optional[List[str]] = None,
    limit: Optional[int] = None,
    only_assigned: bool = True,
    connection_id: Optional[int] = None,
) -> Dict[str, Any]:
    """Assigned SKU count vs how many have importable gallery URLs."""
    channel = resolve_pipeline_channel_code(channel_code)
    assigned = resolve_push_skus(
        session,
        channel,
        skus=skus,
        only_assigned=only_assigned,
    )
    items = build_image_push_items(
        session,
        channel,
        skus=skus,
        limit=limit,
        only_assigned=only_assigned,
        connection_id=connection_id,
    )
    summary = summarize_image_push_items(items)
    assigned_count = len(assigned)
    with_images = summary["skus_with_images"]
    summary.update(
        {
            "assigned_sku_count": assigned_count,
            "assigned_with_images": with_images,
            "assigned_without_images": max(0, assigned_count - with_images),
        }
    )
    if assigned_count and not with_images:
        summary["blocker"] = "no_gallery_images"
        summary["hint"] = (
            f"{assigned_count} SKU(s) assigned to {channel} but none have gallery images. "
            "Import product images on Catalog Import (#/catalog), then retry."
        )
    elif not assigned_count and only_assigned:
        summary["blocker"] = "no_assignments"
        summary["hint"] = f"No master SKUs assigned to {channel}. Assign on Mappings or Publish first."
    return summary
