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

use crate::calendar::CalDAVClient;
use crate::{
    models::{
        ApiError, CreateEventSeriesRequest, CreateEventSeriesResponse, DeleteEventSeriesRequest,
        DeleteEventSeriesResponse, UpdateEventSeriesRequest, UpdateEventSeriesResponse,
    },
    AppState,
};
use calendar_models::{EventClass, EventStatus, VEvent};

use super::auth::{extract_bearer_token, extract_password_header};

fn parse_event_datetime_local(
    date_str: &str,
    time_str: &str,
    all_day: bool,
) -> Result<chrono::NaiveDateTime, String> {
    use chrono::{NaiveDate, NaiveDateTime, NaiveTime};

    // Parse the date
    let date = NaiveDate::parse_from_str(date_str, "%Y-%m-%d")
        .map_err(|_| format!("Invalid date format: {}. Expected YYYY-MM-DD", date_str))?;

    if all_day {
        // For all-day events, use start of day
        let datetime = date
            .and_hms_opt(0, 0, 0)
            .ok_or_else(|| "Failed to create start-of-day datetime".to_string())?;
        Ok(datetime)
    } else {
        // Parse the time
        let time = NaiveTime::parse_from_str(time_str, "%H:%M")
            .map_err(|_| format!("Invalid time format: {}. Expected HH:MM", time_str))?;

        // Combine date and time - now keeping as local time
        Ok(NaiveDateTime::new(date, time))
    }
}

/// Create a new recurring event series
pub async fn create_event_series(
    State(state): State<Arc<AppState>>,
    headers: HeaderMap,
    Json(request): Json<CreateEventSeriesRequest>,
) -> Result<Json<CreateEventSeriesResponse>, ApiError> {
    println!(
        "📝 Create event series request received: title='{}', recurrence='{}', all_day={}",
        request.title, request.recurrence, request.all_day
    );

    // Extract and verify token
    let token = extract_bearer_token(&headers)?;
    let password = extract_password_header(&headers)?;

    // Validate request
    if request.title.trim().is_empty() {
        return Err(ApiError::BadRequest("Event title is required".to_string()));
    }

    if request.title.len() > 200 {
        return Err(ApiError::BadRequest(
            "Event title too long (max 200 characters)".to_string(),
        ));
    }

    if request.recurrence == "none" {
        return Err(ApiError::BadRequest(
            "Use regular create endpoint for non-recurring events".to_string(),
        ));
    }

    // Validate recurrence type - handle both simple strings and RRULE strings
    let recurrence_freq = if request.recurrence.contains("FREQ=") {
        // Parse RRULE to extract frequency
        if request.recurrence.contains("FREQ=DAILY") {
            "daily"
        } else if request.recurrence.contains("FREQ=WEEKLY") {
            "weekly"
        } else if request.recurrence.contains("FREQ=MONTHLY") {
            "monthly"
        } else if request.recurrence.contains("FREQ=YEARLY") {
            "yearly"
        } else {
            return Err(ApiError::BadRequest(
                "Invalid RRULE frequency. Must be DAILY, WEEKLY, MONTHLY, or YEARLY".to_string(),
            ));
        }
    } else {
        // Handle simple strings
        let lower = request.recurrence.to_lowercase();
        match lower.as_str() {
            "daily" => "daily",
            "weekly" => "weekly",
            "monthly" => "monthly",
            "yearly" => "yearly",
            _ => {
                return Err(ApiError::BadRequest(
                    "Invalid recurrence type. Must be daily, weekly, monthly, or yearly"
                        .to_string(),
                ))
            }
        }
    };

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

    // Determine which calendar to use
    let calendar_path = if let Some(ref path) = request.calendar_path {
        path.clone()
    } else {
        // Use the first available calendar
        let calendar_paths = client
            .discover_calendars()
            .await
            .map_err(|e| ApiError::Internal(format!("Failed to discover calendars: {}", e)))?;

        if calendar_paths.is_empty() {
            return Err(ApiError::BadRequest(
                "No calendars available for event creation".to_string(),
            ));
        }

        calendar_paths[0].clone()
    };

    println!("📅 Using calendar path: {}", calendar_path);

    // Parse dates and times as local times (no UTC conversion)
    let start_datetime = parse_event_datetime_local(&request.start_date, &request.start_time, request.all_day)
        .map_err(|e| ApiError::BadRequest(format!("Invalid start date/time: {}", e)))?;

    let end_datetime = parse_event_datetime_local(&request.end_date, &request.end_time, request.all_day)
        .map_err(|e| ApiError::BadRequest(format!("Invalid end date/time: {}", e)))?;

    // Note: Frontend already converts inclusive UI dates to exclusive dates for all-day events
    // No additional conversion needed here

    // Generate a unique UID for the series
    let uid = format!("series-{}", uuid::Uuid::new_v4().to_string());

    // Create the VEvent for the series with local times
    let mut event = VEvent::new(uid.clone(), start_datetime);
    event.dtend = Some(end_datetime);
    event.all_day = request.all_day; // Set the all_day flag properly
    
    // Set timezone information from client
    event.dtstart_tzid = Some(request.timezone.clone());
    event.dtend_tzid = Some(request.timezone.clone());
    event.summary = if request.title.trim().is_empty() {
        None
    } else {
        Some(request.title.clone())
    };
    event.description = if request.description.trim().is_empty() {
        None
    } else {
        Some(request.description.clone())
    };
    event.location = if request.location.trim().is_empty() {
        None
    } else {
        Some(request.location.clone())
    };

    // Set event status
    event.status = Some(match request.status.to_lowercase().as_str() {
        "tentative" => EventStatus::Tentative,
        "cancelled" => EventStatus::Cancelled,
        _ => EventStatus::Confirmed,
    });

    // Set event class
    event.class = Some(match request.class.to_lowercase().as_str() {
        "private" => EventClass::Private,
        "confidential" => EventClass::Confidential,
        _ => EventClass::Public,
    });

    // Set priority
    event.priority = request.priority;

    // Check if recurrence is already a full RRULE or just a simple type
    let rrule = if request.recurrence.starts_with("FREQ=") {
        // Frontend sent a complete RRULE string, use it directly
        request.recurrence.clone()
    } else {
        // Legacy path: Generate the RRULE for recurrence
        build_series_rrule_with_freq(&request, recurrence_freq)?
    };
    event.rrule = Some(rrule);

    // Create the event on the CalDAV server
    let event_href = client
        .create_event(&calendar_path, &event)
        .await
        .map_err(|e| ApiError::Internal(format!("Failed to create event series: {}", e)))?;

    println!(
        "✅ Event series created successfully with UID: {}, href: {}",
        uid, event_href
    );

    Ok(Json(CreateEventSeriesResponse {
        success: true,
        message: "Event series created successfully".to_string(),
        series_uid: Some(uid),
        occurrences_created: Some(1), // Series created as a single repeating event
        event_href: Some(event_href),
    }))
}

