from typing import List, Optional
from fastapi import APIRouter, Depends, HTTPException, status, Request
from sqlalchemy.orm import Session
from datetime import date
from app.api.deps import get_db, get_current_read_user, get_current_operator_user
from app.crud.crud_ppr import ppr as crud_ppr
from app.crud.crud_journal import journal as crud_journal
from app.schemas.ppr import PPR, PPRCreate, PPRUpdate, PPRStatus, PPRStatusUpdate, Journal
from app.models.ppr import User
from app.core.utils import get_client_ip
from app.core.email import email_service
from app.core.config import settings

router = APIRouter()


@router.get("/", response_model=List[PPR])
async def get_pprs(
    request: Request,
    skip: int = 0,
    limit: int = 100,
    status: Optional[PPRStatus] = None,
    date_from: Optional[date] = None,
    date_to: Optional[date] = None,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_read_user)
):
    """Get PPR records with optional filtering"""
    pprs = crud_ppr.get_multi(
        db, skip=skip, limit=limit, status=status, 
        date_from=date_from, date_to=date_to
    )
    return pprs


@router.post("/", response_model=PPR)
async def create_ppr(
    request: Request,
    ppr_in: PPRCreate,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_operator_user)
):
    """Create a new PPR record"""
    client_ip = get_client_ip(request)
    ppr = crud_ppr.create(db, obj_in=ppr_in, created_by=current_user.username, user_ip=client_ip)
    
    # Send real-time update via WebSocket
    if hasattr(request.app.state, 'connection_manager'):
        await request.app.state.connection_manager.broadcast({
            "type": "ppr_created",
            "data": {
                "id": ppr.id,
                "ac_reg": ppr.ac_reg,
                "status": ppr.status.value
            }
        })
    
    return ppr


@router.post("/public", response_model=PPR)
async def create_public_ppr(
    request: Request,
    ppr_in: PPRCreate,
    db: Session = Depends(get_db)
):
    """Create a new PPR record (public endpoint, no authentication required)"""
    client_ip = get_client_ip(request)
    # For public submissions, use a default created_by or None
    ppr = crud_ppr.create(db, obj_in=ppr_in, created_by="public", user_ip=client_ip)
    
    # Send real-time update via WebSocket
    if hasattr(request.app.state, 'connection_manager'):
        await request.app.state.connection_manager.broadcast({
            "type": "ppr_created",
            "data": {
                "id": ppr.id,
                "ac_reg": ppr.ac_reg,
                "status": ppr.status.value
            }
        })
    
    # Send email if email provided
    if ppr_in.email:
        await email_service.send_email(
            to_email=ppr_in.email,
            subject="PPR Submitted Successfully",
            template_name="ppr_submitted.html",
            template_vars={
                "name": ppr_in.captain,
                "aircraft": ppr_in.ac_reg,
                "arrival_time": ppr_in.eta.strftime("%Y-%m-%d %H:%M"),
                "departure_time": ppr_in.etd.strftime("%Y-%m-%d %H:%M") if ppr_in.etd else "N/A",
                "purpose": ppr_in.notes or "N/A",
                "public_token": ppr.public_token,
                "base_url": settings.base_url
            }
        )
    
    return ppr


@router.get("/{ppr_id}", response_model=PPR)
async def get_ppr(
    ppr_id: int,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_read_user)
):
    """Get a specific PPR record"""
    ppr = crud_ppr.get(db, ppr_id=ppr_id)
    if not ppr:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="PPR record not found"
        )
    return ppr


@router.put("/{ppr_id}", response_model=PPR)
async def update_ppr(
    request: Request,
    ppr_id: int,
    ppr_in: PPRUpdate,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_operator_user)
):
    """Update a PPR record"""
    db_ppr = crud_ppr.get(db, ppr_id=ppr_id)
    if not db_ppr:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="PPR record not found"
        )
    
    client_ip = get_client_ip(request)
    ppr = crud_ppr.update(db, db_obj=db_ppr, obj_in=ppr_in, user=current_user.username, user_ip=client_ip)
    
    # Send real-time update
    if hasattr(request.app.state, 'connection_manager'):
        await request.app.state.connection_manager.broadcast({
            "type": "ppr_updated",
            "data": {
                "id": ppr.id,
                "ac_reg": ppr.ac_reg,
                "status": ppr.status.value
            }
        })
    
    return ppr


@router.patch("/{ppr_id}", response_model=PPR)
async def patch_ppr(
    request: Request,
    ppr_id: int,
    ppr_in: PPRUpdate,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_operator_user)
):
    """Partially update a PPR record (only provided fields will be updated)"""
    db_ppr = crud_ppr.get(db, ppr_id=ppr_id)
    if not db_ppr:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="PPR record not found"
        )
    
    client_ip = get_client_ip(request)
    ppr = crud_ppr.update(db, db_obj=db_ppr, obj_in=ppr_in, user=current_user.username, user_ip=client_ip)
    
    # Send real-time update
    if hasattr(request.app.state, 'connection_manager'):
        await request.app.state.connection_manager.broadcast({
            "type": "ppr_updated",
            "data": {
                "id": ppr.id,
                "ac_reg": ppr.ac_reg,
                "status": ppr.status.value
            }
        })
    
    return ppr


