# services/production/app/api/equipment.py
"""
Equipment API - CRUD operations on Equipment model
"""

from fastapi import APIRouter, Depends, HTTPException, Path, Query, Request
from typing import Optional
from uuid import UUID
from datetime import datetime, timezone
import structlog

from shared.auth.decorators import get_current_user_dep
from shared.auth.access_control import require_user_role
from shared.routing import RouteBuilder
from shared.security import create_audit_logger, AuditSeverity, AuditAction
from app.core.database import get_db
from app.services.production_service import ProductionService
from app.models import AuditLog
from app.schemas.equipment import (
    EquipmentCreate,
    EquipmentUpdate,
    EquipmentResponse,
    EquipmentListResponse,
    EquipmentDeletionSummary
)
from app.models.production import EquipmentStatus, EquipmentType
from app.core.config import settings

logger = structlog.get_logger()
route_builder = RouteBuilder('production')
router = APIRouter(tags=["production-equipment"])

# Initialize audit logger with the production service's AuditLog model
audit_logger = create_audit_logger("production-service", AuditLog)


def get_production_service(request: Request) -> ProductionService:
    """Dependency injection for production service"""
    from app.core.database import database_manager
    notification_service = getattr(request.app.state, 'notification_service', None)
    return ProductionService(database_manager, settings, notification_service)


@router.get(
    route_builder.build_base_route("equipment"),
    response_model=EquipmentListResponse
)
async def list_equipment(
    tenant_id: UUID = Path(...),
    status: Optional[EquipmentStatus] = Query(None, description="Filter by status"),
    type: Optional[EquipmentType] = Query(None, description="Filter by equipment type"),
    is_active: Optional[bool] = Query(None, description="Filter by active status"),
    page: int = Query(1, ge=1, description="Page number"),
    page_size: int = Query(50, ge=1, le=100, description="Page size"),
    current_user: dict = Depends(get_current_user_dep),
    production_service: ProductionService = Depends(get_production_service)
):
    """List equipment with filters: status, type, active status"""
    try:
        filters = {
            "status": status,
            "type": type,
            "is_active": is_active
        }

        equipment_list = await production_service.get_equipment_list(tenant_id, filters, page, page_size)

        logger.info("Retrieved equipment list",
                   tenant_id=str(tenant_id), filters=filters)

        return equipment_list

    except Exception as e:
        logger.error("Error listing equipment",
                    error=str(e), tenant_id=str(tenant_id))
        raise HTTPException(status_code=500, detail="Failed to list equipment")


@router.post(
    route_builder.build_base_route("equipment"),
    response_model=EquipmentResponse
)
async def create_equipment(
    equipment_data: EquipmentCreate,
    tenant_id: UUID = Path(...),
    current_user: dict = Depends(get_current_user_dep),
    production_service: ProductionService = Depends(get_production_service),
    db = Depends(get_db)
):
    """Create a new equipment item"""
    try:
        equipment = await production_service.create_equipment(tenant_id, equipment_data)

        logger.info("Created equipment",
                   equipment_id=str(equipment.id), tenant_id=str(tenant_id))

        # Audit log the equipment creation
        await audit_logger.log_event(
            db_session=db,
            tenant_id=str(tenant_id),
            user_id=current_user.get('user_id'),
            action=AuditAction.CREATE.value,
            resource_type="equipment",
            resource_id=str(equipment.id),
            severity=AuditSeverity.INFO.value,
            audit_metadata={"equipment_name": equipment.name, "equipment_type": equipment.type.value}
        )

        return EquipmentResponse.model_validate(equipment)

    except ValueError as e:
        logger.warning("Validation error creating equipment",
                      error=str(e), tenant_id=str(tenant_id))
        raise HTTPException(status_code=400, detail=str(e))

    except Exception as e:
        logger.error("Error creating equipment",
                    error=str(e), tenant_id=str(tenant_id))
        raise HTTPException(status_code=500, detail="Failed to create equipment")


@router.get(
    route_builder.build_base_route("equipment/{equipment_id}"),
    response_model=EquipmentResponse
)
async def get_equipment(
    tenant_id: UUID = Path(...),
    equipment_id: UUID = Path(...),
    current_user: dict = Depends(get_current_user_dep),
    production_service: ProductionService = Depends(get_production_service)
):
    """Get a specific equipment item"""
    try:
        equipment = await production_service.get_equipment(tenant_id, equipment_id)

        if not equipment:
            raise HTTPException(status_code=404, detail="Equipment not found")

        logger.info("Retrieved equipment",
                   equipment_id=str(equipment_id), tenant_id=str(tenant_id))

        return EquipmentResponse.model_validate(equipment)

    except HTTPException:
        raise
    except Exception as e:
        logger.error("Error retrieving equipment",
                    error=str(e), equipment_id=str(equipment_id), tenant_id=str(tenant_id))
        raise HTTPException(status_code=500, detail="Failed to retrieve equipment")


