//! Event GraphQL types
//!
//! Types for the event audit trail system.

use async_graphql::{ComplexObject, Context, Enum, Result, SimpleObject};
use chrono::{DateTime, Utc};
use serde_json::Value as JsonValue;
use uuid::Uuid;

use crate::db::Database;
use crate::models::{Event, EventType, TeamProfile, CustomerProfile};

use super::{TeamProfileType, CustomerProfileType, ProfileUnion};

// ==================== EVENT TYPE ENUM ====================

/// Event type enum for GraphQL
/// Mirrors the EventType enum from models but exposed to GraphQL
#[derive(Enum, Copy, Clone, Eq, PartialEq)]
pub enum EventTypeEnum {
    // Customer events
    CustomerCreated,
    CustomerUpdated,
    CustomerDeleted,
    CustomerStatusChanged,
    CustomerAddressCreated,
    CustomerAddressUpdated,
    CustomerAddressDeleted,
    CustomerContactCreated,
    CustomerContactUpdated,
    CustomerContactDeleted,

    // Account events
    AccountCreated,
    AccountUpdated,
    AccountDeleted,
    AccountStatusChanged,
    AccountAddressCreated,
    AccountAddressUpdated,
    AccountAddressDeleted,
    AccountAddressPrimaryChanged,
    AccountContactCreated,
    AccountContactUpdated,
    AccountContactDeleted,
    AccountContactPrimaryChanged,

    // Service events
    ServiceCreated,
    ServiceUpdated,
    ServiceDeleted,
    ServiceStatusChanged,
    ServiceAssigned,
    ServiceUnassigned,
    ServiceRescheduled,

    // Project events
    ProjectCreated,
    ProjectUpdated,
    ProjectDeleted,
    ProjectStatusChanged,
    ProjectAssigned,
    ProjectUnassigned,
    ProjectRescheduled,
    ProjectAmountChanged,

    // Schedule events
    ScheduleCreated,
    ScheduleUpdated,
    ScheduleDeleted,
    ScheduleFrequencyChanged,

    // Session events
    ServiceSessionStarted,
    ServiceSessionEnded,
    ServiceSessionReverted,
    ProjectSessionStarted,
    ProjectSessionEnded,
    ProjectSessionReverted,

    // Session media events
    SessionNoteCreated,
    SessionNoteUpdated,
    SessionNoteDeleted,
    SessionImageUploaded,
    SessionImageUpdated,
    SessionImageDeleted,
    SessionVideoUploaded,
    SessionVideoUpdated,
    SessionVideoDeleted,
    SessionMediaInternalFlagged,

    // Task events
    ServiceTaskCompleted,
    ServiceTaskUncompleted,
    ProjectTaskCompleted,
    ProjectTaskUncompleted,

    // Service scope events
    ServiceScopeCreated,
    ServiceScopeUpdated,
    ServiceScopeDeleted,
    ServiceScopeActivated,
    ServiceScopeDeactivated,
    ServiceScopeAreaCreated,
    ServiceScopeAreaUpdated,
    ServiceScopeAreaDeleted,
    ServiceScopeTaskCreated,
    ServiceScopeTaskUpdated,
    ServiceScopeTaskDeleted,

    // Project scope events
    ProjectScopeCreated,
    ProjectScopeUpdated,
    ProjectScopeDeleted,
    ProjectScopeActivated,
    ProjectScopeDeactivated,
    ProjectScopeCategoryCreated,
    ProjectScopeCategoryUpdated,
    ProjectScopeCategoryDeleted,
    ProjectScopeTaskCreated,
    ProjectScopeTaskUpdated,
    ProjectScopeTaskDeleted,

    // Scope template events
    ScopeTemplateCreated,
    ScopeTemplateUpdated,
    ScopeTemplateDeleted,
    ScopeTemplateActivated,
    ScopeTemplateDeactivated,
    ScopeTemplateInstantiated,

    // Profile events
    TeamProfileCreated,
    TeamProfileUpdated,
    TeamProfileDeleted,
    TeamProfileRoleChanged,
    TeamProfileStatusChanged,
    CustomerProfileCreated,
    CustomerProfileUpdated,
    CustomerProfileDeleted,
    CustomerProfileStatusChanged,
    CustomerProfileAccessGranted,
    CustomerProfileAccessRevoked,