/// Update a recurring event series with different scope options
pub async fn update_event_series(
    State(state): State<Arc<AppState>>,
    headers: HeaderMap,
    Json(request): Json<UpdateEventSeriesRequest>,
) -> Result<Json<UpdateEventSeriesResponse>, ApiError> {
    println!(
        "🔄 Update event series request received: series_uid='{}', update_scope='{}', recurrence_count={:?}, recurrence_end_date={:?}",
        request.series_uid, request.update_scope, request.recurrence_count, request.recurrence_end_date
    );
    println!("🕐 SERIES: Received start_date: '{}', start_time: '{}', timezone: '{}'", 
             request.start_date, request.start_time, request.timezone);

    // Extract and verify token
    let token = extract_bearer_token(&headers)?;
    let password = extract_password_header(&headers)?;

    // Validate request
    if request.series_uid.trim().is_empty() {
        return Err(ApiError::BadRequest("Series UID is required".to_string()));
    }

    if request.title.trim().is_empty() {
        return Err(ApiError::BadRequest("Event title is required".to_string()));
    }

    if request.title.len() > 200 {
        return Err(ApiError::BadRequest(
            "Event title too long (max 200 characters)".to_string(),
        ));
    }

    // Validate update scope
    match request.update_scope.as_str() {
        "this_only" | "this_and_future" | "all_in_series" => {}
        _ => {
            return Err(ApiError::BadRequest(
                "Invalid update_scope. Must be: this_only, this_and_future, or all_in_series"
                    .to_string(),
            ))
        }
    }

    // Validate recurrence type - handle both simple strings and RRULE strings
    let recurrence_freq = if request.recurrence.contains("FREQ=") {
        // Parse RRULE to extract frequency
        if request.recurrence.contains("FREQ=DAILY") {
            "daily"
        } else if request.recurrence.contains("FREQ=WEEKLY") {
            "weekly"
        } else if request.recurrence.contains("FREQ=MONTHLY") {
            "monthly"
        } else if request.recurrence.contains("FREQ=YEARLY") {
            "yearly"
        } else {
            return Err(ApiError::BadRequest(
                "Invalid RRULE frequency. Must be DAILY, WEEKLY, MONTHLY, or YEARLY".to_string(),
            ));
        }
    } else {
        // Handle simple strings
        let lower = request.recurrence.to_lowercase();
        match lower.as_str() {
            "daily" => "daily",
            "weekly" => "weekly",
            "monthly" => "monthly",
            "yearly" => "yearly",
            _ => {
                return Err(ApiError::BadRequest(
                    "Invalid recurrence type. Must be daily, weekly, monthly, or yearly"
                        .to_string(),
                ))
            }
        }
    };

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

    // Use the parsed frequency for further processing (avoiding unused variable warning)
    let _freq_for_processing = recurrence_freq;

    // Determine which calendar to search (or search all calendars)
    let calendar_paths = if let Some(ref path) = request.calendar_path {
        vec![path.clone()]
    } else {
        client
            .discover_calendars()
            .await
            .map_err(|e| ApiError::Internal(format!("Failed to discover calendars: {}", e)))?
    };

    if calendar_paths.is_empty() {
        return Err(ApiError::BadRequest(
            "No calendars available for event update".to_string(),
        ));
    }

    // Find the series event across all specified calendars
    let mut existing_event = None;
    let mut calendar_path = String::new();

    for path in &calendar_paths {
        if let Ok(Some(event)) = client.fetch_event_by_uid(path, &request.series_uid).await {
            existing_event = Some(event);
            calendar_path = path.clone();
            break;
        }
    }

    let mut existing_event = existing_event.ok_or_else(|| {
        ApiError::NotFound(format!(
            "Event series with UID '{}' not found",
            request.series_uid
        ))
    })?;

    println!("📅 Found series event in calendar: {}", calendar_path);
    println!(
        "📅 Event details: UID={}, summary={:?}, dtstart={}",
        existing_event.uid, existing_event.summary, existing_event.dtstart
    );

    // Parse datetime components for the update
    let original_start_date = existing_event.dtstart.date();

    // For "this_and_future" and "this_only" updates, use the occurrence date for the modified event
    // For "all_in_series" updates, preserve the original series start date
    let start_date = if (request.update_scope == "this_and_future"
        || request.update_scope == "this_only")
        && request.occurrence_date.is_some()
    {
        let occurrence_date_str = request.occurrence_date.as_ref().unwrap();
        chrono::NaiveDate::parse_from_str(occurrence_date_str, "%Y-%m-%d").map_err(|_| {
            ApiError::BadRequest("Invalid occurrence_date format. Expected YYYY-MM-DD".to_string())
        })?
    } else {
        original_start_date
    };

    let (start_datetime, end_datetime) = if request.all_day {
        // For all-day events, use noon UTC to avoid timezone boundary issues
        let start_dt = start_date
            .and_hms_opt(12, 0, 0)
            .ok_or_else(|| ApiError::BadRequest("Invalid start date".to_string()))?;

        // For all-day events, also preserve the original date pattern
        let end_date = if !request.end_date.is_empty() {
            // Calculate the duration from the original event
            let original_duration_days = existing_event
                .dtend
                .map(|end| (end.date() - existing_event.dtstart.date()).num_days())
                .unwrap_or(0);
            start_date + chrono::Duration::days(original_duration_days)
        } else {
            start_date
        };

        let end_dt = end_date
            .and_hms_opt(12, 0, 0)
            .ok_or_else(|| ApiError::BadRequest("Invalid end date".to_string()))?;

        // For all-day events, use local times directly
        (start_dt, end_dt)
    } else {
        let start_time = if !request.start_time.is_empty() {
            chrono::NaiveTime::parse_from_str(&request.start_time, "%H:%M").map_err(|_| {
                ApiError::BadRequest("Invalid start_time format. Expected HH:MM".to_string())
            })?
        } else {
            existing_event.dtstart.time()
        };

        let end_time = if !request.end_time.is_empty() {
            chrono::NaiveTime::parse_from_str(&request.end_time, "%H:%M").map_err(|_| {
                ApiError::BadRequest("Invalid end_time format. Expected HH:MM".to_string())
            })?
        } else {
            existing_event
                .dtend
                .map(|dt| dt.time())
                .unwrap_or_else(|| existing_event.dtstart.time() + chrono::Duration::hours(1))
        };

        let start_dt = start_date.and_time(start_time);
        let end_dt = if !request.end_time.is_empty() {
            // Use the new end time with the preserved date
            start_date.and_time(end_time)
        } else {
            // Calculate end time based on original duration
            let original_duration = existing_event
                .dtend
                .map(|end| end - existing_event.dtstart)
                .unwrap_or_else(|| chrono::Duration::hours(1));
            start_dt + original_duration
        };

        // Frontend now sends local times, so use them directly
        (start_dt, end_dt)
    };

    // Handle different update scopes
    let (updated_event, occurrences_affected) = match request.update_scope.as_str() {
        "all_in_series" => {
            // Update the entire series - modify the master event
            update_entire_series(&mut existing_event, &request, start_datetime, end_datetime)?
        }
        "this_and_future" => {
            // Split the series: keep past occurrences, create new series from occurrence date
            update_this_and_future(
                &mut existing_event,
                &request,
                start_datetime,
                end_datetime,
                &client,
                &calendar_path,
            )
            .await?
        }
        "this_only" => {
            // Create exception for single occurrence, keep original series
            let event_href = existing_event
                .href
                .as_ref()
                .ok_or_else(|| {
                    ApiError::Internal(
                        "Event missing href for single occurrence update".to_string(),
                    )
                })?
                .clone();
            update_single_occurrence(
                &mut existing_event,
                &request,
                start_datetime,
                end_datetime,
                &client,
                &calendar_path,
                &event_href,
            )
            .await?
        }
        _ => unreachable!(), // Already validated above
    };

    // Update the event on the CalDAV server using the original event's href
    let event_href = existing_event
        .href
        .as_ref()
        .ok_or_else(|| ApiError::Internal("Event missing href for update".to_string()))?;

    match client
        .update_event(&calendar_path, &updated_event, event_href)
        .await
    {
        Ok(_) => {
            println!("✅ CalDAV update completed successfully");
        }
        Err(e) => {
            println!("❌ CalDAV update failed: {}", e);
            return Err(ApiError::Internal(format!(
                "Failed to update event series: {}",
                e
            )));
        }
    }

    println!(
        "✅ Event series updated successfully with UID: {}",
        request.series_uid
    );

    Ok(Json(UpdateEventSeriesResponse {
        success: true,
        message: "Event series updated successfully".to_string(),
        series_uid: Some(request.series_uid),
        occurrences_affected: Some(occurrences_affected),
    }))
}