@router.put(
    route_builder.build_base_route("equipment/{equipment_id}"),
    response_model=EquipmentResponse
)
async def update_equipment(
    equipment_data: EquipmentUpdate,
    tenant_id: UUID = Path(...),
    equipment_id: UUID = Path(...),
    current_user: dict = Depends(get_current_user_dep),
    production_service: ProductionService = Depends(get_production_service),
    db = Depends(get_db)
):
    """Update an equipment item"""
    try:
        equipment = await production_service.update_equipment(tenant_id, equipment_id, equipment_data)

        if not equipment:
            raise HTTPException(status_code=404, detail="Equipment not found")

        logger.info("Updated equipment",
                   equipment_id=str(equipment_id), tenant_id=str(tenant_id))

        # Audit log the equipment update
        await audit_logger.log_event(
            db_session=db,
            tenant_id=str(tenant_id),
            user_id=current_user.get('user_id'),
            action=AuditAction.UPDATE.value,
            resource_type="equipment",
            resource_id=str(equipment_id),
            severity=AuditSeverity.INFO.value,
            audit_metadata={"updates": equipment_data.model_dump(exclude_unset=True)}
        )

        return EquipmentResponse.model_validate(equipment)

    except HTTPException:
        raise
    except ValueError as e:
        logger.warning("Validation error updating equipment",
                      error=str(e), equipment_id=str(equipment_id), tenant_id=str(tenant_id))
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        logger.error("Error updating equipment",
                    error=str(e), equipment_id=str(equipment_id), tenant_id=str(tenant_id))
        raise HTTPException(status_code=500, detail="Failed to update equipment")


@router.get(
    route_builder.build_base_route("equipment/{equipment_id}/deletion-summary"),
    response_model=EquipmentDeletionSummary
)
async def get_equipment_deletion_summary(
    tenant_id: UUID = Path(...),
    equipment_id: UUID = Path(...),
    current_user: dict = Depends(get_current_user_dep),
    production_service: ProductionService = Depends(get_production_service)
):
    """Get deletion summary for equipment (dependency check)"""
    try:
        summary = await production_service.get_equipment_deletion_summary(tenant_id, equipment_id)

        logger.info("Retrieved equipment deletion summary",
                   equipment_id=str(equipment_id), tenant_id=str(tenant_id))

        return EquipmentDeletionSummary(**summary)

    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 HTTPException(status_code=500, detail="Failed to get deletion summary")


@router.post(
    route_builder.build_base_route("equipment/{equipment_id}/report-failure"),
    response_model=EquipmentResponse
)
async def report_equipment_failure(
    failure_data: dict,
    request: Request,
    tenant_id: UUID = Path(...),
    equipment_id: UUID = Path(...),
    current_user: dict = Depends(get_current_user_dep),
    production_service: ProductionService = Depends(get_production_service),
    db = Depends(get_db)
):
    """Report equipment failure and trigger maintenance workflow"""
    try:
        # Update equipment status and add failure record
        equipment = await production_service.report_equipment_failure(
            tenant_id, 
            equipment_id, 
            failure_data
        )

        if not equipment:
            raise HTTPException(status_code=404, detail="Equipment not found")

        logger.info("Reported equipment failure",
                   equipment_id=str(equipment_id), 
                   tenant_id=str(tenant_id),
                   failure_type=failure_data.get('failureType'))

        # Audit log the failure report
        await audit_logger.log_event(
            db_session=db,
            tenant_id=str(tenant_id),
            user_id=current_user.get('user_id'),
            action=AuditAction.UPDATE.value,
            resource_type="equipment",
            resource_id=str(equipment_id),
            severity=AuditSeverity.WARNING.value,
            audit_metadata={
                "action": "report_failure",
                "failure_type": failure_data.get('failureType'),
                "severity": failure_data.get('severity')
            }
        )

        # Get notification service from app state
        notification_service = getattr(request.app.state, 'notification_service', None)

        # Trigger notifications if notification service is available
        if notification_service:
            try:
                await trigger_failure_notifications(
                    notification_service,
                    tenant_id,
                    equipment,
                    failure_data
                )

                # Send primary notification to equipment support contact if available
                if equipment.support_contact and equipment.support_contact.get('email'):
                    await send_support_contact_notification(
                        notification_service,
                        tenant_id,
                        equipment,
                        failure_data,
                        equipment.support_contact['email']
                    )
            except Exception as e:
                logger.warning("Failed to send notifications", error=str(e), equipment_id=str(equipment_id))
                # Continue even if notifications fail

        return EquipmentResponse.model_validate(equipment)

    except HTTPException:
        raise
    except Exception as e:
        logger.error("Error reporting equipment failure",
                    error=str(e), equipment_id=str(equipment_id), tenant_id=str(tenant_id))
        raise HTTPException(status_code=500, detail="Failed to report equipment failure")


