# app/tasks/letzshop_tasks.py
"""Background tasks for Letzshop historical order imports."""

import logging
from datetime import UTC, datetime
from typing import Callable

from app.core.database import SessionLocal
from app.services.letzshop import LetzshopClientError
from app.services.letzshop.credentials_service import LetzshopCredentialsService
from app.services.letzshop.order_service import LetzshopOrderService
from models.database.letzshop import LetzshopHistoricalImportJob

logger = logging.getLogger(__name__)


def _get_credentials_service(db) -> LetzshopCredentialsService:
    """Create a credentials service instance."""
    return LetzshopCredentialsService(db)


def _get_order_service(db) -> LetzshopOrderService:
    """Create an order service instance."""
    return LetzshopOrderService(db)


def process_historical_import(job_id: int, vendor_id: int):
    """
    Background task for historical order import with progress tracking.

    Imports both confirmed and declined orders from Letzshop API,
    updating job progress in the database for frontend polling.

    Args:
        job_id: ID of the LetzshopHistoricalImportJob record
        vendor_id: ID of the vendor to import orders for
    """
    db = SessionLocal()
    job = None

    try:
        # Get the import job
        job = (
            db.query(LetzshopHistoricalImportJob)
            .filter(LetzshopHistoricalImportJob.id == job_id)
            .first()
        )
        if not job:
            logger.error(f"Historical import job {job_id} not found")
            return

        # Mark as started
        job.status = "fetching"
        job.started_at = datetime.now(UTC)
        db.commit()

        creds_service = _get_credentials_service(db)
        order_service = _get_order_service(db)

        # Create progress callback for fetching
        def fetch_progress_callback(page: int, total_fetched: int):
            """Update fetch progress in database."""
            job.current_page = page
            job.shipments_fetched = total_fetched
            db.commit()

        # Create progress callback for processing
        def create_processing_callback(
            phase: str,
        ) -> Callable[[int, int, int, int], None]:
            """Create a processing progress callback for a phase."""

            def callback(processed: int, imported: int, updated: int, skipped: int):
                job.orders_processed = processed
                job.orders_imported = imported
                job.orders_updated = updated
                job.orders_skipped = skipped
                db.commit()

            return callback

        with creds_service.create_client(vendor_id) as client:
            # ================================================================
            # Phase 1: Import confirmed orders
            # ================================================================
            job.current_phase = "confirmed"
            job.current_page = 0
            job.shipments_fetched = 0
            db.commit()

            logger.info(f"Job {job_id}: Fetching confirmed shipments for vendor {vendor_id}")

            confirmed_shipments = client.get_all_shipments_paginated(
                state="confirmed",
                page_size=50,
                progress_callback=fetch_progress_callback,
            )

            logger.info(f"Job {job_id}: Fetched {len(confirmed_shipments)} confirmed shipments")

            # Process confirmed shipments
            job.status = "processing"
            job.orders_processed = 0
            job.orders_imported = 0
            job.orders_updated = 0
            job.orders_skipped = 0
            db.commit()

            confirmed_stats = order_service.import_historical_shipments(
                vendor_id=vendor_id,
                shipments=confirmed_shipments,
                match_products=True,
                progress_callback=create_processing_callback("confirmed"),
            )

            # Store confirmed stats
            job.confirmed_stats = {
                "total": confirmed_stats["total"],
                "imported": confirmed_stats["imported"],
                "updated": confirmed_stats["updated"],
                "skipped": confirmed_stats["skipped"],
                "products_matched": confirmed_stats["products_matched"],
                "products_not_found": confirmed_stats["products_not_found"],
            }
            job.products_matched = confirmed_stats["products_matched"]
            job.products_not_found = confirmed_stats["products_not_found"]
            db.commit()

            logger.info(
                f"Job {job_id}: Confirmed phase complete - "
                f"imported={confirmed_stats['imported']}, "
                f"updated={confirmed_stats['updated']}, "
                f"skipped={confirmed_stats['skipped']}"
            )

            # ================================================================
            # Phase 2: Import unconfirmed (pending) orders
            # Note: Letzshop API has no "declined" state. Declined items
            # are tracked at the inventory unit level, not shipment level.
            # Valid states: unconfirmed, confirmed, completed, accepted
            # ================================================================
            job.current_phase = "unconfirmed"
            job.status = "fetching"
            job.current_page = 0
            job.shipments_fetched = 0
            db.commit()

            logger.info(f"Job {job_id}: Fetching unconfirmed shipments for vendor {vendor_id}")

            unconfirmed_shipments = client.get_all_shipments_paginated(
                state="unconfirmed",
                page_size=50,
                progress_callback=fetch_progress_callback,
            )

            logger.info(f"Job {job_id}: Fetched {len(unconfirmed_shipments)} unconfirmed shipments")

            # Process unconfirmed shipments
            job.status = "processing"
            job.orders_processed = 0
            db.commit()

            unconfirmed_stats = order_service.import_historical_shipments(
                vendor_id=vendor_id,
                shipments=unconfirmed_shipments,
                match_products=True,
                progress_callback=create_processing_callback("unconfirmed"),
            )

            # Store unconfirmed stats (in declined_stats field for compatibility)
            job.declined_stats = {
                "total": unconfirmed_stats["total"],
                "imported": unconfirmed_stats["imported"],
                "updated": unconfirmed_stats["updated"],
                "skipped": unconfirmed_stats["skipped"],
                "products_matched": unconfirmed_stats["products_matched"],
                "products_not_found": unconfirmed_stats["products_not_found"],
            }

            # Add to cumulative product matching stats
            job.products_matched += unconfirmed_stats["products_matched"]
            job.products_not_found += unconfirmed_stats["products_not_found"]

            logger.info(
                f"Job {job_id}: Unconfirmed phase complete - "
                f"imported={unconfirmed_stats['imported']}, "
                f"updated={unconfirmed_stats['updated']}, "
                f"skipped={unconfirmed_stats['skipped']}"
            )

            # ================================================================
            # Complete
            # ================================================================
            job.status = "completed"
            job.completed_at = datetime.now(UTC)
            db.commit()

            # Update credentials sync status
            creds_service.update_sync_status(vendor_id, "success", None)

            logger.info(f"Job {job_id}: Historical import completed successfully")

    except LetzshopClientError as e:
        logger.error(f"Job {job_id}: Letzshop API error: {e}")
        if job is not None:
            try:
                job.status = "failed"
                job.error_message = f"Letzshop API error: {e}"
                job.completed_at = datetime.now(UTC)
                db.commit()

                creds_service = _get_credentials_service(db)
                creds_service.update_sync_status(vendor_id, "failed", str(e))
            except Exception as commit_error:
                logger.error(f"Job {job_id}: Failed to update job status: {commit_error}")
                db.rollback()

    except Exception as e:
        logger.error(f"Job {job_id}: Unexpected error: {e}", exc_info=True)
        if job is not None:
            try:
                job.status = "failed"
                job.error_message = str(e)
                job.completed_at = datetime.now(UTC)
                db.commit()
            except Exception as commit_error:
                logger.error(f"Job {job_id}: Failed to update job status: {commit_error}")
                db.rollback()

    finally:
        if hasattr(db, "close") and callable(db.close):
            try:
                db.close()
            except Exception as close_error:
                logger.error(f"Job {job_id}: Error closing database session: {close_error}")