/// Delete a recurring event series or specific occurrences
pub async fn delete_event_series(
    State(state): State<Arc<AppState>>,
    headers: HeaderMap,
    Json(request): Json<DeleteEventSeriesRequest>,
) -> Result<Json<DeleteEventSeriesResponse>, ApiError> {
    println!(
        "🗑️ Delete event series request received: series_uid='{}', delete_scope='{}'",
        request.series_uid, request.delete_scope
    );

    // Extract and verify token
    let token = extract_bearer_token(&headers)?;
    let password = extract_password_header(&headers)?;

    // Validate request
    if request.series_uid.trim().is_empty() {
        return Err(ApiError::BadRequest("Series UID is required".to_string()));
    }

    if request.calendar_path.trim().is_empty() {
        return Err(ApiError::BadRequest(
            "Calendar path is required".to_string(),
        ));
    }

    if request.event_href.trim().is_empty() {
        return Err(ApiError::BadRequest("Event href is required".to_string()));
    }

    // Validate delete scope
    match request.delete_scope.as_str() {
        "this_only" | "this_and_future" | "all_in_series" => {}
        _ => {
            return Err(ApiError::BadRequest(
                "Invalid delete_scope. Must be: this_only, this_and_future, or all_in_series"
                    .to_string(),
            ))
        }
    }

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

    // Handle different deletion scopes
    let occurrences_affected = match request.delete_scope.as_str() {
        "all_in_series" => {
            // Delete the entire series - simply delete the event
            delete_entire_series(&client, &request).await?
        }
        "this_and_future" => {
            // Modify RRULE to end before this occurrence
            delete_this_and_future(&client, &request).await?
        }
        "this_only" => {
            // Add EXDATE for single occurrence
            delete_single_occurrence(&client, &request).await?
        }
        _ => unreachable!(), // Already validated above
    };

    println!(
        "✅ Event series deletion completed with {} occurrences affected",
        occurrences_affected
    );

    Ok(Json(DeleteEventSeriesResponse {
        success: true,
        message: "Event series deletion completed successfully".to_string(),
        occurrences_affected: Some(occurrences_affected),
    }))
}