@router.post(
    route_builder.build_base_route("equipment/{equipment_id}/mark-repaired"),
    response_model=EquipmentResponse
)
async def mark_equipment_repaired(
    repair_data: dict,
    request: Request,
    tenant_id: UUID = Path(...),
    equipment_id: UUID = Path(...),
    current_user: dict = Depends(get_current_user_dep),
    production_service: ProductionService = Depends(get_production_service),
    db = Depends(get_db)
):
    """Mark equipment as repaired and update maintenance records"""
    try:
        # Update equipment status and add repair record
        equipment = await production_service.mark_equipment_repaired(
            tenant_id, 
            equipment_id, 
            repair_data
        )

        if not equipment:
            raise HTTPException(status_code=404, detail="Equipment not found")

        logger.info("Marked equipment as repaired",
                   equipment_id=str(equipment_id), 
                   tenant_id=str(tenant_id))

        # Audit log the repair completion
        await audit_logger.log_event(
            db_session=db,
            tenant_id=str(tenant_id),
            user_id=current_user.get('user_id'),
            action=AuditAction.UPDATE.value,
            resource_type="equipment",
            resource_id=str(equipment_id),
            severity=AuditSeverity.INFO.value,
            audit_metadata={
                "action": "mark_repaired",
                "technician": repair_data.get('technicianName'),
                "cost": repair_data.get('cost')
            }
        )

        # Get notification service from app state
        notification_service = getattr(request.app.state, 'notification_service', None)

        # Trigger notifications if notification service is available
        if notification_service:
            try:
                # Calculate downtime for notifications
                last_maintenance_date = equipment.last_maintenance_date or datetime.now(timezone.utc)
                repair_date_str = repair_data.get('repairDate')
                if repair_date_str:
                    if 'T' in repair_date_str:
                        repair_date = datetime.fromisoformat(repair_date_str.replace('Z', '+00:00'))
                    else:
                        repair_date = datetime.fromisoformat(f"{repair_date_str}T00:00:00+00:00")
                else:
                    repair_date = datetime.now(timezone.utc)

                downtime_hours = int((repair_date - last_maintenance_date).total_seconds() / 3600)

                # Add downtime to repair_data for notification
                repair_data_with_downtime = {**repair_data, 'downtime': downtime_hours}

                await trigger_repair_notifications(
                    notification_service,
                    tenant_id,
                    equipment,
                    repair_data_with_downtime
                )
            except Exception as e:
                logger.warning("Failed to send notifications", error=str(e), equipment_id=str(equipment_id))
                # Continue even if notifications fail

        return EquipmentResponse.model_validate(equipment)

    except HTTPException:
        raise
    except Exception as e:
        logger.error("Error marking equipment as repaired",
                    error=str(e), equipment_id=str(equipment_id), tenant_id=str(tenant_id))
        raise HTTPException(status_code=500, detail="Failed to mark equipment as repaired")


