# app/services/marketplace_import_job_service.py
from __future__ import annotations

import logging
from typing import TYPE_CHECKING

from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm import Session

from app.modules.marketplace.exceptions import (
    ImportJobNotFoundException,
    ImportJobNotOwnedException,
    ImportValidationError,
)
from app.modules.marketplace.models import (
    MarketplaceImportError,
    MarketplaceImportJob,
)
from app.modules.marketplace.schemas import (
    AdminMarketplaceImportJobResponse,
    MarketplaceImportJobRequest,
    MarketplaceImportJobResponse,
)

if TYPE_CHECKING:
    from app.modules.tenancy.models import Store, User

logger = logging.getLogger(__name__)


class MarketplaceImportJobService:
    """Service class for Marketplace operations."""

    def create_import_job(
        self,
        db: Session,
        request: MarketplaceImportJobRequest,
        store: Store,  # CHANGED: Store object from middleware
        user: User,
    ) -> MarketplaceImportJob:
        """
        Create a new marketplace import job.

        Args:
            db: Database session
            request: Import request data
            store: Store object (from middleware)
            user: User creating the job

        Returns:
            Created MarketplaceImportJob object
        """
        try:
            # Create marketplace import job record
            import_job = MarketplaceImportJob(
                status="pending",
                source_url=request.source_url,
                marketplace=request.marketplace,
                language=request.language,
                store_id=store.id,
                user_id=user.id,
            )

            db.add(import_job)
            db.flush()
            db.refresh(import_job)

            logger.info(
                f"Created marketplace import job {import_job.id}: "
                f"{request.marketplace} -> {store.name} (code: {store.store_code}) "
                f"by user {user.username}"
            )

            return import_job

        except SQLAlchemyError as e:
            logger.error(f"Error creating import job: {str(e)}")
            raise ImportValidationError("Failed to create import job")

    def get_import_job_by_id(
        self, db: Session, job_id: int, user: User
    ) -> MarketplaceImportJob:
        """Get a marketplace import job by ID with access control."""
        try:
            job = (
                db.query(MarketplaceImportJob)
                .filter(MarketplaceImportJob.id == job_id)
                .first()
            )

            if not job:
                raise ImportJobNotFoundException(job_id)

            # Users can only see their own jobs, admins can see all
            if not user.is_admin and job.user_id != user.id:
                raise ImportJobNotOwnedException(job_id, user.id)

            return job

        except (ImportJobNotFoundException, ImportJobNotOwnedException):
            raise
        except SQLAlchemyError as e:
            logger.error(f"Error getting import job {job_id}: {str(e)}")
            raise ImportValidationError("Failed to retrieve import job")

    def get_import_job_for_store(
        self, db: Session, job_id: int, store_id: int
    ) -> MarketplaceImportJob:
        """
        Get a marketplace import job by ID with store access control.

        Validates that the job belongs to the specified store.

        Args:
            db: Database session
            job_id: Import job ID
            store_id: Store ID from token (to verify ownership)

        Raises:
            ImportJobNotFoundException: If job not found
            UnauthorizedStoreAccessException: If job doesn't belong to store
        """
        from app.modules.tenancy.exceptions import UnauthorizedStoreAccessException

        try:
            job = (
                db.query(MarketplaceImportJob)
                .filter(MarketplaceImportJob.id == job_id)
                .first()
            )

            if not job:
                raise ImportJobNotFoundException(job_id)

            # Verify job belongs to store (service layer validation)
            if job.store_id != store_id:
                raise UnauthorizedStoreAccessException(
                    store_code=str(store_id),
                    user_id=0,  # Not user-specific, but store mismatch
                )

            return job

        except (ImportJobNotFoundException, UnauthorizedStoreAccessException):
            raise
        except SQLAlchemyError as e:
            logger.error(
                f"Error getting import job {job_id} for store {store_id}: {str(e)}"
            )
            raise ImportValidationError("Failed to retrieve import job")

    def get_import_jobs(
        self,
        db: Session,
        store: Store,  # ADDED: Store filter
        user: User,
        marketplace: str | None = None,
        skip: int = 0,
        limit: int = 50,
    ) -> list[MarketplaceImportJob]:
        """Get marketplace import jobs for a specific store."""
        try:
            query = db.query(MarketplaceImportJob).filter(
                MarketplaceImportJob.store_id == store.id
            )

            # Users can only see their own jobs, admins can see all store jobs
            if not user.is_admin:
                query = query.filter(MarketplaceImportJob.user_id == user.id)

            # Apply marketplace filter
            if marketplace:
                query = query.filter(
                    MarketplaceImportJob.marketplace.ilike(f"%{marketplace}%")
                )

            # Order by creation date (newest first) and apply pagination
            jobs = (
                query.order_by(
                    MarketplaceImportJob.created_at.desc(),
                    MarketplaceImportJob.id.desc(),  # Tiebreaker for same timestamp
                )
                .offset(skip)
                .limit(limit)
                .all()
            )

            return jobs

        except SQLAlchemyError as e:
            logger.error(f"Error getting import jobs: {str(e)}")
            raise ImportValidationError("Failed to retrieve import jobs")

    def convert_to_response_model(
        self, job: MarketplaceImportJob
    ) -> MarketplaceImportJobResponse:
        """Convert database model to API response model."""
        return MarketplaceImportJobResponse(
            job_id=job.id,
            status=job.status,
            marketplace=job.marketplace,
            language=job.language,
            store_id=job.store_id,
            store_code=job.store.store_code if job.store else None,
            store_name=job.store.name if job.store else None,
            source_url=job.source_url,
            imported=job.imported_count or 0,
            updated=job.updated_count or 0,
            total_processed=job.total_processed or 0,
            error_count=job.error_count or 0,
            error_message=job.error_message,
            created_at=job.created_at,
            started_at=job.started_at,
            completed_at=job.completed_at,
        )

    def convert_to_admin_response_model(
        self, job: MarketplaceImportJob
    ) -> AdminMarketplaceImportJobResponse:
        """Convert database model to admin API response model with extra fields."""
        return AdminMarketplaceImportJobResponse(
            id=job.id,
            job_id=job.id,
            status=job.status,
            marketplace=job.marketplace,
            language=job.language,
            store_id=job.store_id,
            store_code=job.store.store_code if job.store else None,
            store_name=job.store.name if job.store else None,
            source_url=job.source_url,
            imported=job.imported_count or 0,
            updated=job.updated_count or 0,
            total_processed=job.total_processed or 0,
            error_count=job.error_count or 0,
            error_message=job.error_message,
            error_details=[],
            created_at=job.created_at,
            started_at=job.started_at,
            completed_at=job.completed_at,
            created_by_name=job.user.username if job.user else None,
        )

    def get_all_import_jobs_paginated(
        self,
        db: Session,
        marketplace: str | None = None,
        status: str | None = None,
        page: int = 1,
        limit: int = 100,
    ) -> tuple[list[MarketplaceImportJob], int]:
        """Get all marketplace import jobs with pagination (for admin)."""
        try:
            query = db.query(MarketplaceImportJob)

            if marketplace:
                query = query.filter(
                    MarketplaceImportJob.marketplace.ilike(f"%{marketplace}%")
                )
            if status:
                query = query.filter(MarketplaceImportJob.status == status)

            total = query.count()
            skip = (page - 1) * limit
            jobs = (
                query.order_by(
                    MarketplaceImportJob.created_at.desc(),
                    MarketplaceImportJob.id.desc(),  # Tiebreaker for same timestamp
                )
                .offset(skip)
                .limit(limit)
                .all()
            )

            return jobs, total

        except SQLAlchemyError as e:
            logger.error(f"Error getting all import jobs: {str(e)}")
            raise ImportValidationError("Failed to retrieve import jobs")

    def get_import_job_by_id_admin(
        self, db: Session, job_id: int
    ) -> MarketplaceImportJob:
        """Get a marketplace import job by ID (admin - no access control)."""
        job = (
            db.query(MarketplaceImportJob)
            .filter(MarketplaceImportJob.id == job_id)
            .first()
        )
        if not job:
            raise ImportJobNotFoundException(job_id)
        return job

    def get_import_job_errors(
        self,
        db: Session,
        job_id: int,
        error_type: str | None = None,
        page: int = 1,
        limit: int = 50,
    ) -> tuple[list[MarketplaceImportError], int]:
        """
        Get import errors for a specific job with pagination.

        Args:
            db: Database session
            job_id: Import job ID
            error_type: Optional filter by error type
            page: Page number (1-indexed)
            limit: Number of items per page

        Returns:
            Tuple of (list of errors, total count)
        """
        try:
            query = db.query(MarketplaceImportError).filter(
                MarketplaceImportError.import_job_id == job_id
            )

            if error_type:
                query = query.filter(MarketplaceImportError.error_type == error_type)

            total = query.count()

            offset = (page - 1) * limit
            errors = (
                query.order_by(MarketplaceImportError.row_number)
                .offset(offset)
                .limit(limit)
                .all()
            )

            return errors, total

        except SQLAlchemyError as e:
            logger.error(f"Error getting import job errors for job {job_id}: {str(e)}")
            raise ImportValidationError("Failed to retrieve import errors")


    # ========================================================================
    # Cross-module public API methods
    # ========================================================================

    def get_import_job_stats(
        self, db: Session, store_id: int | None = None
    ) -> dict:
        """
        Get import job statistics.

        Args:
            db: Database session
            store_id: Optional store scope

        Returns:
            Dict with total, pending, completed, failed counts
        """
        from sqlalchemy import func

        base = db.query(func.count(MarketplaceImportJob.id))
        if store_id is not None:
            base = base.filter(MarketplaceImportJob.store_id == store_id)

        total = base.scalar() or 0
        pending = (
            base.filter(MarketplaceImportJob.status == "pending").scalar() or 0
        )
        completed = (
            base.filter(MarketplaceImportJob.status == "completed").scalar() or 0
        )
        failed = (
            base.filter(MarketplaceImportJob.status == "failed").scalar() or 0
        )
        processing = (
            base.filter(MarketplaceImportJob.status == "processing").scalar() or 0
        )

        # Count today's imports
        from datetime import UTC, datetime

        today_start = datetime.now(UTC).replace(
            hour=0, minute=0, second=0, microsecond=0
        )
        today_base = db.query(func.count(MarketplaceImportJob.id)).filter(
            MarketplaceImportJob.created_at >= today_start,
        )
        if store_id is not None:
            today_base = today_base.filter(MarketplaceImportJob.store_id == store_id)
        today = today_base.scalar() or 0

        return {
            "total": total,
            "pending": pending,
            "processing": processing,
            "completed": completed,
            "failed": failed,
            "today": today,
        }

    def get_total_import_job_count(self, db: Session) -> int:
        """
        Get total count of all import jobs.

        Args:
            db: Database session

        Returns:
            Total import job count
        """
        from sqlalchemy import func

        return db.query(func.count(MarketplaceImportJob.id)).scalar() or 0

    def get_import_job_count_by_status(
        self, db: Session, status: str, store_id: int | None = None
    ) -> int:
        """
        Count import jobs by status.

        Args:
            db: Database session
            status: Job status to count
            store_id: Optional store scope

        Returns:
            Count of jobs with given status
        """
        from sqlalchemy import func

        query = db.query(func.count(MarketplaceImportJob.id)).filter(
            MarketplaceImportJob.status == status
        )
        if store_id is not None:
            query = query.filter(MarketplaceImportJob.store_id == store_id)
        return query.scalar() or 0


marketplace_import_job_service = MarketplaceImportJobService()
