"""
Equipment Repository
"""

from typing import Optional, List, Dict, Any
from sqlalchemy import select, func, and_, text
from sqlalchemy.ext.asyncio import AsyncSession
from uuid import UUID
import structlog

from app.repositories.base import ProductionBaseRepository
from app.models.production import Equipment, EquipmentStatus, EquipmentType

logger = structlog.get_logger()


class EquipmentRepository(ProductionBaseRepository):
    """Repository for equipment operations"""

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

    async def get_equipment_filtered(
        self,
        filters: Dict[str, Any],
        page: int = 1,
        page_size: int = 50
    ) -> List[Equipment]:
        """Get equipment list with filters and pagination"""
        try:
            # Build base query
            query = select(Equipment).filter(Equipment.tenant_id == UUID(filters.get("tenant_id")))

            # Apply status filter
            if "status" in filters and filters["status"]:
                query = query.filter(Equipment.status == filters["status"])

            # Apply type filter
            if "type" in filters and filters["type"]:
                query = query.filter(Equipment.type == filters["type"])

            # Apply active filter
            if "is_active" in filters and filters["is_active"] is not None:
                query = query.filter(Equipment.is_active == filters["is_active"])

            # Apply pagination
            query = query.order_by(Equipment.created_at.desc())
            query = query.offset((page - 1) * page_size).limit(page_size)

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

        except Exception as e:
            logger.error("Error getting filtered equipment", error=str(e), filters=filters)
            raise

    async def count_equipment_filtered(self, filters: Dict[str, Any]) -> int:
        """Count equipment matching filters"""
        try:
            # Build base query
            query = select(func.count(Equipment.id)).filter(
                Equipment.tenant_id == UUID(filters.get("tenant_id"))
            )

            # Apply status filter
            if "status" in filters and filters["status"]:
                query = query.filter(Equipment.status == filters["status"])

            # Apply type filter
            if "type" in filters and filters["type"]:
                query = query.filter(Equipment.type == filters["type"])

            # Apply active filter
            if "is_active" in filters and filters["is_active"] is not None:
                query = query.filter(Equipment.is_active == filters["is_active"])

            result = await self.session.execute(query)
            return result.scalar() or 0

        except Exception as e:
            logger.error("Error counting filtered equipment", error=str(e), filters=filters)
            raise

    async def get_equipment_by_id(self, tenant_id: UUID, equipment_id: UUID) -> Optional[Equipment]:
        """Get equipment by ID and tenant"""
        try:
            query = select(Equipment).filter(
                and_(
                    Equipment.id == equipment_id,
                    Equipment.tenant_id == tenant_id
                )
            )
            result = await self.session.execute(query)
            return result.scalar_one_or_none()

        except Exception as e:
            logger.error("Error getting equipment by ID",
                        error=str(e),
                        equipment_id=str(equipment_id),
                        tenant_id=str(tenant_id))
            raise

    async def create_equipment(self, equipment_data: Dict[str, Any]) -> Equipment:
        """Create new equipment"""
        try:
            equipment = Equipment(**equipment_data)
            self.session.add(equipment)
            await self.session.flush()
            await self.session.refresh(equipment)
            return equipment

        except Exception as e:
            logger.error("Error creating equipment", error=str(e), data=equipment_data)
            raise

    async def update_equipment(
        self,
        equipment_id: UUID,
        updates: Dict[str, Any]
    ) -> Optional[Equipment]:
        """Update equipment"""
        try:
            equipment = await self.get(equipment_id)
            if not equipment:
                return None

            for key, value in updates.items():
                if hasattr(equipment, key) and value is not None:
                    setattr(equipment, key, value)

            await self.session.flush()
            await self.session.refresh(equipment)
            return equipment

        except Exception as e:
            logger.error("Error updating equipment", error=str(e), equipment_id=str(equipment_id))
            raise

    async def delete_equipment(self, equipment_id: UUID) -> bool:
        """Soft delete equipment (set is_active to False)"""
        try:
            equipment = await self.get(equipment_id)
            if not equipment:
                return False

            equipment.is_active = False
            await self.session.flush()
            return True

        except Exception as e:
            logger.error("Error deleting equipment", error=str(e), equipment_id=str(equipment_id))
            raise

    async def hard_delete_equipment(self, equipment_id: UUID) -> bool:
        """Permanently delete equipment from database"""
        try:
            equipment = await self.get(equipment_id)
            if not equipment:
                return False

            await self.session.delete(equipment)
            await self.session.flush()
            return True

        except Exception as e:
            logger.error("Error hard deleting equipment", error=str(e), equipment_id=str(equipment_id))
            raise

    async def get_equipment_deletion_summary(self, tenant_id: UUID, equipment_id: UUID) -> Dict[str, Any]:
        """Get summary of what will be affected by deleting equipment"""
        try:
            equipment = await self.get_equipment_by_id(tenant_id, equipment_id)
            if not equipment:
                return {
                    "can_delete": False,
                    "warnings": ["Equipment not found"],
                    "production_batches_count": 0,
                    "maintenance_records_count": 0,
                    "temperature_logs_count": 0
                }

            # Check for related production batches
            from app.models.production import ProductionBatch
            batch_query = select(func.count(ProductionBatch.id)).filter(
                and_(
                    ProductionBatch.tenant_id == tenant_id,
                    ProductionBatch.equipment_id == equipment_id
                )
            )
            batch_result = await self.session.execute(batch_query)
            batches_count = batch_result.scalar() or 0

            # For now, we'll use placeholder counts for maintenance and temperature logs
            # These would need to be implemented based on your actual models
            maintenance_count = 0
            temperature_logs_count = 0

            warnings = []
            if batches_count > 0:
                warnings.append(f"{batches_count} production batch(es) are using this equipment")

            # Equipment can be deleted even with dependencies, but warn the user
            can_delete = True

            return {
                "can_delete": can_delete,
                "warnings": warnings,
                "production_batches_count": batches_count,
                "maintenance_records_count": maintenance_count,
                "temperature_logs_count": temperature_logs_count,
                "equipment_name": equipment.name,
                "equipment_type": equipment.type.value,
                "equipment_location": equipment.location
            }

        except Exception as e:
            logger.error("Error getting equipment deletion summary",
                        error=str(e),
                        equipment_id=str(equipment_id),
                        tenant_id=str(tenant_id))
            raise

    # ================================================================
    # ALERT-RELATED METHODS (migrated from production_alert_repository)
    # ================================================================

    async def get_equipment_status(self, tenant_id: UUID) -> List[Dict[str, Any]]:
        """
        Get equipment requiring attention.
        Returns equipment with maintenance due or status issues.
        """
        try:

            query = text("""
                SELECT
                    e.id, e.tenant_id, e.name, e.type, e.status,
                    e.efficiency_percentage, e.uptime_percentage,
                    e.last_maintenance_date, e.next_maintenance_date,
                    e.maintenance_interval_days,
                    EXTRACT(DAYS FROM (e.next_maintenance_date - NOW())) as days_to_maintenance,
                    COUNT(ea.id) as active_alerts
                FROM equipment e
                LEFT JOIN alerts ea ON ea.equipment_id = e.id
                    AND ea.is_active = true
                    AND ea.is_resolved = false
                WHERE e.is_active = true
                AND e.tenant_id = :tenant_id
                GROUP BY e.id, e.tenant_id, e.name, e.type, e.status,
                         e.efficiency_percentage, e.uptime_percentage,
                         e.last_maintenance_date, e.next_maintenance_date,
                         e.maintenance_interval_days
                ORDER BY e.next_maintenance_date ASC
            """)

            result = await self.session.execute(query, {"tenant_id": tenant_id})
            return [dict(row._mapping) for row in result.fetchall()]

        except Exception as e:
            logger.error("Failed to get equipment status", error=str(e), tenant_id=str(tenant_id))
            raise

    async def get_equipment_needing_maintenance(self, tenant_id: Optional[UUID] = None) -> List[Dict[str, Any]]:
        """
        Get equipment that needs maintenance.
        Returns equipment where next_maintenance_date has passed.

        Args:
            tenant_id: Optional tenant ID to filter by
        """
        try:

            query_str = """
                SELECT
                    e.id, e.name, e.type, e.tenant_id,
                    e.last_maintenance_date,
                    e.next_maintenance_date,
                    EXTRACT(DAY FROM (NOW() - e.next_maintenance_date)) as days_overdue
                FROM equipment e
                WHERE e.next_maintenance_date IS NOT NULL
                AND e.next_maintenance_date < NOW()
                AND e.status = 'OPERATIONAL'
                AND e.is_active = true
            """

            params = {}
            if tenant_id:
                query_str += " AND e.tenant_id = :tenant_id"
                params["tenant_id"] = tenant_id

            query_str += " ORDER BY e.next_maintenance_date ASC LIMIT 50"

            result = await self.session.execute(text(query_str), params)
            rows = result.fetchall()

            return [
                {
                    'id': str(row.id),
                    'name': row.name,
                    'type': row.type,
                    'tenant_id': str(row.tenant_id),
                    'last_maintenance_date': row.last_maintenance_date.isoformat() if row.last_maintenance_date else None,
                    'next_maintenance_date': row.next_maintenance_date.isoformat() if row.next_maintenance_date else None,
                    'days_overdue': int(row.days_overdue) if row.days_overdue else 0
                }
                for row in rows
            ]

        except Exception as e:
            logger.error("Failed to get equipment needing maintenance", error=str(e))
            raise

    async def get_efficiency_recommendations(self, tenant_id: UUID) -> List[Dict[str, Any]]:
        """
        Get production efficiency improvement recommendations.
        Analyzes production patterns to identify optimization opportunities.
        """
        try:

            query = text("""
                WITH efficiency_analysis AS (
                    SELECT
                        pb.tenant_id, pb.product_name,
                        AVG(EXTRACT(EPOCH FROM (pb.actual_end_time - pb.actual_start_time)) / 60) as avg_production_time,
                        AVG(pb.planned_duration_minutes) as avg_planned_duration,
                        COUNT(*) as batch_count,
                        AVG(pb.yield_percentage) as avg_yield,
                        EXTRACT(hour FROM pb.actual_start_time) as start_hour
                    FROM production_batches pb
                    WHERE pb.status = 'COMPLETED'
                    AND pb.actual_completion_time > CURRENT_DATE - INTERVAL '30 days'
                    AND pb.tenant_id = :tenant_id
                    GROUP BY pb.tenant_id, pb.product_name, EXTRACT(hour FROM pb.actual_start_time)
                    HAVING COUNT(*) >= 3
                ),
                recommendations AS (
                    SELECT *,
                        CASE
                            WHEN avg_production_time > avg_planned_duration * 1.2 THEN 'reduce_production_time'
                            WHEN avg_yield < 85 THEN 'improve_yield'
                            WHEN start_hour BETWEEN 14 AND 16 AND avg_production_time > avg_planned_duration * 1.1 THEN 'avoid_afternoon_production'
                            ELSE null
                        END as recommendation_type,
                        (avg_production_time - avg_planned_duration) / avg_planned_duration * 100 as efficiency_loss_percent
                    FROM efficiency_analysis
                )
                SELECT * FROM recommendations
                WHERE recommendation_type IS NOT NULL
                AND efficiency_loss_percent > 10
                ORDER BY efficiency_loss_percent DESC
            """)

            result = await self.session.execute(query, {"tenant_id": tenant_id})
            return [dict(row._mapping) for row in result.fetchall()]

        except Exception as e:
            logger.error("Failed to get efficiency recommendations", error=str(e), tenant_id=str(tenant_id))
            raise

    async def get_energy_consumption_patterns(self, tenant_id: UUID) -> List[Dict[str, Any]]:
        """
        Get energy consumption patterns for optimization analysis.
        Returns consumption by equipment and hour of day.
        """
        try:

            query = text("""
                SELECT
                    e.tenant_id, e.name as equipment_name, e.type,
                    AVG(ec.energy_consumption_kwh) as avg_energy,
                    EXTRACT(hour FROM ec.recorded_at) as hour_of_day,
                    COUNT(*) as readings_count
                FROM equipment e
                JOIN energy_consumption ec ON ec.equipment_id = e.id
                WHERE ec.recorded_at > CURRENT_DATE - INTERVAL '30 days'
                AND e.tenant_id = :tenant_id
                GROUP BY e.tenant_id, e.id, e.name, e.type, EXTRACT(hour FROM ec.recorded_at)
                HAVING COUNT(*) >= 10
                ORDER BY avg_energy DESC
            """)

            result = await self.session.execute(query, {"tenant_id": tenant_id})
            return [dict(row._mapping) for row in result.fetchall()]

        except Exception as e:
            logger.error("Failed to get energy consumption patterns", error=str(e), tenant_id=str(tenant_id))
            raise