// Helper functions

fn build_series_rrule_with_freq(
    request: &CreateEventSeriesRequest,
    freq: &str,
) -> Result<String, ApiError> {
    let mut rrule_parts = Vec::new();

    // Add frequency
    match freq {
        "daily" => rrule_parts.push("FREQ=DAILY".to_string()),
        "weekly" => rrule_parts.push("FREQ=WEEKLY".to_string()),
        "monthly" => rrule_parts.push("FREQ=MONTHLY".to_string()),
        "yearly" => rrule_parts.push("FREQ=YEARLY".to_string()),
        _ => {
            return Err(ApiError::BadRequest(
                "Invalid recurrence frequency".to_string(),
            ))
        }
    }

    // Add interval if specified and greater than 1
    if let Some(interval) = request.recurrence_interval {
        if interval > 1 {
            rrule_parts.push(format!("INTERVAL={}", interval));
        }
    }

    // Handle weekly recurrence with specific days (BYDAY)
    if freq == "weekly" && request.recurrence_days.len() == 7 {
        let selected_days: Vec<&str> = request
            .recurrence_days
            .iter()
            .enumerate()
            .filter_map(|(i, &selected)| {
                if selected {
                    Some(match i {
                        0 => "SU", // Sunday
                        1 => "MO", // Monday
                        2 => "TU", // Tuesday
                        3 => "WE", // Wednesday
                        4 => "TH", // Thursday
                        5 => "FR", // Friday
                        6 => "SA", // Saturday
                        _ => return None,
                    })
                } else {
                    None
                }
            })
            .collect();

        if !selected_days.is_empty() {
            rrule_parts.push(format!("BYDAY={}", selected_days.join(",")));
        }
    }

    // Add end date if specified (UNTIL takes precedence over COUNT)
    if let Some(end_date) = &request.recurrence_end_date {
        // Parse the end date and convert to RRULE format (YYYYMMDDTHHMMSSZ)
        match chrono::NaiveDate::parse_from_str(end_date, "%Y-%m-%d") {
            Ok(date) => {
                let end_datetime = date
                    .and_hms_opt(23, 59, 59)
                    .ok_or_else(|| ApiError::BadRequest("Invalid end date".to_string()))?;
                let utc_end = chrono::Utc.from_utc_datetime(&end_datetime);
                rrule_parts.push(format!("UNTIL={}", utc_end.format("%Y%m%dT%H%M%SZ")));
            }
            Err(_) => {
                return Err(ApiError::BadRequest(
                    "Invalid recurrence_end_date format. Expected YYYY-MM-DD".to_string(),
                ))
            }
        }
    } else if let Some(count) = request.recurrence_count {
        if count > 0 {
            rrule_parts.push(format!("COUNT={}", count));
        }
    }

    Ok(rrule_parts.join(";"))
}

