//! VEvent - RFC 5545 compliant calendar event structure

use crate::common::*;
use chrono::{DateTime, Duration, NaiveDateTime, Utc};
use serde::{Deserialize, Serialize};

// ==================== VEVENT COMPONENT ====================

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct VEvent {
    // Required properties
    pub dtstamp: DateTime<Utc>,          // Date-time stamp (DTSTAMP) - REQUIRED (always UTC)
    pub uid: String,                     // Unique identifier (UID) - REQUIRED
    pub dtstart: NaiveDateTime,          // Start date-time (DTSTART) - REQUIRED (local time)
    pub dtstart_tzid: Option<String>,    // Timezone ID for DTSTART (TZID parameter)

    // Optional properties (commonly used)
    pub dtend: Option<NaiveDateTime>,    // End date-time (DTEND) (local time)
    pub dtend_tzid: Option<String>,      // Timezone ID for DTEND (TZID parameter)
    pub duration: Option<Duration>,   // Duration (DURATION) - alternative to DTEND
    pub summary: Option<String>,      // Summary/title (SUMMARY)
    pub description: Option<String>,  // Description (DESCRIPTION)
    pub location: Option<String>,     // Location (LOCATION)

    // Classification and status
    pub class: Option<EventClass>,        // Classification (CLASS)
    pub status: Option<EventStatus>,      // Status (STATUS)
    pub transp: Option<TimeTransparency>, // Time transparency (TRANSP)
    pub priority: Option<u8>,             // Priority 0-9 (PRIORITY)

    // People and organization
    pub organizer: Option<CalendarUser>, // Organizer (ORGANIZER)
    pub attendees: Vec<Attendee>,        // Attendees (ATTENDEE)
    pub contact: Option<String>,         // Contact information (CONTACT)

    // Categorization and relationships
    pub categories: Vec<String>,    // Categories (CATEGORIES)
    pub comment: Option<String>,    // Comment (COMMENT)
    pub resources: Vec<String>,     // Resources (RESOURCES)
    pub related_to: Option<String>, // Related component (RELATED-TO)
    pub url: Option<String>,        // URL (URL)

    // Geographical
    pub geo: Option<GeographicPosition>, // Geographic position (GEO)

    // Versioning and modification
    pub sequence: Option<u32>,                // Sequence number (SEQUENCE)
    pub created: Option<NaiveDateTime>,       // Creation time (CREATED) (local time)
    pub created_tzid: Option<String>,         // Timezone ID for CREATED
    pub last_modified: Option<NaiveDateTime>, // Last modified (LAST-MODIFIED) (local time)  
    pub last_modified_tzid: Option<String>,   // Timezone ID for LAST-MODIFIED

    // Recurrence
    pub rrule: Option<String>,                    // Recurrence rule (RRULE)
    pub rdate: Vec<NaiveDateTime>,                // Recurrence dates (RDATE) (local time)
    pub rdate_tzid: Option<String>,               // Timezone ID for RDATE
    pub exdate: Vec<NaiveDateTime>,               // Exception dates (EXDATE) (local time)
    pub exdate_tzid: Option<String>,              // Timezone ID for EXDATE
    pub recurrence_id: Option<NaiveDateTime>,     // Recurrence ID (RECURRENCE-ID) (local time)
    pub recurrence_id_tzid: Option<String>,       // Timezone ID for RECURRENCE-ID

    // Alarms and attachments
    pub alarms: Vec<VAlarm>,          // VALARM components
    pub attachments: Vec<Attachment>, // Attachments (ATTACH)

    // CalDAV specific (for implementation)
    pub etag: Option<String>,          // ETag for CalDAV
    pub href: Option<String>,          // Href for CalDAV
    pub calendar_path: Option<String>, // Calendar path
    pub all_day: bool,                 // All-day event flag
}

impl VEvent {
    /// Create a new VEvent with required fields (local time)
    pub fn new(uid: String, dtstart: NaiveDateTime) -> Self {
        Self {
            dtstamp: Utc::now(),
            uid,
            dtstart,
            dtstart_tzid: None,
            dtend: None,
            dtend_tzid: None,
            duration: None,
            summary: None,
            description: None,
            location: None,
            class: None,
            status: None,
            transp: None,
            priority: None,
            organizer: None,
            attendees: Vec::new(),
            contact: None,
            categories: Vec::new(),
            comment: None,
            resources: Vec::new(),
            related_to: None,
            url: None,
            geo: None,
            sequence: None,
            created: Some(chrono::Local::now().naive_local()),
            created_tzid: None,
            last_modified: Some(chrono::Local::now().naive_local()),
            last_modified_tzid: None,
            rrule: None,
            rdate: Vec::new(),
            rdate_tzid: None,
            exdate: Vec::new(),
            exdate_tzid: None,
            recurrence_id: None,
            recurrence_id_tzid: None,
            alarms: Vec::new(),
            attachments: Vec::new(),
            etag: None,
            href: None,
            calendar_path: None,
            all_day: false,
        }
    }

    /// Helper method to get effective end time (dtend or dtstart + duration)
    pub fn get_end_time(&self) -> NaiveDateTime {
        if let Some(dtend) = self.dtend {
            dtend
        } else if let Some(duration) = self.duration {
            self.dtstart + duration
        } else {
            // Default to 1 hour if no end or duration specified
            self.dtstart + Duration::hours(1)
        }
    }

    /// Helper method to get event duration
    pub fn get_duration(&self) -> Duration {
        if let Some(duration) = self.duration {
            duration
        } else if let Some(dtend) = self.dtend {
            dtend - self.dtstart
        } else {
            Duration::hours(1) // Default duration
        }
    }

    /// Helper method to get display title (summary or "Untitled Event")
    pub fn get_title(&self) -> String {
        self.summary
            .clone()
            .unwrap_or_else(|| "Untitled Event".to_string())
    }

    /// Helper method to get start date for UI compatibility
    pub fn get_date(&self) -> chrono::NaiveDate {
        self.dtstart.date()
    }

    /// Check if event is recurring
    pub fn is_recurring(&self) -> bool {
        self.rrule.is_some()
    }

    /// Check if this is an exception to a recurring series
    pub fn is_exception(&self) -> bool {
        self.recurrence_id.is_some()
    }

    /// Get display string for status
    pub fn get_status_display(&self) -> &'static str {
        match &self.status {
            Some(EventStatus::Tentative) => "Tentative",
            Some(EventStatus::Confirmed) => "Confirmed",
            Some(EventStatus::Cancelled) => "Cancelled",
            None => "Confirmed", // Default
        }
    }

    /// Get display string for class
    pub fn get_class_display(&self) -> &'static str {
        match &self.class {
            Some(EventClass::Public) => "Public",
            Some(EventClass::Private) => "Private",
            Some(EventClass::Confidential) => "Confidential",
            None => "Public", // Default
        }
    }

    /// Get display string for priority
    pub fn get_priority_display(&self) -> String {
        match self.priority {
            None => "Not set".to_string(),
            Some(0) => "Undefined".to_string(),
            Some(1) => "High".to_string(),
            Some(p) if p <= 4 => "High".to_string(),
            Some(5) => "Medium".to_string(),
            Some(p) if p <= 8 => "Low".to_string(),
            Some(9) => "Low".to_string(),
            Some(p) => format!("Priority {}", p),
        }
    }
}
