use axum::{extract::State, http::HeaderMap, response::Json};
use std::sync::Arc;

use crate::calendar::CalDAVClient;
use crate::{
    models::{ApiError, AuthResponse, CalDAVLoginRequest, CalendarInfo, UserInfo},
    AppState,
};

pub fn extract_bearer_token(headers: &HeaderMap) -> Result<String, ApiError> {
    let auth_header = headers
        .get("authorization")
        .ok_or_else(|| ApiError::Unauthorized("Missing Authorization header".to_string()))?;

    let auth_str = auth_header
        .to_str()
        .map_err(|_| ApiError::BadRequest("Invalid Authorization header".to_string()))?;

    if let Some(token) = auth_str.strip_prefix("Bearer ") {
        Ok(token.to_string())
    } else {
        Err(ApiError::BadRequest(
            "Authorization header must be Bearer token".to_string(),
        ))
    }
}

pub fn extract_password_header(headers: &HeaderMap) -> Result<String, ApiError> {
    let password_header = headers
        .get("x-caldav-password")
        .ok_or_else(|| ApiError::BadRequest("Missing X-CalDAV-Password header".to_string()))?;

    password_header
        .to_str()
        .map(|s| s.to_string())
        .map_err(|_| ApiError::BadRequest("Invalid X-CalDAV-Password header".to_string()))
}

pub async fn login(
    State(state): State<Arc<AppState>>,
    Json(request): Json<CalDAVLoginRequest>,
) -> Result<Json<AuthResponse>, ApiError> {
    println!("🔐 Login attempt:");
    println!("  Server URL: {}", request.server_url);
    println!("  Username: {}", request.username);
    println!("  Password length: {}", request.password.len());

    // Use the auth service login method which now handles database, sessions, and preferences
    let response = state.auth_service.login(request).await?;

    println!("✅ Login successful with session management");

    Ok(Json(response))
}

pub async fn verify_token(
    State(state): State<Arc<AppState>>,
    headers: HeaderMap,
) -> Result<Json<serde_json::Value>, ApiError> {
    let token = extract_bearer_token(&headers)?;
    let is_valid = state.auth_service.verify_token(&token).is_ok();

    Ok(Json(serde_json::json!({ "valid": is_valid })))
}

pub async fn get_user_info(
    State(state): State<Arc<AppState>>,
    headers: HeaderMap,
) -> Result<Json<UserInfo>, ApiError> {
    let token = extract_bearer_token(&headers)?;
    let password = extract_password_header(&headers)?;

    // Create CalDAV config from token and password
    let config = state
        .auth_service
        .caldav_config_from_token(&token, &password)?;
    let client = CalDAVClient::new(config.clone());

    // Discover calendars
    let calendar_paths = client
        .discover_calendars()
        .await
        .map_err(|e| ApiError::Internal(format!("Failed to discover calendars: {}", e)))?;


    let calendars: Vec<CalendarInfo> = calendar_paths
        .iter()
        .map(|path| CalendarInfo {
            path: path.clone(),
            display_name: extract_calendar_name(path),
            color: generate_calendar_color(path),
            is_visible: true, // Default to visible
        })
        .collect();

    Ok(Json(UserInfo {
        username: config.username,
        server_url: config.server_url,
        calendars,
    }))
}

fn generate_calendar_color(path: &str) -> String {
    // Generate a consistent color based on the calendar path
    // This is a simple hash-based approach
    let mut hash: u32 = 0;
    for byte in path.bytes() {
        hash = hash.wrapping_mul(31).wrapping_add(byte as u32);
    }

    // Define a set of pleasant colors
    let colors = [
        "#3B82F6", "#10B981", "#F59E0B", "#EF4444", "#8B5CF6", "#06B6D4", "#84CC16", "#F97316",
        "#EC4899", "#6366F1", "#14B8A6", "#F3B806", "#8B5A2B", "#6B7280", "#DC2626", "#7C3AED",
        "#059669", "#D97706", "#BE185D", "#4F46E5",
    ];

    colors[(hash as usize) % colors.len()].to_string()
}

fn extract_calendar_name(path: &str) -> String {
    // Extract calendar name from path
    // E.g., "/calendars/user/calendar-name/" -> "Calendar Name"
    path.split('/')
        .filter(|s| !s.is_empty())
        .last()
        .unwrap_or("Calendar")
        .replace('-', " ")
        .replace('_', " ")
        .split_whitespace()
        .map(|word| {
            let mut chars = word.chars();
            match chars.next() {
                None => String::new(),
                Some(first) => first.to_uppercase().collect::<String>() + chars.as_str(),
            }
        })
        .collect::<Vec<String>>()
        .join(" ")
}