/// Update the entire series - modify the master event
fn update_entire_series(
    existing_event: &mut VEvent,
    request: &UpdateEventSeriesRequest,
    start_datetime: chrono::NaiveDateTime,
    end_datetime: chrono::NaiveDateTime,
) -> Result<(VEvent, u32), ApiError> {
    // Clone the existing event to preserve all metadata
    let mut updated_event = existing_event.clone();

    // Update only the modified properties from the request
    updated_event.dtstart = start_datetime;
    updated_event.dtend = Some(end_datetime);
    updated_event.dtstart_tzid = Some(request.timezone.clone());
    updated_event.dtend_tzid = Some(request.timezone.clone());
    updated_event.summary = if request.title.trim().is_empty() {
        existing_event.summary.clone() // Keep original if empty
    } else {
        Some(request.title.clone())
    };
    updated_event.description = if request.description.trim().is_empty() {
        existing_event.description.clone() // Keep original if empty
    } else {
        Some(request.description.clone())
    };
    updated_event.location = if request.location.trim().is_empty() {
        existing_event.location.clone() // Keep original if empty
    } else {
        Some(request.location.clone())
    };

    updated_event.status = Some(match request.status.to_lowercase().as_str() {
        "tentative" => EventStatus::Tentative,
        "cancelled" => EventStatus::Cancelled,
        _ => EventStatus::Confirmed,
    });

    updated_event.class = Some(match request.class.to_lowercase().as_str() {
        "private" => EventClass::Private,
        "confidential" => EventClass::Confidential,
        _ => EventClass::Public,
    });

    updated_event.priority = request.priority;

    // Update timestamps
    let now = chrono::Utc::now();
    let now_naive = now.naive_utc();
    updated_event.dtstamp = now;
    updated_event.last_modified = Some(now_naive);
    // Keep original created timestamp to preserve event history

    // Update RRULE if recurrence parameters are provided
    if let Some(ref existing_rrule) = updated_event.rrule {
        let mut new_rrule = existing_rrule.clone();
        println!("🔄 Original RRULE: {}", existing_rrule);
        
        // Update COUNT if provided
        if let Some(count) = request.recurrence_count {
            println!("🔄 Updating RRULE with new COUNT: {}", count);
            // Remove old COUNT or UNTIL parameters
            new_rrule = new_rrule.split(';')
                .filter(|part| !part.starts_with("COUNT=") && !part.starts_with("UNTIL="))
                .collect::<Vec<_>>()
                .join(";");
            // Add new COUNT
            new_rrule = format!("{};COUNT={}", new_rrule, count);
        } else if let Some(ref end_date) = request.recurrence_end_date {
            println!("🔄 Updating RRULE with new UNTIL: {}", end_date);
            // Remove old COUNT or UNTIL parameters
            new_rrule = new_rrule.split(';')
                .filter(|part| !part.starts_with("COUNT=") && !part.starts_with("UNTIL="))
                .collect::<Vec<_>>()
                .join(";");
            // Add new UNTIL (convert YYYY-MM-DD to YYYYMMDD format)
            let until_date = end_date.replace("-", "");
            new_rrule = format!("{};UNTIL={}", new_rrule, until_date);
        }
        
        println!("🔄 Updated RRULE: {}", new_rrule);
        updated_event.rrule = Some(new_rrule);
    }

    // Copy the updated event back to existing_event for the main handler
    *existing_event = updated_event.clone();

    Ok((updated_event, 1)) // 1 series updated (affects all occurrences)
}