@router.patch("/{ppr_id}/status", response_model=PPR)
async def update_ppr_status(
    request: Request,
    ppr_id: int,
    status_update: PPRStatusUpdate,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_operator_user)
):
    """Update PPR status (LANDED, DEPARTED, etc.)"""
    client_ip = get_client_ip(request)
    ppr = crud_ppr.update_status(
        db, 
        ppr_id=ppr_id, 
        status=status_update.status,
        timestamp=status_update.timestamp,
        user=current_user.username,
        user_ip=client_ip
    )
    if not ppr:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="PPR record not found"
        )
    
    # Send real-time update
    if hasattr(request.app.state, 'connection_manager'):
        await request.app.state.connection_manager.broadcast({
            "type": "status_update",
            "data": {
                "id": ppr.id,
                "ac_reg": ppr.ac_reg,
                "status": ppr.status.value,
                "timestamp": ppr.landed_dt.isoformat() if ppr.landed_dt else (ppr.departed_dt.isoformat() if ppr.departed_dt else None)
            }
        })
    
    # Send email if cancelled and email provided
    if status_update.status == PPRStatus.CANCELED and ppr.email:
        await email_service.send_email(
            to_email=ppr.email,
            subject="PPR Cancelled",
            template_name="ppr_cancelled.html",
            template_vars={
                "name": ppr.captain,
                "aircraft": ppr.ac_reg,
                "arrival_time": ppr.eta.strftime("%Y-%m-%d %H:%M"),
                "departure_time": ppr.etd.strftime("%Y-%m-%d %H:%M") if ppr.etd else "N/A"
            }
        )
    
    return ppr


@router.delete("/{ppr_id}", response_model=PPR)
async def delete_ppr(
    request: Request,
    ppr_id: int,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_operator_user)
):
    """Delete (soft delete) a PPR record"""
    client_ip = get_client_ip(request)
    ppr = crud_ppr.delete(db, ppr_id=ppr_id, user=current_user.username, user_ip=client_ip)
    if not ppr:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="PPR record not found"
        )
    
    # Send real-time update
    if hasattr(request.app.state, 'connection_manager'):
        await request.app.state.connection_manager.broadcast({
            "type": "ppr_deleted",
            "data": {
                "id": ppr.id,
                "ac_reg": ppr.ac_reg
            }
        })
    
    return ppr


@router.get("/public/edit/{token}", response_model=PPR)
async def get_ppr_for_edit(
    token: str,
    db: Session = Depends(get_db)
):
    """Get PPR details for public editing using token"""
    ppr = crud_ppr.get_by_public_token(db, token)
    if not ppr:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Invalid or expired token"
        )
    # Only allow editing if not already processed
    if ppr.status in [PPRStatus.CANCELED, PPRStatus.DELETED, PPRStatus.LANDED, PPRStatus.DEPARTED]:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="PPR cannot be edited at this stage"
        )
    return ppr


@router.patch("/public/edit/{token}", response_model=PPR)
async def update_ppr_public(
    token: str,
    ppr_in: PPRUpdate,
    request: Request,
    db: Session = Depends(get_db)
):
    """Update PPR publicly using token"""
    ppr = crud_ppr.get_by_public_token(db, token)
    if not ppr:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Invalid or expired token"
        )
    # Only allow editing if not already processed
    if ppr.status in [PPRStatus.CANCELED, PPRStatus.DELETED, PPRStatus.LANDED, PPRStatus.DEPARTED]:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="PPR cannot be edited at this stage"
        )
    
    client_ip = get_client_ip(request)
    updated_ppr = crud_ppr.update(db, db_obj=ppr, obj_in=ppr_in, user="public", user_ip=client_ip)
    return updated_ppr


@router.delete("/public/cancel/{token}", response_model=PPR)
async def cancel_ppr_public(
    token: str,
    request: Request,
    db: Session = Depends(get_db)
):
    """Cancel PPR publicly using token"""
    ppr = crud_ppr.get_by_public_token(db, token)
    if not ppr:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Invalid or expired token"
        )
    # Only allow canceling if not already processed
    if ppr.status in [PPRStatus.CANCELED, PPRStatus.DELETED, PPRStatus.LANDED, PPRStatus.DEPARTED]:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="PPR cannot be cancelled at this stage"
        )
    
    client_ip = get_client_ip(request)
    # Cancel by setting status to CANCELED
    cancelled_ppr = crud_ppr.update_status(
        db, 
        ppr_id=ppr.id, 
        status=PPRStatus.CANCELED,
        user="public",
        user_ip=client_ip
    )
    
    # Send cancellation email if email provided
    if cancelled_ppr.email:
        await email_service.send_email(
            to_email=cancelled_ppr.email,
            subject="PPR Cancelled",
            template_name="ppr_cancelled.html",
            template_vars={
                "name": cancelled_ppr.captain,
                "aircraft": cancelled_ppr.ac_reg,
                "arrival_time": cancelled_ppr.eta.strftime("%Y-%m-%d %H:%M"),
                "departure_time": cancelled_ppr.etd.strftime("%Y-%m-%d %H:%M") if cancelled_ppr.etd else "N/A"
            }
        )
    
    return cancelled_ppr


@router.get("/{ppr_id}/journal", response_model=List[Journal])
async def get_ppr_journal(
    ppr_id: int,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_read_user)
):
    """Get journal entries for a specific PPR"""
    # Verify PPR exists
    ppr = crud_ppr.get(db, ppr_id=ppr_id)
    if not ppr:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="PPR record not found"
        )
    
    return crud_journal.get_by_ppr_id(db, ppr_id=ppr_id)