@router.delete(
    route_builder.build_base_route("equipment/{equipment_id}")
)
async def delete_equipment(
    tenant_id: UUID = Path(...),
    equipment_id: UUID = Path(...),
    permanent: bool = Query(False, description="Permanent delete (hard delete) if true"),
    current_user: dict = Depends(get_current_user_dep),
    production_service: ProductionService = Depends(get_production_service),
    db = Depends(get_db)
):
    """Delete an equipment item. Use permanent=true for hard delete (requires admin role)"""
    try:
        # Hard delete requires admin role
        if permanent:
            user_role = current_user.get('role', '').lower()
            if user_role not in ['admin', 'owner']:
                raise HTTPException(
                    status_code=403,
                    detail="Hard delete requires admin or owner role"
                )

            success = await production_service.hard_delete_equipment(tenant_id, equipment_id)
            delete_type = "hard_delete"
            severity = AuditSeverity.CRITICAL.value
        else:
            success = await production_service.delete_equipment(tenant_id, equipment_id)
            delete_type = "soft_delete"
            severity = AuditSeverity.WARNING.value

        if not success:
            raise HTTPException(status_code=404, detail="Equipment not found")

        logger.info(f"{'Hard' if permanent else 'Soft'} deleted equipment",
                   equipment_id=str(equipment_id), tenant_id=str(tenant_id))

        # Audit log the equipment deletion
        await audit_logger.log_event(
            db_session=db,
            tenant_id=str(tenant_id),
            user_id=current_user.get('user_id'),
            action=AuditAction.DELETE.value,
            resource_type="equipment",
            resource_id=str(equipment_id),
            severity=severity,
            audit_metadata={"action": delete_type, "permanent": permanent}
        )

        return {"message": f"Equipment {'permanently deleted' if permanent else 'deleted'} successfully"}

    except HTTPException:
        raise
    except Exception as e:
        logger.error("Error deleting equipment",
                    error=str(e), equipment_id=str(equipment_id), tenant_id=str(tenant_id))
        raise HTTPException(status_code=500, detail="Failed to delete equipment")


# Helper functions for notifications
async def trigger_failure_notifications(notification_service: any, tenant_id: UUID, equipment: any, failure_data: dict):
    """Trigger failure notifications via email - sends to bakery managers"""
    try:
        from jinja2 import Environment, FileSystemLoader
        from pathlib import Path

        # Load template from file
        template_dir = Path(__file__).parent.parent.parent / "notification" / "app" / "templates"
        env = Environment(loader=FileSystemLoader(str(template_dir)))
        template = env.get_template('equipment_failure_email.html')

        # Prepare template variables
        template_vars = {
            "equipment_name": equipment.name,
            "equipment_type": equipment.type.value if hasattr(equipment.type, 'value') else equipment.type,
            "equipment_model": equipment.model or "N/A",
            "equipment_serial_number": equipment.serial_number or "N/A",
            "equipment_location": equipment.location or "N/A",
            "failure_type": failure_data.get('failureType', 'Unknown'),
            "severity": failure_data.get('severity', 'high'),
            "description": failure_data.get('description', ''),
            "reported_time": datetime.now(timezone.utc).strftime('%Y-%m-%d %H:%M:%S UTC'),
            "estimated_impact": "SÍ - Afecta producción" if failure_data.get('estimatedImpact') else "NO - Sin impacto en producción",
            "support_contact": equipment.support_contact or {},
            "equipment_link": f"https://app.bakeryia.com/equipment/{equipment.id}",
            "bakery_name": "BakeryIA",
            "current_year": datetime.now().year
        }

        html_content = template.render(**template_vars)
        text_content = f"Equipment failure alert: {equipment.name} - {failure_data.get('failureType', 'Unknown')}"

        # Send via notification service API
        if notification_service:
            result = await notification_service.send_email(
                tenant_id=str(tenant_id),
                to_email="managers@bakeryia.com",  # Should be configured from DB in production
                subject=f"🚨 Fallo de Equipo: {equipment.name}",
                message=text_content,
                html_content=html_content,
                priority="high"
            )
            
            if result:
                logger.info("Failure notifications sent via notification service",
                           equipment_id=str(equipment.id),
                           tenant_id=str(tenant_id),
                           notification_id=result.get('notification_id'))
            else:
                logger.error("Failed to send failure notifications via notification service",
                           equipment_id=str(equipment.id),
                           tenant_id=str(tenant_id))
        else:
            logger.warning("Notification service not available, failure notifications not sent",
                          equipment_id=str(equipment.id),
                          tenant_id=str(tenant_id))

    except Exception as e:
        logger.error("Error triggering failure notifications",
                    error=str(e), equipment_id=str(equipment.id), tenant_id=str(tenant_id))
        raise


