"""
Quality Template Repository for Production Service
"""

from typing import List, Optional, Tuple
from sqlalchemy import and_, or_, func, select
from sqlalchemy.ext.asyncio import AsyncSession
from uuid import UUID
import structlog

from .base import ProductionBaseRepository
from ..models.production import QualityCheckTemplate, ProcessStage

logger = structlog.get_logger()


class QualityTemplateRepository(ProductionBaseRepository):
    """Repository for quality check template operations"""

    def __init__(self, session: AsyncSession):
        super().__init__(QualityCheckTemplate, session)

    async def get_templates_by_tenant(
        self,
        tenant_id: str,
        stage: Optional[ProcessStage] = None,
        check_type: Optional[str] = None,
        is_active: Optional[bool] = True,
        skip: int = 0,
        limit: int = 100
    ) -> Tuple[List[QualityCheckTemplate], int]:
        """Get quality check templates with filtering and pagination"""

        filters = [QualityCheckTemplate.tenant_id == tenant_id]

        if is_active is not None:
            filters.append(QualityCheckTemplate.is_active == is_active)

        if check_type:
            filters.append(QualityCheckTemplate.check_type == check_type)

        if stage:
            filters.append(
                or_(
                    func.json_contains(
                        QualityCheckTemplate.applicable_stages,
                        f'"{stage.value}"'
                    ),
                    QualityCheckTemplate.applicable_stages.is_(None)
                )
            )

        # Get total count with SQLAlchemy conditions
        count_query = select(func.count(QualityCheckTemplate.id)).where(and_(*filters))
        count_result = await self.session.execute(count_query)
        total = count_result.scalar()

        # Get templates with ordering
        query = select(QualityCheckTemplate).where(and_(*filters)).order_by(
            QualityCheckTemplate.is_critical.desc(),
            QualityCheckTemplate.is_required.desc(),
            QualityCheckTemplate.name
        ).offset(skip).limit(limit)

        result = await self.session.execute(query)
        templates = result.scalars().all()

        return templates, total

    async def get_by_tenant_and_id(
        self,
        tenant_id: str,
        template_id: UUID
    ) -> Optional[QualityCheckTemplate]:
        """Get a specific quality check template by tenant and ID"""

        return await self.get_by_filters(
            and_(
                QualityCheckTemplate.tenant_id == tenant_id,
                QualityCheckTemplate.id == template_id
            )
        )

    async def get_templates_for_stage(
        self,
        tenant_id: str,
        stage: ProcessStage,
        is_active: Optional[bool] = True
    ) -> List[QualityCheckTemplate]:
        """Get all quality check templates applicable to a specific process stage"""

        filters = [
            QualityCheckTemplate.tenant_id == tenant_id,
            or_(
                func.json_contains(
                    QualityCheckTemplate.applicable_stages,
                    f'"{stage.value}"'
                ),
                QualityCheckTemplate.applicable_stages.is_(None)
            )
        ]

        if is_active is not None:
            filters.append(QualityCheckTemplate.is_active == is_active)

        return await self.get_multi(
            filters=and_(*filters),
            order_by=[
                QualityCheckTemplate.is_critical.desc(),
                QualityCheckTemplate.is_required.desc(),
                QualityCheckTemplate.weight.desc(),
                QualityCheckTemplate.name
            ]
        )

    async def check_template_code_exists(
        self,
        tenant_id: str,
        template_code: str,
        exclude_id: Optional[UUID] = None
    ) -> bool:
        """Check if a template code already exists for the tenant"""

        filters = [
            QualityCheckTemplate.tenant_id == tenant_id,
            QualityCheckTemplate.template_code == template_code
        ]

        if exclude_id:
            filters.append(QualityCheckTemplate.id != exclude_id)

        existing = await self.get_by_filters(and_(*filters))
        return existing is not None

    async def get_by_filters(self, *filters):
        """Get a single record by filters"""
        try:
            query = select(self.model).where(and_(*filters))
            result = await self.session.execute(query)
            return result.scalar_one_or_none()
        except Exception as e:
            logger.error("Error getting record by filters", error=str(e), filters=str(filters))
            raise

    async def get_templates_by_ids(
        self,
        tenant_id: str,
        template_ids: List[UUID]
    ) -> List[QualityCheckTemplate]:
        """Get quality check templates by list of IDs"""

        return await self.get_multi(
            filters=and_(
                QualityCheckTemplate.tenant_id == tenant_id,
                QualityCheckTemplate.id.in_(template_ids)
            ),
            order_by=[
                QualityCheckTemplate.is_critical.desc(),
                QualityCheckTemplate.is_required.desc(),
                QualityCheckTemplate.weight.desc()
            ]
        )