/// Update this occurrence and all future occurrences (RFC 5545 compliant series splitting)
///
/// This function implements the "this and future events" modification pattern for recurring
/// event series by splitting the original series into two parts:
///
/// ## Operation Overview:
/// 1. **Terminate Original Series**: Adds an UNTIL clause to the original recurring event
///    to stop generating occurrences before the target occurrence date.
/// 2. **Create New Series**: Creates a completely new recurring series starting from the
///    target occurrence date with the updated properties (new times, title, etc.).
///
/// ## Example Scenario:
/// - Original series: "Daily meeting 9:00-10:00 AM" (Aug 15 onwards, no end date)
/// - User drags Aug 22 occurrence to 2:00-3:00 PM  
/// - Result:
///   - Original series: "Daily meeting 9:00-10:00 AM" with UNTIL=Aug 22 midnight (covers Aug 15-21)
///   - New series: "Daily meeting 2:00-3:00 PM" starting Aug 22 (covers Aug 22 onwards)
///
/// ## RFC 5545 Compliance:
/// - Uses UNTIL property in RRULE to cleanly terminate the original series
/// - Preserves original event UIDs and CalDAV metadata  
/// - Maintains proper DTSTAMP and LAST-MODIFIED timestamps
/// - New series gets fresh UID to avoid conflicts
///
/// ## CalDAV Operations:
/// This function performs two sequential CalDAV operations:
/// 1. CREATE new series on the CalDAV server
/// 2. UPDATE original series (handled by caller) with UNTIL clause
///
/// Operations are serialized using a global mutex to prevent race conditions.
///
/// ## Parameters:
/// - `existing_event`: The original recurring event to be split
/// - `request`: Update request containing new properties and occurrence_date
/// - `start_datetime`/`end_datetime`: New times for the future occurrences  
/// - `client`: CalDAV client for server operations
/// - `calendar_path`: CalDAV calendar path where events are stored
///
/// ## Returns:
/// - `(VEvent, u32)`: Updated original event with UNTIL clause, and count of operations (2)
///
/// ## Error Handling:
/// - Validates occurrence_date format and presence
/// - Handles CalDAV server communication errors
/// - Ensures atomic operations (both succeed or both fail)
async fn update_this_and_future(
    existing_event: &mut VEvent,
    request: &UpdateEventSeriesRequest,
    start_datetime: chrono::NaiveDateTime,
    end_datetime: chrono::NaiveDateTime,
    client: &CalDAVClient,
    calendar_path: &str,
) -> Result<(VEvent, u32), ApiError> {
    // Clone the existing event to create the new series before modifying the RRULE of the
    // original, because we'd like to preserve the original UNTIL logic
    let mut new_series = existing_event.clone();
    let occurrence_date = request.occurrence_date.as_ref().ok_or_else(|| {
        ApiError::BadRequest("occurrence_date is required for this_and_future updates".to_string())
    })?;

    // Parse occurrence date
    let occurrence_date_parsed = chrono::NaiveDate::parse_from_str(occurrence_date, "%Y-%m-%d")
        .map_err(|_| ApiError::BadRequest("Invalid occurrence date format".to_string()))?;

    // Step 1: Add UNTIL to the original series to stop before the occurrence date
    let until_datetime = occurrence_date_parsed
        .and_hms_opt(0, 0, 0)
        .ok_or_else(|| ApiError::BadRequest("Invalid occurrence date".to_string()))?;
    let utc_until = chrono::Utc.from_utc_datetime(&until_datetime);

    // Create modified RRULE with UNTIL clause for the original series
    let original_rrule = existing_event
        .rrule
        .clone()
        .unwrap_or_else(|| "FREQ=WEEKLY".to_string());
    let parts: Vec<&str> = original_rrule
        .split(';')
        .filter(|part| !part.starts_with("UNTIL=") && !part.starts_with("COUNT="))
        .collect();

    existing_event.rrule = Some(format!(
        "{};UNTIL={}",
        parts.join(";"),
        utc_until.format("%Y%m%dT%H%M%SZ")
    ));
    println!(
        "🔄 this_and_future: Updated original series RRULE: {:?}",
        existing_event.rrule
    );

    // Step 2: Create a new series starting from the occurrence date with updated properties
    let new_series_uid = format!("series-{}", uuid::Uuid::new_v4());

    // Update the new series with new properties
    new_series.uid = new_series_uid.clone();
    new_series.dtstart = start_datetime;
    new_series.dtend = Some(end_datetime);
    new_series.dtstart_tzid = Some(request.timezone.clone());
    new_series.dtend_tzid = Some(request.timezone.clone());
    new_series.summary = if request.title.trim().is_empty() {
        None
    } else {
        Some(request.title.clone())
    };
    new_series.description = if request.description.trim().is_empty() {
        None
    } else {
        Some(request.description.clone())
    };
    new_series.location = if request.location.trim().is_empty() {
        None
    } else {
        Some(request.location.clone())
    };

    new_series.status = Some(match request.status.to_lowercase().as_str() {
        "tentative" => EventStatus::Tentative,
        "cancelled" => EventStatus::Cancelled,
        _ => EventStatus::Confirmed,
    });

    new_series.class = Some(match request.class.to_lowercase().as_str() {
        "private" => EventClass::Private,
        "confidential" => EventClass::Confidential,
        _ => EventClass::Public,
    });

    new_series.priority = request.priority;

    // Update timestamps
    let now = chrono::Utc::now();
    let now_naive = now.naive_utc();
    new_series.dtstamp = now;
    new_series.created = Some(now_naive);
    new_series.last_modified = Some(now_naive);
    new_series.href = None; // Will be set when created

    println!(
        "🔄 this_and_future: Creating new series with UID: {}",
        new_series_uid
    );
    println!(
        "🔄 this_and_future: New series RRULE: {:?}",
        new_series.rrule
    );

    // Create the new series on CalDAV server
    client
        .create_event(calendar_path, &new_series)
        .await
        .map_err(|e| ApiError::Internal(format!("Failed to create new series: {}", e)))?;

    println!("✅ this_and_future: Created new series successfully");

    // Return the original event (with UNTIL added) - it will be updated by the main handler
    Ok((existing_event.clone(), 2)) // 2 operations: updated original + created new series
}

