"""
Scheduler Router

Handles scheduled actions for automated recording control.
"""

from fastapi import APIRouter, Request, Depends, HTTPException, Query
from fastapi.responses import HTMLResponse, JSONResponse
from sqlalchemy.orm import Session
from sqlalchemy import and_, or_
from datetime import datetime, timedelta
from typing import Optional
import uuid
import json

from backend.database import get_db
from backend.models import (
    Project,
    ScheduledAction,
    MonitoringLocation,
    UnitAssignment,
    RosterUnit,
)
from backend.services.scheduler import get_scheduler
from backend.templates_config import templates

router = APIRouter(prefix="/api/projects/{project_id}/scheduler", tags=["scheduler"])


# ============================================================================
# Scheduled Actions List
# ============================================================================

@router.get("/actions", response_class=HTMLResponse)
async def get_scheduled_actions(
    project_id: str,
    request: Request,
    db: Session = Depends(get_db),
    status: Optional[str] = Query(None),
    start_date: Optional[str] = Query(None),
    end_date: Optional[str] = Query(None),
):
    """
    Get scheduled actions for a project.
    Returns HTML partial with agenda/calendar view.
    """
    query = db.query(ScheduledAction).filter_by(project_id=project_id)

    # Filter by status
    if status:
        query = query.filter_by(execution_status=status)
    else:
        # By default, show pending and upcoming completed/failed
        query = query.filter(
            or_(
                ScheduledAction.execution_status == "pending",
                and_(
                    ScheduledAction.execution_status.in_(["completed", "failed"]),
                    ScheduledAction.scheduled_time >= datetime.utcnow() - timedelta(days=7),
                ),
            )
        )

    # Filter by date range
    if start_date:
        query = query.filter(ScheduledAction.scheduled_time >= datetime.fromisoformat(start_date))
    if end_date:
        query = query.filter(ScheduledAction.scheduled_time <= datetime.fromisoformat(end_date))

    actions = query.order_by(ScheduledAction.scheduled_time).all()

    # Enrich with location and unit details
    actions_data = []
    for action in actions:
        location = db.query(MonitoringLocation).filter_by(id=action.location_id).first()

        unit = None
        if action.unit_id:
            unit = db.query(RosterUnit).filter_by(id=action.unit_id).first()
        else:
            # Get from assignment
            assignment = db.query(UnitAssignment).filter(
                and_(
                    UnitAssignment.location_id == action.location_id,
                    UnitAssignment.status == "active",
                )
            ).first()
            if assignment:
                unit = db.query(RosterUnit).filter_by(id=assignment.unit_id).first()

        actions_data.append({
            "action": action,
            "location": location,
            "unit": unit,
        })

    return templates.TemplateResponse("partials/projects/scheduler_agenda.html", {
        "request": request,
        "project_id": project_id,
        "actions": actions_data,
    })


# ============================================================================
# Create Scheduled Action
# ============================================================================

@router.post("/actions/create")
async def create_scheduled_action(
    project_id: str,
    request: Request,
    db: Session = Depends(get_db),
):
    """
    Create a new scheduled action.
    """
    project = db.query(Project).filter_by(id=project_id).first()
    if not project:
        raise HTTPException(status_code=404, detail="Project not found")

    form_data = await request.form()

    location_id = form_data.get("location_id")
    location = db.query(MonitoringLocation).filter_by(
        id=location_id,
        project_id=project_id,
    ).first()

    if not location:
        raise HTTPException(status_code=404, detail="Location not found")

    # Determine device type from location
    device_type = "slm" if location.location_type == "sound" else "seismograph"

    # Get unit_id (optional - can be determined from assignment at execution time)
    unit_id = form_data.get("unit_id")

    action = ScheduledAction(
        id=str(uuid.uuid4()),
        project_id=project_id,
        location_id=location_id,
        unit_id=unit_id,
        action_type=form_data.get("action_type"),
        device_type=device_type,
        scheduled_time=datetime.fromisoformat(form_data.get("scheduled_time")),
        execution_status="pending",
        notes=form_data.get("notes"),
    )

    db.add(action)
    db.commit()
    db.refresh(action)

    return JSONResponse({
        "success": True,
        "action_id": action.id,
        "message": f"Scheduled action '{action.action_type}' created for {action.scheduled_time}",
    })


# ============================================================================
# Schedule Recording Session
# ============================================================================

