# create_advisor_schedule → POST /api/v1/schedules
# create_bulk_advisor_schedules → POST /api/v1/schedules/bulk
# update_advisor_schedule → PUT /api/v1/schedules/{schedule_id}
# delete_advisor_schedule → DELETE /api/v1/schedules/{schedule_id}
# get_advisor_schedules → GET /api/v1/schedules
# refresh_all_advisor_statuses → POST /api/v1/schedules/refresh
# update_advisor_status → POST /api/v1/schedules/advisor/{advisor_id}/refresh (new endpoint)
# SHIFTS → GET /api/v1/shifts
# SHIRTS/ADVISRORS GET /shifts/{shift}/advisors
# AVAILABLE ADVISORS GET /schedules/available-advisors
from fastapi import APIRouter, Depends, HTTPException, status, Body, Query
from sqlalchemy.orm import Session
from typing import List, Dict, Any, Optional
from datetime import datetime, date, timedelta
import logging
from pydantic import BaseModel

from app.common.database import get_db
from app.common import schemas, models
from ..services.schedule_service import (
    create_advisor_schedule,
    update_advisor_schedule,
    delete_advisor_schedule,
    get_advisor_schedules,
    refresh_all_advisor_statuses,
    create_bulk_advisor_schedules,
    update_advisor_status,
    SHIFTS,
    get_advisors_by_shift,
    get_available_advisors_at_datetime
)
from auth_service.services.auth_service import verify_token_internally

router = APIRouter()
logger = logging.getLogger(__name__)

# Helper function to check if user is a manager
def check_manager_role(current_user: Dict):
    user_type = None
    
    if isinstance(current_user, dict):
        user_type = current_user.get("type")
        if not user_type and "user" in current_user:
            user_type = current_user.get("user", {}).get("type")
    
    if user_type not in ["manager", "admin"]:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Only managers can access this resource"
        )

# Define a Pydantic model for the JSON input
class ScheduleFilterParams(BaseModel):
    advisor_id: Optional[int] = None
    start_date: Optional[date] = None
    end_date: Optional[date] = None

# 1. Create a single advisor schedule
@router.post("/schedules", response_model=schemas.AdvisorSchedule)
async def create_schedule(
    schedule_data: Dict[str, Any] = Body(...),
    db: Session = Depends(get_db),
    current_user: Dict = Depends(verify_token_internally)
):
    """
    Create a new advisor schedule (manager only)
    
    Expects a JSON object:
    {
        "advisor_id": 1,
        "shift_period_start": "2023-06-01",
        "shift_period_end": "2023-06-07",
        "shift": "SHIFT_1",
        "advisor_status": true
    }
    """
    # Check if user is a manager
    check_manager_role(current_user)
    
    # Get manager ID
    manager_id = current_user.get("user_id")
    if not manager_id:
        manager_id = current_user.get("user", {}).get("id")
    
    if not manager_id:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Could not determine manager ID from authentication token"
        )
    
    # Convert to schema
    try:
        schedule_create = schemas.AdvisorScheduleCreate(**schedule_data)
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"Invalid schedule data: {str(e)}"
        )
    
    # Create schedule
    return create_advisor_schedule(db, schedule_create, manager_id)

# 2. Create schedules for multiple advisors
@router.post("/schedules/bulk", response_model=Dict[str, Any])
async def create_bulk_schedules(
    bulk_data: Dict[str, Any] = Body(...),
    db: Session = Depends(get_db),
    current_user: Dict = Depends(verify_token_internally)
):
    """
    Create schedules for multiple advisors at once (manager only)
    
    Expects a JSON object:
    {
        "advisor_ids": [1, 2, 3],
        "shift_period_start": "2023-06-01",
        "shift_period_end": "2023-06-07",
        "shift": "SHIFT_1",
        "advisor_status": true
    }
    """
    # Check if user is a manager
    check_manager_role(current_user)
    
    # Get manager ID
    manager_id = current_user.get("user_id")
    if not manager_id:
        manager_id = current_user.get("user", {}).get("id")
    
    if not manager_id:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Could not determine manager ID from authentication token"
        )
    
    # Extract data from request
    advisor_ids = bulk_data.get("advisor_ids", [])
    if not advisor_ids or not isinstance(advisor_ids, list):
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="advisor_ids must be a non-empty list"
        )
    
    # Create a base schedule object without advisor_id
    base_schedule = {
        "shift_period_start": bulk_data.get("shift_period_start"),
        "shift_period_end": bulk_data.get("shift_period_end"),
        "shift": bulk_data.get("shift"),
        "advisor_status": bulk_data.get("advisor_status", True)
    }
    
    # Create schedules for each advisor
    results = create_bulk_advisor_schedules(db, advisor_ids, base_schedule, manager_id)
    
    # Return summary
    return {
        "message": f"Created schedules for {len(results['success'])} advisors, {len(results['failed'])} failed",
        "results": results
    }

