# services/production/app/api/production_schedules.py
"""
Production Schedules API - ATOMIC CRUD operations on ProductionSchedule model
"""

from fastapi import APIRouter, Depends, HTTPException, Path, Query, Request
from typing import Optional
from datetime import date, datetime, timedelta
from uuid import UUID
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.production import (
    ProductionScheduleCreate,
    ProductionScheduleUpdate,
    ProductionScheduleResponse
)
from app.core.config import settings

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

# 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("schedules"),
    response_model=dict
)
async def get_production_schedule(
    tenant_id: UUID = Path(...),
    start_date: Optional[date] = Query(None, description="Start date for schedule"),
    end_date: Optional[date] = Query(None, description="End date for schedule"),
    current_user: dict = Depends(get_current_user_dep),
    db=Depends(get_db)
):
    """Get production schedule for a date range"""
    try:
        # Default to next 7 days if no dates provided
        if not start_date:
            start_date = datetime.now().date()
        if not end_date:
            end_date = start_date + timedelta(days=7)

        from app.repositories.production_schedule_repository import ProductionScheduleRepository
        schedule_repo = ProductionScheduleRepository(db)

        schedules = await schedule_repo.get_schedules_by_date_range(
            str(tenant_id), start_date, end_date
        )

        schedule_data = {
            "start_date": start_date.isoformat(),
            "end_date": end_date.isoformat(),
            "schedules": [
                {
                    "id": str(schedule.id),
                    "date": schedule.schedule_date.isoformat(),
                    "shift_start": schedule.shift_start.isoformat(),
                    "shift_end": schedule.shift_end.isoformat(),
                    "capacity_utilization": schedule.utilization_percentage,
                    "batches_planned": schedule.total_batches_planned,
                    "is_finalized": schedule.is_finalized
                }
                for schedule in schedules
            ],
            "total_schedules": len(schedules)
        }

        logger.info("Retrieved production schedule",
                   tenant_id=str(tenant_id),
                   start_date=start_date.isoformat(),
                   end_date=end_date.isoformat(),
                   schedules_count=len(schedules))

        return schedule_data

    except Exception as e:
        logger.error("Error getting production schedule",
                    error=str(e), tenant_id=str(tenant_id))
        raise HTTPException(status_code=500, detail="Failed to get production schedule")


@router.get(
    route_builder.build_resource_detail_route("schedules", "schedule_id"),
    response_model=ProductionScheduleResponse
)
async def get_production_schedule_details(
    tenant_id: UUID = Path(...),
    schedule_id: UUID = Path(...),
    current_user: dict = Depends(get_current_user_dep),
    db=Depends(get_db)
):
    """Retrieve full schedule details including assignments"""
    try:
        from app.repositories.production_schedule_repository import ProductionScheduleRepository
        schedule_repo = ProductionScheduleRepository(db)

        schedule = await schedule_repo.get(schedule_id)
        if not schedule or str(schedule.tenant_id) != str(tenant_id):
            raise HTTPException(status_code=404, detail="Production schedule not found")

        logger.info("Retrieved production schedule details",
                   schedule_id=str(schedule_id), tenant_id=str(tenant_id))

        return ProductionScheduleResponse.model_validate(schedule)

    except HTTPException:
        raise
    except Exception as e:
        logger.error("Error getting production schedule details",
                    error=str(e), schedule_id=str(schedule_id), tenant_id=str(tenant_id))
        raise HTTPException(status_code=500, detail="Failed to get production schedule details")


@router.post(
    route_builder.build_base_route("schedules"),
    response_model=ProductionScheduleResponse
)
@require_user_role(['admin', 'owner'])
async def create_production_schedule(
    schedule_data: ProductionScheduleCreate,
    tenant_id: UUID = Path(...),
    current_user: dict = Depends(get_current_user_dep),
    production_service: ProductionService = Depends(get_production_service)
):
    """Generate or manually create a daily/shift schedule (Admin+ only)"""
    try:
        schedule = await production_service.create_production_schedule(tenant_id, schedule_data)

        logger.info("Created production schedule",
                   schedule_id=str(schedule.id), tenant_id=str(tenant_id))

        return ProductionScheduleResponse.model_validate(schedule)

    except ValueError as e:
        logger.warning("Invalid schedule data", error=str(e), tenant_id=str(tenant_id))
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        logger.error("Error creating production schedule",
                    error=str(e), tenant_id=str(tenant_id))
        raise HTTPException(status_code=500, detail="Failed to create production schedule")


@router.put(
    route_builder.build_resource_detail_route("schedules", "schedule_id"),
    response_model=ProductionScheduleResponse
)
@require_user_role(['admin', 'owner'])
async def update_production_schedule(
    schedule_update: ProductionScheduleUpdate,
    tenant_id: UUID = Path(...),
    schedule_id: UUID = Path(...),
    current_user: dict = Depends(get_current_user_dep),
    production_service: ProductionService = Depends(get_production_service)
):
    """Edit schedule before finalizing (Admin+ only)"""
    try:
        schedule = await production_service.update_production_schedule(tenant_id, schedule_id, schedule_update)

        logger.info("Updated production schedule",
                   schedule_id=str(schedule_id), tenant_id=str(tenant_id))

        return ProductionScheduleResponse.model_validate(schedule)

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


@router.delete(
    route_builder.build_resource_detail_route("schedules", "schedule_id")
)
async def delete_production_schedule(
    tenant_id: UUID = Path(...),
    schedule_id: UUID = Path(...),
    current_user: dict = Depends(get_current_user_dep),
    db=Depends(get_db)
):
    """Delete a production schedule (if not finalized)"""
    try:
        from app.repositories.production_schedule_repository import ProductionScheduleRepository
        schedule_repo = ProductionScheduleRepository(db)

        schedule = await schedule_repo.get(schedule_id)
        if not schedule or str(schedule.tenant_id) != str(tenant_id):
            raise HTTPException(status_code=404, detail="Production schedule not found")

        if schedule.is_finalized:
            raise HTTPException(status_code=400, detail="Cannot delete finalized schedule")

        await schedule_repo.delete(schedule_id)

        logger.info("Deleted production schedule",
                   schedule_id=str(schedule_id), tenant_id=str(tenant_id))

        return {"message": "Production schedule deleted successfully"}

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