/// Update only a single occurrence (create an exception)
async fn update_single_occurrence(
    existing_event: &mut VEvent,
    request: &UpdateEventSeriesRequest,
    start_datetime: chrono::NaiveDateTime,
    end_datetime: chrono::NaiveDateTime,
    client: &CalDAVClient,
    calendar_path: &str,
    _original_event_href: &str,
) -> Result<(VEvent, u32), ApiError> {
    // For RFC 5545 compliant single occurrence updates, we need to:
    // 1. Add EXDATE to the original series to exclude this occurrence
    // 2. Create a new exception event with RECURRENCE-ID pointing to the original occurrence

    // First, add EXDATE to the original series
    let occurrence_date = request.occurrence_date.as_ref().ok_or_else(|| {
        ApiError::BadRequest(
            "occurrence_date is required for single occurrence updates".to_string(),
        )
    })?;

    // Parse the occurrence date
    let exception_date =
        chrono::NaiveDate::parse_from_str(occurrence_date, "%Y-%m-%d").map_err(|_| {
            ApiError::BadRequest("Invalid occurrence date format. Expected YYYY-MM-DD".to_string())
        })?;

    // Create the EXDATE datetime using the original event's time
    let original_time = existing_event.dtstart.time();
    let exception_datetime = exception_date.and_time(original_time);

    // Add the exception date to the original series
    println!(
        "📝 BEFORE adding EXDATE: existing_event.exdate = {:?}",
        existing_event.exdate
    );
    existing_event.exdate.push(exception_datetime);
    println!(
        "📝 AFTER adding EXDATE: existing_event.exdate = {:?}",
        existing_event.exdate
    );
    println!(
        "🚫 Added EXDATE for single occurrence modification: {}",
        exception_datetime.format("%Y-%m-%d %H:%M:%S")
    );

    // Create exception event by cloning the existing event to preserve all metadata
    let mut exception_event = existing_event.clone();

    // Give the exception event a unique UID (required for CalDAV)
    exception_event.uid = format!("exception-{}", uuid::Uuid::new_v4());

    // Update the modified properties from the request
    exception_event.dtstart = start_datetime;
    exception_event.dtend = Some(end_datetime);
    exception_event.dtstart_tzid = Some(request.timezone.clone());
    exception_event.dtend_tzid = Some(request.timezone.clone());
    exception_event.summary = if request.title.trim().is_empty() {
        existing_event.summary.clone() // Keep original if empty
    } else {
        Some(request.title.clone())
    };
    exception_event.description = if request.description.trim().is_empty() {
        existing_event.description.clone() // Keep original if empty
    } else {
        Some(request.description.clone())
    };
    exception_event.location = if request.location.trim().is_empty() {
        existing_event.location.clone() // Keep original if empty
    } else {
        Some(request.location.clone())
    };

    exception_event.status = Some(match request.status.to_lowercase().as_str() {
        "tentative" => EventStatus::Tentative,
        "cancelled" => EventStatus::Cancelled,
        _ => EventStatus::Confirmed,
    });

    exception_event.class = Some(match request.class.to_lowercase().as_str() {
        "private" => EventClass::Private,
        "confidential" => EventClass::Confidential,
        _ => EventClass::Public,
    });

    exception_event.priority = request.priority;

    // Update timestamps for the exception event
    let now = chrono::Utc::now();
    let now_naive = now.naive_utc();
    exception_event.dtstamp = now;
    exception_event.last_modified = Some(now_naive);
    // Keep original created timestamp to preserve event history

    // Set RECURRENCE-ID to point to the original occurrence
    // exception_event.recurrence_id = Some(exception_utc);

    // Remove any recurrence rules from the exception (it's a single event)
    exception_event.rrule = None;
    exception_event.rdate.clear();
    exception_event.exdate.clear();

    // Set calendar path for the exception event
    exception_event.calendar_path = Some(calendar_path.to_string());

    println!(
        "✨ Created exception event with RECURRENCE-ID: {}",
        exception_datetime.format("%Y-%m-%d %H:%M:%S")
    );

    // Create the exception event as a new event (original series will be updated by main handler)
    client
        .create_event(calendar_path, &exception_event)
        .await
        .map_err(|e| ApiError::Internal(format!("Failed to create exception event: {}", e)))?;

    println!("✅ Created exception event successfully");

    // Return the modified existing event with EXDATE for the main handler to update on CalDAV
    Ok((existing_event.clone(), 1)) // 1 occurrence modified (via exception)
}

