"""
Base Repository for Production Service
Service-specific repository base class with production utilities
"""

from typing import Optional, List, Dict, Any, Type
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import text, and_, or_
from datetime import datetime, date, timedelta
import structlog

from shared.database.repository import BaseRepository
from shared.database.exceptions import DatabaseError


logger = structlog.get_logger()


class ProductionBaseRepository(BaseRepository):
    """Base repository for production service with common production operations"""
    
    def __init__(self, model: Type, session: AsyncSession, cache_ttl: Optional[int] = 300):
        # Production data is more dynamic, shorter cache time (5 minutes)
        super().__init__(model, session, cache_ttl)
    
    async def get_by_tenant_id(self, tenant_id: str, skip: int = 0, limit: int = 100) -> List:
        """Get records by tenant ID"""
        if hasattr(self.model, 'tenant_id'):
            return await self.get_multi(
                skip=skip,
                limit=limit,
                filters={"tenant_id": tenant_id},
                order_by="created_at",
                order_desc=True
            )
        return await self.get_multi(skip=skip, limit=limit)
    
    async def get_by_status(
        self, 
        tenant_id: str, 
        status: str,
        skip: int = 0,
        limit: int = 100
    ) -> List:
        """Get records by tenant and status"""
        if hasattr(self.model, 'status'):
            return await self.get_multi(
                skip=skip,
                limit=limit,
                filters={
                    "tenant_id": tenant_id,
                    "status": status
                },
                order_by="created_at",
                order_desc=True
            )
        return await self.get_by_tenant_id(tenant_id, skip, limit)
    
    async def get_by_date_range(
        self, 
        tenant_id: str, 
        start_date: date, 
        end_date: date,
        date_field: str = "created_at",
        skip: int = 0,
        limit: int = 100
    ) -> List:
        """Get records by tenant and date range"""
        try:
            start_datetime = datetime.combine(start_date, datetime.min.time())
            end_datetime = datetime.combine(end_date, datetime.max.time())
            
            filters = {
                "tenant_id": tenant_id,
                f"{date_field}__gte": start_datetime,
                f"{date_field}__lte": end_datetime
            }
            
            return await self.get_multi(
                skip=skip,
                limit=limit,
                filters=filters,
                order_by=date_field,
                order_desc=True
            )
        except Exception as e:
            logger.error("Error fetching records by date range", 
                        error=str(e), tenant_id=tenant_id)
            raise DatabaseError(f"Failed to fetch records by date range: {str(e)}")
    
    async def get_active_records(
        self, 
        tenant_id: str,
        active_field: str = "is_active",
        skip: int = 0,
        limit: int = 100
    ) -> List:
        """Get active records for a tenant"""
        if hasattr(self.model, active_field):
            return await self.get_multi(
                skip=skip,
                limit=limit,
                filters={
                    "tenant_id": tenant_id,
                    active_field: True
                },
                order_by="created_at",
                order_desc=True
            )
        return await self.get_by_tenant_id(tenant_id, skip, limit)
    
    def _validate_production_data(
        self, 
        data: Dict[str, Any], 
        required_fields: List[str]
    ) -> Dict[str, Any]:
        """Validate production data with required fields"""
        errors = []
        
        # Check required fields
        for field in required_fields:
            if field not in data or data[field] is None:
                errors.append(f"Missing required field: {field}")
        
        # Validate tenant_id format
        if "tenant_id" in data:
            try:
                import uuid
                uuid.UUID(str(data["tenant_id"]))
            except (ValueError, TypeError):
                errors.append("Invalid tenant_id format")
        
        # Validate datetime fields
        datetime_fields = ["planned_start_time", "planned_end_time", "actual_start_time", "actual_end_time"]
        for field in datetime_fields:
            if field in data and data[field] is not None:
                if not isinstance(data[field], (datetime, str)):
                    errors.append(f"Invalid datetime format for {field}")
        
        # Validate numeric fields
        numeric_fields = ["planned_quantity", "actual_quantity", "quality_score", "yield_percentage"]
        for field in numeric_fields:
            if field in data and data[field] is not None:
                try:
                    float(data[field])
                    if data[field] < 0:
                        errors.append(f"{field} cannot be negative")
                except (ValueError, TypeError):
                    errors.append(f"Invalid numeric value for {field}")
        
        # Validate percentage fields (0-100)
        percentage_fields = ["yield_percentage", "efficiency_percentage", "utilization_percentage"]
        for field in percentage_fields:
            if field in data and data[field] is not None:
                try:
                    value = float(data[field])
                    if value < 0 or value > 100:
                        errors.append(f"{field} must be between 0 and 100")
                except (ValueError, TypeError):
                    pass  # Already caught by numeric validation
        
        return {
            "is_valid": len(errors) == 0,
            "errors": errors
        }
    
    async def get_production_statistics(
        self, 
        tenant_id: str, 
        start_date: date, 
        end_date: date
    ) -> Dict[str, Any]:
        """Get production statistics for a tenant and date range"""
        try:
            # Base query for the model
            start_datetime = datetime.combine(start_date, datetime.min.time())
            end_datetime = datetime.combine(end_date, datetime.max.time())
            
            # This would need to be implemented per specific model
            # For now, return basic count
            records = await self.get_by_date_range(
                tenant_id, start_date, end_date, limit=1000
            )
            
            return {
                "total_records": len(records),
                "period_start": start_date.isoformat(),
                "period_end": end_date.isoformat(),
                "tenant_id": tenant_id
            }
            
        except Exception as e:
            logger.error("Error calculating production statistics", 
                        error=str(e), tenant_id=tenant_id)
            raise DatabaseError(f"Failed to calculate statistics: {str(e)}")
    
    async def check_duplicate(
        self, 
        tenant_id: str, 
        unique_fields: Dict[str, Any]
    ) -> bool:
        """Check if a record with the same unique fields exists"""
        try:
            filters = {"tenant_id": tenant_id}
            filters.update(unique_fields)
            
            existing = await self.get_multi(
                filters=filters,
                limit=1
            )
            
            return len(existing) > 0
            
        except Exception as e:
            logger.error("Error checking for duplicates", 
                        error=str(e), tenant_id=tenant_id)
            return False