    // Financial events
    LaborCreated,
    LaborUpdated,
    LaborDeleted,
    LaborRateChanged,
    RevenueCreated,
    RevenueUpdated,
    RevenueDeleted,
    RevenueAmountChanged,
    InvoiceCreated,
    InvoiceUpdated,
    InvoiceDeleted,
    InvoiceStatusChanged,
    InvoiceSent,
    InvoicePaid,
    InvoiceOverdue,

    // Report events
    ReportCreated,
    ReportUpdated,
    ReportDeleted,
    ReportSubmitted,
    ReportApproved,

    // Conversation events
    ConversationCreated,
    ConversationUpdated,
    ConversationArchived,
    ConversationUnarchived,
    ConversationParticipantAdded,
    ConversationParticipantRemoved,

    // Message events
    MessageSent,
    MessageUpdated,
    MessageDeleted,
    MessageRead,

    // Notification events
    NotificationRuleCreated,
    NotificationRuleUpdated,
    NotificationRuleDeleted,
    NotificationRuleActivated,
    NotificationRuleDeactivated,
    NotificationCreated,
    NotificationSent,
    NotificationRead,
    NotificationFailed,
    NotificationDeliveryAttempted,
    NotificationDeliverySucceeded,
    NotificationDeliveryFailed,

    // System events
    SystemStartup,
    SystemShutdown,
    MonitoringTaskRun,
    MonitoringAlertTriggered,
    BackgroundJobStarted,
    BackgroundJobCompleted,
    BackgroundJobFailed,
}