async def trigger_repair_notifications(notification_service: any, tenant_id: UUID, equipment: any, repair_data: dict):
    """Trigger repair completion notifications via email - sends to bakery managers"""
    try:
        from jinja2 import Environment, FileSystemLoader
        from pathlib import Path

        # Load template from file
        template_dir = Path(__file__).parent.parent.parent / "notification" / "app" / "templates"
        env = Environment(loader=FileSystemLoader(str(template_dir)))
        template = env.get_template('equipment_repaired_email.html')

        # Prepare template variables
        template_vars = {
            "equipment_name": equipment.name,
            "equipment_type": equipment.type.value if hasattr(equipment.type, 'value') else equipment.type,
            "equipment_model": equipment.model or "N/A",
            "equipment_location": equipment.location or "N/A",
            "repair_date": repair_data.get('repairDate', datetime.now(timezone.utc).strftime('%Y-%m-%d')),
            "technician_name": repair_data.get('technicianName', 'Unknown'),
            "repair_description": repair_data.get('repairDescription', ''),
            "parts_replaced": repair_data.get('partsReplaced', []),
            "cost": repair_data.get('cost', 0),
            "downtime_hours": repair_data.get('downtime', 0),
            "test_results": repair_data.get('testResults', False),
            "equipment_link": f"https://app.bakeryia.com/equipment/{equipment.id}",
            "bakery_name": "BakeryIA",
            "current_year": datetime.now().year
        }

        html_content = template.render(**template_vars)
        text_content = f"Equipment repair completed: {equipment.name} - {repair_data.get('repairDescription', 'Repair completed')}"

        # Send via notification service API
        if notification_service:
            result = await notification_service.send_email(
                tenant_id=str(tenant_id),
                to_email="managers@bakeryia.com",  # Should be configured from DB in production
                subject=f"✅ Equipo Reparado: {equipment.name}",
                message=text_content,
                html_content=html_content,
                priority="normal"
            )
            
            if result:
                logger.info("Repair notifications sent via notification service",
                           equipment_id=str(equipment.id),
                           tenant_id=str(tenant_id),
                           notification_id=result.get('notification_id'))
            else:
                logger.error("Failed to send repair notifications via notification service",
                           equipment_id=str(equipment.id),
                           tenant_id=str(tenant_id))
        else:
            logger.warning("Notification service not available, repair notifications not sent",
                          equipment_id=str(equipment.id),
                          tenant_id=str(tenant_id))

    except Exception as e:
        logger.error("Error triggering repair notifications",
                    error=str(e), equipment_id=str(equipment.id), tenant_id=str(tenant_id))
        raise


async def send_support_contact_notification(notification_service: any, tenant_id: UUID, equipment: any, failure_data: dict, support_email: str):
    """Send direct notification to equipment support contact for repair request"""
    try:
        from jinja2 import Environment, FileSystemLoader
        from pathlib import Path

        # Load template from file
        template_dir = Path(__file__).parent.parent.parent / "notification" / "app" / "templates"
        env = Environment(loader=FileSystemLoader(str(template_dir)))
        template = env.get_template('equipment_failure_email.html')

        # Prepare template variables
        template_vars = {
            "equipment_name": equipment.name,
            "equipment_type": equipment.type.value if hasattr(equipment.type, 'value') else equipment.type,
            "equipment_model": equipment.model or "N/A",
            "equipment_serial_number": equipment.serial_number or "N/A",
            "equipment_location": equipment.location or "N/A",
            "failure_type": failure_data.get('failureType', 'Unknown'),
            "severity": failure_data.get('severity', 'high'),
            "description": failure_data.get('description', ''),
            "reported_time": datetime.now(timezone.utc).strftime('%Y-%m-%d %H:%M:%S UTC'),
            "estimated_impact": "SÍ - Afecta producción" if failure_data.get('estimatedImpact') else "NO - Sin impacto en producción",
            "support_contact": equipment.support_contact or {},
            "equipment_link": f"https://app.bakeryia.com/equipment/{equipment.id}",
            "bakery_name": "BakeryIA",
            "current_year": datetime.now().year
        }

        html_content = template.render(**template_vars)
        text_content = f"Equipment failure alert: {equipment.name} - {failure_data.get('failureType', 'Unknown')}"

        # Send via notification service API
        if notification_service and support_email:
            result = await notification_service.send_email(
                tenant_id=str(tenant_id),
                to_email=support_email,
                subject=f"🚨 URGENTE: Fallo de Equipo - {equipment.name}",
                message=text_content,
                html_content=html_content,
                priority="high"
            )
            
            if result:
                logger.info("Support contact notification sent via notification service",
                           equipment_id=str(equipment.id),
                           tenant_id=str(tenant_id),
                           support_email=support_email,
                           notification_id=result.get('notification_id'))
            else:
                logger.error("Failed to send support contact notification via notification service",
                           equipment_id=str(equipment.id),
                           tenant_id=str(tenant_id),
                           support_email=support_email)
        else:
            logger.warning("Notification service not available or no support email provided",
                          equipment_id=str(equipment.id),
                          tenant_id=str(tenant_id),
                          support_email=support_email)

    except Exception as e:
        logger.error("Error sending support contact notification",
                    error=str(e), equipment_id=str(equipment.id), tenant_id=str(tenant_id))
        raise
