"""Async enqueue for channel image-push (keeps HTTP POST from blocking on DB pool)."""

from __future__ import annotations

import logging
import threading
from datetime import datetime
from typing import Any, Dict, Optional

from sqlalchemy import select

from app.jobs.channel_jobs import enqueue_channel_job, job_to_dict
from db.magento_repositories import SqlAlchemyMagentoSyncQueueRepository
from db.models import ChannelJob, MagentoSyncQueue
from db.session import get_session

logger = logging.getLogger(__name__)

_acceptance_lock = threading.Lock()
_acceptance: Dict[str, Dict[str, Any]] = {}


def _set_acceptance(label: str, payload: Dict[str, Any]) -> None:
    with _acceptance_lock:
        _acceptance[label] = payload


def get_acceptance(label: str) -> Optional[Dict[str, Any]]:
    with _acceptance_lock:
        cached = _acceptance.get(label)
    if cached and cached.get("status") != "pending":
        return dict(cached)

    with get_session() as session:
        queue = session.scalar(
            select(MagentoSyncQueue).where(MagentoSyncQueue.label == label)
        )
        if queue is not None:
            job = session.scalar(
                select(ChannelJob).where(ChannelJob.backend_queue_id == queue.id)
            )
            if job is not None:
                return {
                    "status": "ready",
                    "label": label,
                    "channel_code": "magento",
                    "job_id": job.id,
                    "queue_id": queue.id,
                    "job": job_to_dict(job),
                }
        job = session.scalar(
            select(ChannelJob)
            .where(ChannelJob.notes == label)
            .order_by(ChannelJob.id.desc())
        )
        if job is not None:
            return {
                "status": "ready",
                "label": label,
                "channel_code": job.channel_type,
                "job_id": job.id,
                "job": job_to_dict(job),
            }

    if cached:
        return dict(cached)
    return {"status": "pending", "label": label}


def enqueue_magento_image_push_background(
    label: str,
    *,
    connection_id: int,
    dry_run: bool,
    options: Dict[str, Any],
) -> None:
    _set_acceptance(label, {"status": "pending", "label": label, "channel_code": "magento"})
    try:
        from main import _channel_code_for_connection, _connection_row

        with get_session() as session:
            connection = _connection_row(session, connection_id)
            if not connection or connection["channel_type"] != "magento":
                raise RuntimeError("Magento connection not found")
            native_id = connection["native_id"]
            channel_code = _channel_code_for_connection(connection)
            from db.channel_exports import resolve_push_skus
            from db.channel_image_push import build_image_push_items, summarize_image_push_items

            limit_skus = options.get("limit_skus")
            assigned = resolve_push_skus(
                session,
                "magento",
                skus=limit_skus,
                only_assigned=True,
            )
            items = build_image_push_items(
                session,
                "magento",
                skus=limit_skus,
                only_assigned=True,
                connection_id=connection_id,
            )
            preview = summarize_image_push_items(items)
            preview["assigned_sku_count"] = len(assigned)
            queue_id = SqlAlchemyMagentoSyncQueueRepository(session).enqueue(
                native_id,
                label,
                options=options,
                supersede_queued=True,
            )
            job = enqueue_channel_job(
                session,
                channel_connection_id=connection_id,
                channel_type="magento",
                native_connection_id=native_id,
                channel_code=channel_code,
                job_type="push_images",
                dry_run=dry_run,
                mode="images_only",
                options=options,
            )
            job.status = "delegated"
            job.backend_queue_id = queue_id
            job.result = {
                "status": "delegated",
                "backend": "magento_sync_queue",
                "backend_status": "queued",
                "queue_id": queue_id,
                "label": label,
                "mode": "images_only",
                "preview": preview,
            }
            if preview.get("assigned_sku_count") == 0:
                job.notes = "No Magento-assigned SKUs. Assign SKUs before pushing images."
            elif preview.get("skus_with_images", preview.get("total", 0)) == 0:
                job.notes = (
                    f"{preview['assigned_sku_count']} assigned SKU(s) but none have gallery images "
                    "(import on Catalog Import)."
                )
            job_data = job_to_dict(job)
            session.commit()
        _set_acceptance(
            label,
            {
                "status": "ready",
                "label": label,
                "channel_code": "magento",
                "job_id": job_data["id"],
                "queue_id": queue_id,
                "dry_run": dry_run,
                "job": job_data,
            },
        )
        logger.info("image-push enqueue ready label=%s job_id=%s queue_id=%s", label, job_data["id"], queue_id)
    except Exception as exc:
        logger.exception("image-push enqueue failed label=%s", label)
        _set_acceptance(label, {"status": "failed", "label": label, "error": str(exc)})


def enqueue_shopify_image_push_background(
    label: str,
    *,
    connection_id: int,
    dry_run: bool,
    options: Dict[str, Any],
) -> None:
    _set_acceptance(label, {"status": "pending", "label": label, "channel_code": "shopify"})
    try:
        from main import _channel_code_for_connection, _connection_row

        with get_session() as session:
            connection = _connection_row(session, connection_id)
            if not connection or connection["channel_type"] != "shopify":
                raise RuntimeError("Shopify connection not found")
            opts = dict(options)
            opts["shop_code"] = opts.get("shop_code") or connection.get("store_code")
            opts["connection_id"] = connection_id
            job = enqueue_channel_job(
                session,
                channel_connection_id=connection_id,
                channel_type="shopify",
                native_connection_id=connection["native_id"],
                channel_code=_channel_code_for_connection(connection),
                job_type="push_images",
                dry_run=dry_run,
                mode="images_only",
                options=opts,
                notes=label,
            )
            job_data = job_to_dict(job)
            session.commit()
        _set_acceptance(
            label,
            {
                "status": "ready",
                "label": label,
                "channel_code": "shopify",
                "job_id": job_data["id"],
                "dry_run": dry_run,
                "job": job_data,
            },
        )
        logger.info("image-push enqueue ready label=%s job_id=%s (shopify)", label, job_data["id"])
    except Exception as exc:
        logger.exception("image-push enqueue failed label=%s", label)
        _set_acceptance(label, {"status": "failed", "label": label, "error": str(exc)})


def new_image_push_label(channel: str) -> str:
    return f"channel-pipeline-{channel}-images-{datetime.utcnow().strftime('%Y%m%d-%H%M%S%f')}"