/// Delete the entire series
async fn delete_entire_series(
    client: &CalDAVClient,
    request: &DeleteEventSeriesRequest,
) -> Result<u32, ApiError> {
    // Simply delete the entire event from the CalDAV server
    client
        .delete_event(&request.calendar_path, &request.event_href)
        .await
        .map_err(|e| ApiError::Internal(format!("Failed to delete event series: {}", e)))?;

    println!("🗑️ Entire series deleted: {}", request.series_uid);
    Ok(1) // 1 series deleted (affects all occurrences)
}

/// Delete this occurrence and all future occurrences (modify RRULE with UNTIL)
async fn delete_this_and_future(
    client: &CalDAVClient,
    request: &DeleteEventSeriesRequest,
) -> Result<u32, ApiError> {
    // Fetch the existing event to modify its RRULE
    let event_uid = request.series_uid.clone();
    let existing_event = client
        .fetch_event_by_uid(&request.calendar_path, &event_uid)
        .await
        .map_err(|e| ApiError::Internal(format!("Failed to fetch event for modification: {}", e)))?
        .ok_or_else(|| {
            ApiError::NotFound(format!("Event series with UID '{}' not found", event_uid))
        })?;

    // If no occurrence_date is provided, delete the entire series
    let Some(occurrence_date) = &request.occurrence_date else {
        return delete_entire_series(client, request).await;
    };

    // Parse occurrence date to set as UNTIL for the RRULE
    let until_date =
        chrono::NaiveDate::parse_from_str(occurrence_date, "%Y-%m-%d").map_err(|_| {
            ApiError::BadRequest("Invalid occurrence date format. Expected YYYY-MM-DD".to_string())
        })?;

    // Set UNTIL to the day before the occurrence to exclude it and all future occurrences
    let until_datetime = until_date
        .pred_opt()
        .ok_or_else(|| {
            ApiError::BadRequest("Cannot delete from the first possible date".to_string())
        })?
        .and_hms_opt(23, 59, 59)
        .ok_or_else(|| ApiError::BadRequest("Invalid date calculation".to_string()))?;
    let utc_until = chrono::Utc.from_utc_datetime(&until_datetime);

    // Modify the existing event's RRULE
    let mut updated_event = existing_event;
    if let Some(rrule) = &updated_event.rrule {
        // Remove existing UNTIL or COUNT if present and add new UNTIL
        let parts: Vec<&str> = rrule
            .split(';')
            .filter(|part| !part.starts_with("UNTIL=") && !part.starts_with("COUNT="))
            .collect();

        updated_event.rrule = Some(format!(
            "{};UNTIL={}",
            parts.join(";"),
            utc_until.format("%Y%m%dT%H%M%SZ")
        ));
    }

    // Update the event on the CalDAV server
    client
        .update_event(&request.calendar_path, &updated_event, &request.event_href)
        .await
        .map_err(|e| {
            ApiError::Internal(format!("Failed to update event series for deletion: {}", e))
        })?;

    println!(
        "🗑️ Series modified with UNTIL for this_and_future deletion: {}",
        utc_until.format("%Y-%m-%d")
    );
    Ok(1) // 1 series modified
}

/// Delete only a single occurrence (add EXDATE)
async fn delete_single_occurrence(
    client: &CalDAVClient,
    request: &DeleteEventSeriesRequest,
) -> Result<u32, ApiError> {
    // Fetch the existing event to add EXDATE
    let event_uid = request.series_uid.clone();
    let existing_event = client
        .fetch_event_by_uid(&request.calendar_path, &event_uid)
        .await
        .map_err(|e| ApiError::Internal(format!("Failed to fetch event for modification: {}", e)))?
        .ok_or_else(|| {
            ApiError::NotFound(format!("Event series with UID '{}' not found", event_uid))
        })?;

    // If no occurrence_date is provided, cannot delete single occurrence
    let Some(occurrence_date) = &request.occurrence_date else {
        return Err(ApiError::BadRequest(
            "occurrence_date is required for single occurrence deletion".to_string(),
        ));
    };

    // Parse occurrence date
    let exception_date =
        chrono::NaiveDate::parse_from_str(occurrence_date, "%Y-%m-%d").map_err(|_| {
            ApiError::BadRequest("Invalid occurrence date format. Expected YYYY-MM-DD".to_string())
        })?;

    // Create the EXDATE datetime (use the same time as the original event)
    let original_time = existing_event.dtstart.time();
    let exception_datetime = exception_date.and_time(original_time);

    // Add the exception date to the event's EXDATE list
    let mut updated_event = existing_event;
    updated_event.exdate.push(exception_datetime);

    println!(
        "🗑️ Added EXDATE for single occurrence deletion: {}",
        exception_datetime.format("%Y%m%dT%H%M%S")
    );

    // Update the event on the CalDAV server
    client
        .update_event(&request.calendar_path, &updated_event, &request.event_href)
        .await
        .map_err(|e| {
            ApiError::Internal(format!(
                "Failed to update event series for single deletion: {}",
                e
            ))
        })?;

    Ok(1) // 1 occurrence excluded
}