# 3. Update an existing schedule
@router.put("/schedules/{schedule_id}", response_model=schemas.AdvisorSchedule)
async def update_schedule(
    schedule_id: int,
    schedule_data: Dict[str, Any] = Body(...),
    db: Session = Depends(get_db),
    current_user: Dict = Depends(verify_token_internally)
):
    """
    Update an existing advisor schedule (manager only)
    
    Expects a JSON object with fields to update:
    {
        "shift_period_start": "2023-06-01",
        "shift_period_end": "2023-06-07",
        "shift": "SHIFT_2",
        "advisor_status": false
    }
    """
    # Check if user is a manager
    check_manager_role(current_user)
    
    # Get manager ID
    manager_id = current_user.get("user_id")
    if not manager_id:
        manager_id = current_user.get("user", {}).get("id")
    
    if not manager_id:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Could not determine manager ID from authentication token"
        )
    
    # Convert to schema
    try:
        schedule_update = schemas.AdvisorScheduleUpdate(**schedule_data)
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"Invalid schedule data: {str(e)}"
        )
    
    # Update schedule
    return update_advisor_schedule(db, schedule_id, schedule_update, manager_id)

# 4. Delete a schedule
@router.delete("/schedules/{schedule_id}")
async def delete_schedule(
    schedule_id: int,
    db: Session = Depends(get_db),
    current_user: Dict = Depends(verify_token_internally)
):
    """
    Delete an advisor schedule (manager only)
    """
    # Check if user is a manager
    check_manager_role(current_user)
    
    # Delete schedule
    return delete_advisor_schedule(db, schedule_id)

# 5. Get schedules with optional filtering
@router.post("/all-schedules", response_model=List[Dict[str, Any]])
async def get_schedules(
    filters: ScheduleFilterParams = Body(default_factory=dict),
    db: Session = Depends(get_db),
    current_user: Dict = Depends(verify_token_internally)
):
    """
    Get advisor schedules with optional JSON filters (manager only)
    """
    # Check if user is a manager
    check_manager_role(current_user)
    
    # Determine the date range
    if filters.start_date and filters.end_date:
        start_datetime = datetime.combine(filters.start_date, datetime.min.time())
        end_datetime = datetime.combine(filters.end_date, datetime.max.time())
    else:
        # Default to one week backward from today
        today = datetime.now()
        start_datetime = today - timedelta(weeks=1)
        end_datetime = today
    
    # Get schedules
    return get_advisor_schedules(db, filters.advisor_id, start_datetime, end_datetime)

# 6. Refresh all advisor statuses
@router.post("/schedules/refresh")
async def refresh_advisor_statuses(
    db: Session = Depends(get_db),
    current_user: Dict = Depends(verify_token_internally)
):
    """
    Refresh the status of all advisors based on their schedules (manager only)
    """
    # Check if user is a manager
    check_manager_role(current_user)
    
    # Refresh all advisor statuses
    return refresh_all_advisor_statuses(db)

# 7. Update a single advisor's status
@router.post("/schedules/advisor/{advisor_id}/refresh")
async def refresh_single_advisor_status(
    advisor_id: int,
    db: Session = Depends(get_db),
    current_user: Dict = Depends(verify_token_internally)
):
    """
    Refresh the status of a single advisor based on their schedule (manager only)
    """
    # Check if user is a manager
    check_manager_role(current_user)
    
    # Update advisor status
    in_shift = update_advisor_status(db, advisor_id)
    
    return {
        "message": f"Advisor status refreshed",
        "advisor_id": advisor_id,
        "in_shift": in_shift
    }

# 8. Get available shifts
@router.get("/shifts")
async def get_shifts(
    current_user: Dict = Depends(verify_token_internally)
):
    """
    Get available shifts and their timings
    """
    # Format shifts for response
    formatted_shifts = {}
    for shift_key, shift_info in SHIFTS.items():
        formatted_shifts[shift_key] = {
            "name": shift_info["name"],
            "start": shift_info["start"].strftime("%H:%M"),
            "end": shift_info["end"].strftime("%H:%M")
        }
    
    return formatted_shifts