impl From<EventType> for EventTypeEnum {
    fn from(et: EventType) -> Self {
        match et {
            EventType::CustomerCreated => Self::CustomerCreated,
            EventType::CustomerUpdated => Self::CustomerUpdated,
            EventType::CustomerDeleted => Self::CustomerDeleted,
            EventType::CustomerStatusChanged => Self::CustomerStatusChanged,
            EventType::CustomerAddressCreated => Self::CustomerAddressCreated,
            EventType::CustomerAddressUpdated => Self::CustomerAddressUpdated,
            EventType::CustomerAddressDeleted => Self::CustomerAddressDeleted,
            EventType::CustomerContactCreated => Self::CustomerContactCreated,
            EventType::CustomerContactUpdated => Self::CustomerContactUpdated,
            EventType::CustomerContactDeleted => Self::CustomerContactDeleted,

            EventType::AccountCreated => Self::AccountCreated,
            EventType::AccountUpdated => Self::AccountUpdated,
            EventType::AccountDeleted => Self::AccountDeleted,
            EventType::AccountStatusChanged => Self::AccountStatusChanged,
            EventType::AccountAddressCreated => Self::AccountAddressCreated,
            EventType::AccountAddressUpdated => Self::AccountAddressUpdated,
            EventType::AccountAddressDeleted => Self::AccountAddressDeleted,
            EventType::AccountAddressPrimaryChanged => Self::AccountAddressPrimaryChanged,
            EventType::AccountContactCreated => Self::AccountContactCreated,
            EventType::AccountContactUpdated => Self::AccountContactUpdated,
            EventType::AccountContactDeleted => Self::AccountContactDeleted,
            EventType::AccountContactPrimaryChanged => Self::AccountContactPrimaryChanged,

            EventType::ServiceCreated => Self::ServiceCreated,
            EventType::ServiceUpdated => Self::ServiceUpdated,
            EventType::ServiceDeleted => Self::ServiceDeleted,
            EventType::ServiceStatusChanged => Self::ServiceStatusChanged,
            EventType::ServiceAssigned => Self::ServiceAssigned,
            EventType::ServiceUnassigned => Self::ServiceUnassigned,
            EventType::ServiceRescheduled => Self::ServiceRescheduled,

            EventType::ProjectCreated => Self::ProjectCreated,
            EventType::ProjectUpdated => Self::ProjectUpdated,
            EventType::ProjectDeleted => Self::ProjectDeleted,
            EventType::ProjectStatusChanged => Self::ProjectStatusChanged,
            EventType::ProjectAssigned => Self::ProjectAssigned,
            EventType::ProjectUnassigned => Self::ProjectUnassigned,
            EventType::ProjectRescheduled => Self::ProjectRescheduled,
            EventType::ProjectAmountChanged => Self::ProjectAmountChanged,

            EventType::ScheduleCreated => Self::ScheduleCreated,
            EventType::ScheduleUpdated => Self::ScheduleUpdated,
            EventType::ScheduleDeleted => Self::ScheduleDeleted,
            EventType::ScheduleFrequencyChanged => Self::ScheduleFrequencyChanged,

            EventType::ServiceSessionStarted => Self::ServiceSessionStarted,
            EventType::ServiceSessionEnded => Self::ServiceSessionEnded,
            EventType::ServiceSessionReverted => Self::ServiceSessionReverted,
            EventType::ProjectSessionStarted => Self::ProjectSessionStarted,
            EventType::ProjectSessionEnded => Self::ProjectSessionEnded,
            EventType::ProjectSessionReverted => Self::ProjectSessionReverted,

            EventType::SessionNoteCreated => Self::SessionNoteCreated,
            EventType::SessionNoteUpdated => Self::SessionNoteUpdated,
            EventType::SessionNoteDeleted => Self::SessionNoteDeleted,
            EventType::SessionImageUploaded => Self::SessionImageUploaded,
            EventType::SessionImageUpdated => Self::SessionImageUpdated,
            EventType::SessionImageDeleted => Self::SessionImageDeleted,
            EventType::SessionVideoUploaded => Self::SessionVideoUploaded,
            EventType::SessionVideoUpdated => Self::SessionVideoUpdated,
            EventType::SessionVideoDeleted => Self::SessionVideoDeleted,
            EventType::SessionMediaInternalFlagged => Self::SessionMediaInternalFlagged,

            EventType::ServiceTaskCompleted => Self::ServiceTaskCompleted,
            EventType::ServiceTaskUncompleted => Self::ServiceTaskUncompleted,
            EventType::ProjectTaskCompleted => Self::ProjectTaskCompleted,
            EventType::ProjectTaskUncompleted => Self::ProjectTaskUncompleted,

            EventType::ServiceScopeCreated => Self::ServiceScopeCreated,
            EventType::ServiceScopeUpdated => Self::ServiceScopeUpdated,
            EventType::ServiceScopeDeleted => Self::ServiceScopeDeleted,
            EventType::ServiceScopeActivated => Self::ServiceScopeActivated,
            EventType::ServiceScopeDeactivated => Self::ServiceScopeDeactivated,
            EventType::ServiceScopeAreaCreated => Self::ServiceScopeAreaCreated,
            EventType::ServiceScopeAreaUpdated => Self::ServiceScopeAreaUpdated,
            EventType::ServiceScopeAreaDeleted => Self::ServiceScopeAreaDeleted,
            EventType::ServiceScopeTaskCreated => Self::ServiceScopeTaskCreated,
            EventType::ServiceScopeTaskUpdated => Self::ServiceScopeTaskUpdated,
            EventType::ServiceScopeTaskDeleted => Self::ServiceScopeTaskDeleted,

            EventType::ProjectScopeCreated => Self::ProjectScopeCreated,
            EventType::ProjectScopeUpdated => Self::ProjectScopeUpdated,
            EventType::ProjectScopeDeleted => Self::ProjectScopeDeleted,
            EventType::ProjectScopeActivated => Self::ProjectScopeActivated,
            EventType::ProjectScopeDeactivated => Self::ProjectScopeDeactivated,
            EventType::ProjectScopeCategoryCreated => Self::ProjectScopeCategoryCreated,
            EventType::ProjectScopeCategoryUpdated => Self::ProjectScopeCategoryUpdated,
            EventType::ProjectScopeCategoryDeleted => Self::ProjectScopeCategoryDeleted,
            EventType::ProjectScopeTaskCreated => Self::ProjectScopeTaskCreated,
            EventType::ProjectScopeTaskUpdated => Self::ProjectScopeTaskUpdated,
            EventType::ProjectScopeTaskDeleted => Self::ProjectScopeTaskDeleted,

            EventType::ScopeTemplateCreated => Self::ScopeTemplateCreated,
            EventType::ScopeTemplateUpdated => Self::ScopeTemplateUpdated,
            EventType::ScopeTemplateDeleted => Self::ScopeTemplateDeleted,
            EventType::ScopeTemplateActivated => Self::ScopeTemplateActivated,
            EventType::ScopeTemplateDeactivated => Self::ScopeTemplateDeactivated,
            EventType::ScopeTemplateInstantiated => Self::ScopeTemplateInstantiated,

            EventType::TeamProfileCreated => Self::TeamProfileCreated,
            EventType::TeamProfileUpdated => Self::TeamProfileUpdated,
            EventType::TeamProfileDeleted => Self::TeamProfileDeleted,
            EventType::TeamProfileRoleChanged => Self::TeamProfileRoleChanged,
            EventType::TeamProfileStatusChanged => Self::TeamProfileStatusChanged,
            EventType::CustomerProfileCreated => Self::CustomerProfileCreated,
            EventType::CustomerProfileUpdated => Self::CustomerProfileUpdated,
            EventType::CustomerProfileDeleted => Self::CustomerProfileDeleted,
            EventType::CustomerProfileStatusChanged => Self::CustomerProfileStatusChanged,
            EventType::CustomerProfileAccessGranted => Self::CustomerProfileAccessGranted,
            EventType::CustomerProfileAccessRevoked => Self::CustomerProfileAccessRevoked,

            EventType::LaborCreated => Self::LaborCreated,
            EventType::LaborUpdated => Self::LaborUpdated,
            EventType::LaborDeleted => Self::LaborDeleted,
            EventType::LaborRateChanged => Self::LaborRateChanged,
            EventType::RevenueCreated => Self::RevenueCreated,
            EventType::RevenueUpdated => Self::RevenueUpdated,
            EventType::RevenueDeleted => Self::RevenueDeleted,
            EventType::RevenueAmountChanged => Self::RevenueAmountChanged,
            EventType::InvoiceCreated => Self::InvoiceCreated,
            EventType::InvoiceUpdated => Self::InvoiceUpdated,
            EventType::InvoiceDeleted => Self::InvoiceDeleted,
            EventType::InvoiceStatusChanged => Self::InvoiceStatusChanged,
            EventType::InvoiceSent => Self::InvoiceSent,
            EventType::InvoicePaid => Self::InvoicePaid,
            EventType::InvoiceOverdue => Self::InvoiceOverdue,

            EventType::ReportCreated => Self::ReportCreated,
            EventType::ReportUpdated => Self::ReportUpdated,
            EventType::ReportDeleted => Self::ReportDeleted,
            EventType::ReportSubmitted => Self::ReportSubmitted,
            EventType::ReportApproved => Self::ReportApproved,

            EventType::ConversationCreated => Self::ConversationCreated,
            EventType::ConversationUpdated => Self::ConversationUpdated,
            EventType::ConversationArchived => Self::ConversationArchived,
            EventType::ConversationUnarchived => Self::ConversationUnarchived,
            EventType::ConversationParticipantAdded => Self::ConversationParticipantAdded,
            EventType::ConversationParticipantRemoved => Self::ConversationParticipantRemoved,

            EventType::MessageSent => Self::MessageSent,
            EventType::MessageUpdated => Self::MessageUpdated,
            EventType::MessageDeleted => Self::MessageDeleted,
            EventType::MessageRead => Self::MessageRead,

            EventType::NotificationRuleCreated => Self::NotificationRuleCreated,
            EventType::NotificationRuleUpdated => Self::NotificationRuleUpdated,
            EventType::NotificationRuleDeleted => Self::NotificationRuleDeleted,
            EventType::NotificationRuleActivated => Self::NotificationRuleActivated,
            EventType::NotificationRuleDeactivated => Self::NotificationRuleDeactivated,
            EventType::NotificationCreated => Self::NotificationCreated,
            EventType::NotificationSent => Self::NotificationSent,
            EventType::NotificationRead => Self::NotificationRead,
            EventType::NotificationFailed => Self::NotificationFailed,
            EventType::NotificationDeliveryAttempted => Self::NotificationDeliveryAttempted,
            EventType::NotificationDeliverySucceeded => Self::NotificationDeliverySucceeded,
            EventType::NotificationDeliveryFailed => Self::NotificationDeliveryFailed,

            EventType::SystemStartup => Self::SystemStartup,
            EventType::SystemShutdown => Self::SystemShutdown,
            EventType::MonitoringTaskRun => Self::MonitoringTaskRun,
            EventType::MonitoringAlertTriggered => Self::MonitoringAlertTriggered,
            EventType::BackgroundJobStarted => Self::BackgroundJobStarted,
            EventType::BackgroundJobCompleted => Self::BackgroundJobCompleted,
            EventType::BackgroundJobFailed => Self::BackgroundJobFailed,
        }
    }
}

