# app/services/marketplace_import_job_service.py
import logging

from sqlalchemy.orm import Session

from app.exceptions import ValidationException
from app.modules.marketplace.exceptions import (
    ImportJobNotFoundException,
    ImportJobNotOwnedException,
)
from app.modules.marketplace.models import (
    MarketplaceImportError,
    MarketplaceImportJob,
)
from app.modules.tenancy.models import User
from app.modules.tenancy.models import Vendor
from app.modules.marketplace.schemas import (
    AdminMarketplaceImportJobResponse,
    MarketplaceImportJobRequest,
    MarketplaceImportJobResponse,
)

logger = logging.getLogger(__name__)


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

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

        Args:
            db: Database session
            request: Import request data
            vendor: Vendor 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,
                vendor_id=vendor.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} -> {vendor.name} (code: {vendor.vendor_code}) "
                f"by user {user.username}"
            )

            return import_job

        except Exception as e:
            logger.error(f"Error creating import job: {str(e)}")
            raise ValidationException("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 user.role != "admin" and job.user_id != user.id:
                raise ImportJobNotOwnedException(job_id, user.id)

            return job

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

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

        Validates that the job belongs to the specified vendor.

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

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

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

            if not job:
                raise ImportJobNotFoundException(job_id)

            # Verify job belongs to vendor (service layer validation)
            if job.vendor_id != vendor_id:
                raise UnauthorizedVendorAccessException(
                    vendor_code=str(vendor_id),
                    user_id=0,  # Not user-specific, but vendor mismatch
                )

            return job

        except (ImportJobNotFoundException, UnauthorizedVendorAccessException):
            raise
        except Exception as e:
            logger.error(
                f"Error getting import job {job_id} for vendor {vendor_id}: {str(e)}"
            )
            raise ValidationException("Failed to retrieve import job")

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

            # Users can only see their own jobs, admins can see all vendor jobs
            if user.role != "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 Exception as e:
            logger.error(f"Error getting import jobs: {str(e)}")
            raise ValidationException("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,
            vendor_id=job.vendor_id,
            vendor_code=job.vendor.vendor_code if job.vendor else None,
            vendor_name=job.vendor.name if job.vendor 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,
            vendor_id=job.vendor_id,
            vendor_code=job.vendor.vendor_code if job.vendor else None,
            vendor_name=job.vendor.name if job.vendor 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 Exception as e:
            logger.error(f"Error getting all import jobs: {str(e)}")
            raise ValidationException("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 Exception as e:
            logger.error(f"Error getting import job errors for job {job_id}: {str(e)}")
            raise ValidationException("Failed to retrieve import errors")


marketplace_import_job_service = MarketplaceImportJobService()