@router.post("/schedule-session")
async def schedule_recording_session(
    project_id: str,
    request: Request,
    db: Session = Depends(get_db),
):
    """
    Schedule a complete recording session (start + stop).
    Creates two scheduled actions: start and stop.
    """
    project = db.query(Project).filter_by(id=project_id).first()
    if not project:
        raise HTTPException(status_code=404, detail="Project not found")

    form_data = await request.form()

    location_id = form_data.get("location_id")
    location = db.query(MonitoringLocation).filter_by(
        id=location_id,
        project_id=project_id,
    ).first()

    if not location:
        raise HTTPException(status_code=404, detail="Location not found")

    device_type = "slm" if location.location_type == "sound" else "seismograph"
    unit_id = form_data.get("unit_id")

    start_time = datetime.fromisoformat(form_data.get("start_time"))
    duration_minutes = int(form_data.get("duration_minutes", 60))
    stop_time = start_time + timedelta(minutes=duration_minutes)

    # Create START action
    start_action = ScheduledAction(
        id=str(uuid.uuid4()),
        project_id=project_id,
        location_id=location_id,
        unit_id=unit_id,
        action_type="start",
        device_type=device_type,
        scheduled_time=start_time,
        execution_status="pending",
        notes=form_data.get("notes"),
    )

    # Create STOP action
    stop_action = ScheduledAction(
        id=str(uuid.uuid4()),
        project_id=project_id,
        location_id=location_id,
        unit_id=unit_id,
        action_type="stop",
        device_type=device_type,
        scheduled_time=stop_time,
        execution_status="pending",
        notes=f"Auto-stop after {duration_minutes} minutes",
    )

    db.add(start_action)
    db.add(stop_action)
    db.commit()

    return JSONResponse({
        "success": True,
        "start_action_id": start_action.id,
        "stop_action_id": stop_action.id,
        "message": f"Recording session scheduled from {start_time} to {stop_time}",
    })


# ============================================================================
# Update/Cancel Scheduled Action
# ============================================================================

@router.put("/actions/{action_id}")
async def update_scheduled_action(
    project_id: str,
    action_id: str,
    request: Request,
    db: Session = Depends(get_db),
):
    """
    Update a scheduled action (only if not yet executed).
    """
    action = db.query(ScheduledAction).filter_by(
        id=action_id,
        project_id=project_id,
    ).first()

    if not action:
        raise HTTPException(status_code=404, detail="Action not found")

    if action.execution_status != "pending":
        raise HTTPException(
            status_code=400,
            detail="Cannot update action that has already been executed",
        )

    data = await request.json()

    if "scheduled_time" in data:
        action.scheduled_time = datetime.fromisoformat(data["scheduled_time"])
    if "notes" in data:
        action.notes = data["notes"]

    db.commit()

    return {"success": True, "message": "Action updated successfully"}


@router.post("/actions/{action_id}/cancel")
async def cancel_scheduled_action(
    project_id: str,
    action_id: str,
    db: Session = Depends(get_db),
):
    """
    Cancel a pending scheduled action.
    """
    action = db.query(ScheduledAction).filter_by(
        id=action_id,
        project_id=project_id,
    ).first()

    if not action:
        raise HTTPException(status_code=404, detail="Action not found")

    if action.execution_status != "pending":
        raise HTTPException(
            status_code=400,
            detail="Can only cancel pending actions",
        )

    action.execution_status = "cancelled"
    db.commit()

    return {"success": True, "message": "Action cancelled successfully"}


@router.delete("/actions/{action_id}")
async def delete_scheduled_action(
    project_id: str,
    action_id: str,
    db: Session = Depends(get_db),
):
    """
    Delete a scheduled action (only if pending or cancelled).
    """
    action = db.query(ScheduledAction).filter_by(
        id=action_id,
        project_id=project_id,
    ).first()

    if not action:
        raise HTTPException(status_code=404, detail="Action not found")

    if action.execution_status not in ["pending", "cancelled"]:
        raise HTTPException(
            status_code=400,
            detail="Cannot delete action that has been executed",
        )

    db.delete(action)
    db.commit()

    return {"success": True, "message": "Action deleted successfully"}


# ============================================================================
# Manual Execution
# ============================================================================

@router.post("/actions/{action_id}/execute")
async def execute_action_now(
    project_id: str,
    action_id: str,
    db: Session = Depends(get_db),
):
    """
    Manually trigger execution of a scheduled action (for testing/debugging).
    """
    action = db.query(ScheduledAction).filter_by(
        id=action_id,
        project_id=project_id,
    ).first()

    if not action:
        raise HTTPException(status_code=404, detail="Action not found")

    if action.execution_status != "pending":
        raise HTTPException(
            status_code=400,
            detail="Action is not pending",
        )

    # Execute via scheduler service
    scheduler = get_scheduler()
    result = await scheduler.execute_action_by_id(action_id)

    # Refresh from DB to get updated status
    db.refresh(action)

    return JSONResponse({
        "success": result.get("success", False),
        "result": result,
        "action": {
            "id": action.id,
            "execution_status": action.execution_status,
            "executed_at": action.executed_at.isoformat() if action.executed_at else None,
            "error_message": action.error_message,
        },
    })


# ============================================================================
# Scheduler Status
# ============================================================================

@router.get("/status")
async def get_scheduler_status():
    """
    Get scheduler service status.
    """
    scheduler = get_scheduler()

    return {
        "running": scheduler.running,
        "check_interval": scheduler.check_interval,
    }


@router.post("/execute-pending")
async def trigger_pending_execution():
    """
    Manually trigger execution of all pending actions (for testing).
    """
    scheduler = get_scheduler()
    results = await scheduler.execute_pending_actions()

    return {
        "success": True,
        "executed_count": len(results),
        "results": results,
    }