// ==================== EVENT TYPE ====================

/// Audit trail event
#[derive(SimpleObject)]
#[graphql(complex)]
pub struct EventType_ {
    pub id: Uuid,
    pub event_type: EventTypeEnum,
    /// Entity type (e.g., "customer", "service", "project")
    pub entity_type: String,
    pub entity_id: Uuid,
    /// Actor type ("team_profile", "customer_profile", or "system")
    pub actor_type: Option<String>,
    pub actor_id: Option<Uuid>,
    /// Additional context (old_status, new_status, changed_fields, etc.)
    pub metadata: Option<JsonValue>,
    /// When the event occurred (business timestamp)
    pub timestamp: DateTime<Utc>,
    pub created_at: DateTime<Utc>,
}

#[ComplexObject]
impl EventType_ {
    /// The actor's profile (polymorphic - team or customer)
    async fn actor_profile(&self, ctx: &Context<'_>) -> Result<Option<ProfileUnion>> {
        let Some(ref actor_type) = self.actor_type else {
            return Ok(None);
        };
        let Some(actor_id) = self.actor_id else {
            return Ok(None);
        };

        // System actors don't have profiles
        if actor_type == "system" {
            return Ok(None);
        }

        let db = ctx.data::<Database>()?;
        let pool = db.pool().await;

        match actor_type.as_str() {
            "team_profile" => {
                let profile: Option<TeamProfile> = sqlx::query_as(
                    r#"
                    SELECT id, created_at, updated_at, first_name, last_name, phone, email, role, status, notes
                    FROM team_profiles
                    WHERE id = $1
                    "#,
                )
                .bind(actor_id)
                .fetch_optional(&*pool)
                .await?;

                Ok(profile.map(|p| ProfileUnion::TeamProfile(TeamProfileType::from(p))))
            }
            "customer_profile" => {
                let profile: Option<CustomerProfile> = sqlx::query_as(
                    r#"
                    SELECT id, created_at, updated_at, customer_id, first_name, last_name, email, phone, status, notes, is_primary
                    FROM customer_profiles
                    WHERE id = $1
                    "#,
                )
                .bind(actor_id)
                .fetch_optional(&*pool)
                .await?;

                Ok(profile.map(|p| ProfileUnion::CustomerProfile(CustomerProfileType::from(p))))
            }
            _ => Ok(None),
        }
    }