# 9. Get advisors available for a specific shift
@router.get("/shifts/{shift}/advisors", response_model=List[Dict[str, Any]])
async def get_advisors_by_shift(
    shift: str,
    date: Optional[date] = Query(None, description="Date to check (defaults to today)"),
    db: Session = Depends(get_db),
    current_user: Dict = Depends(verify_token_internally)
):
    """
    Get all advisors scheduled for a specific shift on a given date
    
    Returns a list of advisors with their schedule details
    """
    # Check if user is a manager
    check_manager_role(current_user)
    
    # If no date provided, use today
    check_date = date or datetime.now().date()
    
    # Convert to datetime for database query
    check_datetime = datetime.combine(check_date, datetime.min.time())
    
    # Get all schedules for the specified shift and date
    schedules = db.query(models.AdvisorSchedule).filter(
        models.AdvisorSchedule.shift == shift,
        models.AdvisorSchedule.shift_period_start <= check_datetime,
        models.AdvisorSchedule.shift_period_end >= check_datetime,
        models.AdvisorSchedule.advisor_status == True
    ).all()
    
    # Get advisor details for each schedule
    result = []
    for schedule in schedules:
        advisor = db.query(models.Advisor).filter(
            models.Advisor.id == schedule.advisor_id
        ).first()
        
        if advisor:
            result.append({
                "advisor_id": advisor.id,
                "full_name": advisor.full_name,
                "email": advisor.email,
                "phone_number": advisor.phone_number,
                "status": advisor.status,
                "schedule_id": schedule.id,
                "shift": schedule.shift,
                "shift_period_start": schedule.shift_period_start,
                "shift_period_end": schedule.shift_period_end
            })
    
    return result

@router.post("/schedules/available-advisors", response_model=List[Dict[str, Any]])
async def get_available_advisors(
    data: Dict[str, Any] = Body(...),
    db: Session = Depends(get_db),
    current_user: Dict = Depends(verify_token_internally)
):
    """
    Get advisors available at a specific date and time
    
    Expects a JSON object:
    {
        "datetime": "2025-03-15 15:00"  # Format: YYYY-MM-DD HH:MM (24-hour format)
    }
    
    Returns a list of advisors with their IDs and statuses
    """
    # Check if user is a manager
    check_manager_role(current_user)
    
    # Extract datetime from request
    datetime_str = data.get("datetime")
    if not datetime_str:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="datetime field is required"
        )
    
    # Parse the datetime string
    try:
        # Try parsing with 24-hour format
        check_datetime = datetime.strptime(datetime_str, "%Y-%m-%d %H:%M")
    except ValueError:
        try:
            # Try parsing with 12-hour format
            check_datetime = datetime.strptime(datetime_str, "%Y-%m-%d %I:%M%p")
        except ValueError:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Invalid datetime format. Use 'YYYY-MM-DD HH:MM' (24-hour) or 'YYYY-MM-DD HH:MMam/pm' (12-hour)"
            )
    
    # Get available advisors
    return get_available_advisors_at_datetime(db, check_datetime)

@router.post("/schedules/individual", response_model=Dict[str, Any])
async def update_individual_schedules(
    schedules_data: Dict[str, Any] = Body(...),
    db: Session = Depends(get_db),
    current_user: Dict = Depends(verify_token_internally)
):
    """
    Update schedules for individual advisors (manager only)
    
    Expects a JSON object:
    {
        "schedules": [
            {
                "advisor_id": 1,
                "shift_period_start": "2023-06-01",
                "shift_period_end": "2023-06-07",
                "shift": "SHIFT_1",
                "advisor_status": true
            },
            {
                "advisor_id": 2,
                "shift_period_start": "2023-06-02",
                "shift_period_end": "2023-06-08",
                "shift": "SHIFT_2",
                "advisor_status": false
            }
        ]
    }
    """
    # Check if user is a manager
    check_manager_role(current_user)
    
    # Get manager ID
    manager_id = current_user.get("user_id")
    if not manager_id:
        manager_id = current_user.get("user", {}).get("id")
    
    if not manager_id:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Could not determine manager ID from authentication token"
        )
    
    # Extract schedules data
    schedules = schedules_data.get("schedules", [])
    if not schedules or not isinstance(schedules, list):
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="schedules must be a non-empty list"
        )
    
    # Process each schedule
    results = {
        "success": [],
        "failed": []
    }
    
    for schedule in schedules:
        try:
            # Convert to schema
            schedule_create = schemas.AdvisorScheduleCreate(**schedule)
            
            # Create the schedule using the service function
            new_schedule = create_advisor_schedule(db, schedule_create, manager_id)
            
            results["success"].append({
                "advisor_id": schedule["advisor_id"],
                "schedule_id": new_schedule.id
            })
            
        except Exception as e:
            results["failed"].append({
                "advisor_id": schedule.get("advisor_id"),
                "error": str(e)
            })
    
    return {
        "message": f"Updated schedules for {len(results['success'])} advisors, {len(results['failed'])} failed",
        "results": results
    } 