    /// Human-readable description of the event
    async fn description(&self) -> String {
        format_event_description(&self.event_type, &self.entity_type, self.metadata.as_ref())
    }
}

impl From<Event> for EventType_ {
    fn from(e: Event) -> Self {
        Self {
            id: e.id,
            event_type: e.event_type.into(),
            entity_type: e.entity_type,
            entity_id: e.entity_id,
            actor_type: e.actor_type,
            actor_id: e.actor_id,
            metadata: e.metadata,
            timestamp: e.timestamp,
            created_at: e.created_at,
        }
    }
}

/// Format a human-readable description for an event
fn format_event_description(
    event_type: &EventTypeEnum,
    entity_type: &str,
    metadata: Option<&JsonValue>,
) -> String {
    let action = match event_type {
        // Create events
        EventTypeEnum::CustomerCreated
        | EventTypeEnum::AccountCreated
        | EventTypeEnum::ServiceCreated
        | EventTypeEnum::ProjectCreated
        | EventTypeEnum::ScheduleCreated
        | EventTypeEnum::TeamProfileCreated
        | EventTypeEnum::CustomerProfileCreated
        | EventTypeEnum::LaborCreated
        | EventTypeEnum::RevenueCreated
        | EventTypeEnum::InvoiceCreated
        | EventTypeEnum::ReportCreated
        | EventTypeEnum::ConversationCreated
        | EventTypeEnum::NotificationRuleCreated
        | EventTypeEnum::NotificationCreated => "created",

        // Update events
        EventTypeEnum::CustomerUpdated
        | EventTypeEnum::AccountUpdated
        | EventTypeEnum::ServiceUpdated
        | EventTypeEnum::ProjectUpdated
        | EventTypeEnum::ScheduleUpdated
        | EventTypeEnum::TeamProfileUpdated
        | EventTypeEnum::CustomerProfileUpdated
        | EventTypeEnum::LaborUpdated
        | EventTypeEnum::RevenueUpdated
        | EventTypeEnum::InvoiceUpdated
        | EventTypeEnum::ReportUpdated
        | EventTypeEnum::ConversationUpdated
        | EventTypeEnum::NotificationRuleUpdated
        | EventTypeEnum::MessageUpdated => "updated",

        // Delete events
        EventTypeEnum::CustomerDeleted
        | EventTypeEnum::AccountDeleted
        | EventTypeEnum::ServiceDeleted
        | EventTypeEnum::ProjectDeleted
        | EventTypeEnum::ScheduleDeleted
        | EventTypeEnum::TeamProfileDeleted
        | EventTypeEnum::CustomerProfileDeleted
        | EventTypeEnum::LaborDeleted
        | EventTypeEnum::RevenueDeleted
        | EventTypeEnum::InvoiceDeleted
        | EventTypeEnum::ReportDeleted
        | EventTypeEnum::NotificationRuleDeleted
        | EventTypeEnum::MessageDeleted => "deleted",

        // Status changes
        EventTypeEnum::CustomerStatusChanged
        | EventTypeEnum::AccountStatusChanged
        | EventTypeEnum::ServiceStatusChanged
        | EventTypeEnum::ProjectStatusChanged
        | EventTypeEnum::TeamProfileStatusChanged
        | EventTypeEnum::CustomerProfileStatusChanged
        | EventTypeEnum::InvoiceStatusChanged => {
            if let Some(meta) = metadata {
                if let (Some(old), Some(new)) = (
                    meta.get("old_status").and_then(|v| v.as_str()),
                    meta.get("new_status").and_then(|v| v.as_str()),
                ) {
                    return format!("{} status changed from {} to {}", entity_type, old, new);
                }
            }
            "status changed"
        }

        // Session events
        EventTypeEnum::ServiceSessionStarted | EventTypeEnum::ProjectSessionStarted => {
            "session started"
        }
        EventTypeEnum::ServiceSessionEnded | EventTypeEnum::ProjectSessionEnded => "session ended",
        EventTypeEnum::ServiceSessionReverted | EventTypeEnum::ProjectSessionReverted => {
            "session reverted"
        }

        // Task events
        EventTypeEnum::ServiceTaskCompleted | EventTypeEnum::ProjectTaskCompleted => {
            "task completed"
        }
        EventTypeEnum::ServiceTaskUncompleted | EventTypeEnum::ProjectTaskUncompleted => {
            "task uncompleted"
        }

        // Assignment events
        EventTypeEnum::ServiceAssigned | EventTypeEnum::ProjectAssigned => "assigned",
        EventTypeEnum::ServiceUnassigned | EventTypeEnum::ProjectUnassigned => "unassigned",
        EventTypeEnum::ServiceRescheduled | EventTypeEnum::ProjectRescheduled => "rescheduled",

        // Invoice events
        EventTypeEnum::InvoiceSent => "sent",
        EventTypeEnum::InvoicePaid => "paid",
        EventTypeEnum::InvoiceOverdue => "marked overdue",

        // Message events
        EventTypeEnum::MessageSent => "message sent",
        EventTypeEnum::MessageRead => "message read",

        // Notification events
        EventTypeEnum::NotificationSent => "sent",
        EventTypeEnum::NotificationRead => "read",
        EventTypeEnum::NotificationFailed => "failed",

        // Default
        _ => "event occurred",
    };

    format!("{} {}", entity_type, action)
}
