use chrono::{DateTime, NaiveDate, Utc};
use serde::{Deserialize, Serialize};
use sqlx::FromRow;
use uuid::Uuid;
use crate::utils::datetime::DateTimeWithTimezone;
use crate::utils::sanitize::{SanitizeOutput, sanitize_string, sanitize_option_string};

pub mod media;

#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
pub struct User {
    pub id: Uuid,
    pub username: String,                    // NOT NULL
    pub email: Option<String>,               // nullable
    pub name: Option<String>,                // nullable  
    pub avatar_url: Option<String>,          // nullable
    pub role: Option<String>,                // nullable (has default)
    pub verified: Option<bool>,              // nullable (has default)
    pub created_at: Option<DateTime<Utc>>,   // nullable (has default)
    pub updated_at: Option<DateTime<Utc>>,   // nullable (has default)
}

#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
pub struct Member {
    pub id: Uuid,
    pub first_name: String,
    pub last_name: String,
    pub email: Option<String>,
    pub phone: Option<String>,
    pub address: Option<String>,
    pub date_of_birth: Option<NaiveDate>,
    pub membership_status: Option<String>,
    pub join_date: Option<NaiveDate>,
    pub baptism_date: Option<NaiveDate>,
    pub notes: Option<String>,
    pub emergency_contact_name: Option<String>,
    pub emergency_contact_phone: Option<String>,
    pub created_at: Option<DateTime<Utc>>,
    pub updated_at: Option<DateTime<Utc>>,
}

#[derive(Debug, Deserialize)]
pub struct CreateMemberRequest {
    pub first_name: String,
    pub last_name: String,
    pub email: Option<String>,
    pub phone: Option<String>,
    pub address: Option<String>,
    pub date_of_birth: Option<NaiveDate>,
    pub membership_status: Option<String>,
    pub join_date: Option<NaiveDate>,
    pub baptism_date: Option<NaiveDate>,
    pub notes: Option<String>,
    pub emergency_contact_name: Option<String>,
    pub emergency_contact_phone: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
pub struct Bulletin {
    pub id: Uuid,
    pub title: String,
    pub date: NaiveDate,
    pub url: Option<String>,
    pub pdf_url: Option<String>,
    pub is_active: Option<bool>,
    pub pdf_file: Option<String>,
    pub sabbath_school: Option<String>,
    pub divine_worship: Option<String>,
    pub scripture_reading: Option<String>,
    pub sunset: Option<String>,
    pub cover_image: Option<String>,
    pub pdf_path: Option<String>,
    pub created_at: Option<DateTime<Utc>>,
    pub updated_at: Option<DateTime<Utc>>,
}

#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
pub struct Event {
    pub id: Uuid,
    pub title: String,
    pub description: String,
    pub start_time: DateTime<Utc>,
    pub end_time: DateTime<Utc>,
    pub location: String,
    pub location_url: Option<String>,
    pub image: Option<String>,
    pub thumbnail: Option<String>,
    pub category: String,
    pub is_featured: Option<bool>,
    pub recurring_type: Option<String>,
    pub approved_from: Option<String>,
    pub created_at: Option<DateTime<Utc>>,
    pub updated_at: Option<DateTime<Utc>>,
}

#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
pub struct PendingEvent {
    pub id: Uuid,
    pub title: String,                       // NOT NULL
    pub description: String,                 // NOT NULL
    pub start_time: DateTime<Utc>,           // NOT NULL
    pub end_time: DateTime<Utc>,             // NOT NULL
    pub location: String,                    // NOT NULL
    pub location_url: Option<String>,        // nullable
    pub image: Option<String>,               // nullable
    pub thumbnail: Option<String>,           // nullable
    pub category: String,                    // NOT NULL
    pub is_featured: Option<bool>,           // nullable (has default)
    pub recurring_type: Option<String>,      // nullable
    pub approval_status: Option<String>,     // nullable (has default)
    pub submitted_at: Option<DateTime<Utc>>, // nullable (has default)
    pub bulletin_week: String,               // NOT NULL
    pub admin_notes: Option<String>,         // nullable
    pub submitter_email: Option<String>,     // nullable
    pub email_sent: Option<bool>,            // nullable (has default)
    pub pending_email_sent: Option<bool>,    // nullable (has default)
    pub rejection_email_sent: Option<bool>,  // nullable (has default)
    pub approval_email_sent: Option<bool>,   // nullable (has default)
    pub created_at: Option<DateTime<Utc>>,   // nullable (has default)
    pub updated_at: Option<DateTime<Utc>>,   // nullable (has default)
}

#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
pub struct ChurchConfig {
    pub id: Uuid,
    pub church_name: String,
    pub contact_email: String,
    pub contact_phone: Option<String>,
    pub church_address: String,
    pub po_box: Option<String>,
    pub google_maps_url: Option<String>,
    pub about_text: String,
    pub api_keys: Option<serde_json::Value>,
    pub jellyfin_server_url: Option<String>,
    pub brand_color: String,
    pub created_at: Option<DateTime<Utc>>,
    pub updated_at: Option<DateTime<Utc>>,
}

#[derive(Debug, Serialize)]
pub struct ApiResponse<T> {
    pub success: bool,
    pub data: Option<T>,
    pub message: Option<String>,
}

#[derive(Debug, Deserialize)]
pub struct LoginRequest {
    pub username: String,
    pub password: String,
}

#[derive(Debug, Serialize)]
pub struct LoginResponse {
    pub token: String,
    pub user: User,
}

#[derive(Debug, Deserialize)]
pub struct CreateBulletinRequest {
    pub title: String,
    pub date: NaiveDate,
    pub url: Option<String>,
    pub cover_image: Option<String>,
    pub sabbath_school: Option<String>,
    pub divine_worship: Option<String>,
    pub scripture_reading: Option<String>,
    pub sunset: Option<String>,
    pub is_active: Option<bool>,
}

#[derive(Debug, Clone, Deserialize)]
pub struct CreateEventRequest {
    pub title: String,
    pub description: String,
    pub start_time: DateTime<Utc>,
    pub end_time: DateTime<Utc>,
    pub location: String,
    pub location_url: Option<String>,
    pub category: String,
    pub is_featured: Option<bool>,
    pub recurring_type: Option<String>,
}

#[derive(Debug, Deserialize)]
pub struct SubmitEventRequest {
    pub title: String,
    pub description: String,
    pub start_time: DateTime<Utc>,
    pub end_time: DateTime<Utc>,
    pub location: String,
    pub location_url: Option<String>,
    pub category: String,
    pub is_featured: Option<bool>,
    pub recurring_type: Option<String>,
    pub bulletin_week: String,
    pub submitter_email: Option<String>,
    pub image: Option<String>,
    pub thumbnail: Option<String>,
}

#[derive(Debug, Serialize)]
pub struct PaginatedResponse<T> {
    pub items: Vec<T>,
    pub total: i64,
    pub page: i32,
    pub per_page: i32,
    pub has_more: bool,
}

#[derive(Debug, Deserialize)]
pub struct PaginationParams {
    pub page: Option<i64>,
    pub per_page: Option<i64>,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct BibleVerse {
    pub id: Uuid,
    pub reference: String,
    pub text: String,
    pub is_active: Option<bool>,
    pub created_at: Option<chrono::DateTime<chrono::Utc>>,
    pub updated_at: Option<chrono::DateTime<chrono::Utc>>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Personnel {
    pub ss_leader: String,
    pub ss_teacher: String,
    pub mission_story: String,
    pub song_leader: String,
    pub announcements: String,
    pub offering: String,
    pub special_music: String,
    pub speaker: String,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct ScheduleData {
    pub date: String,
    pub personnel: Personnel,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct ConferenceData {
    pub date: String,
    pub offering_focus: String,
    pub sunset_tonight: String,
    pub sunset_next_friday: String,
}

#[derive(Debug, Deserialize)]
pub struct DateQuery {
    pub date: Option<String>,
}


// Database model for schedule
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
pub struct Schedule {
    pub id: Uuid,
    pub date: NaiveDate,
    pub song_leader: Option<String>,
    pub ss_teacher: Option<String>,
    pub ss_leader: Option<String>,
    pub mission_story: Option<String>,
    pub special_program: Option<String>,
    pub sermon_speaker: Option<String>,
    pub scripture: Option<String>,
    pub offering: Option<String>,
    pub deacons: Option<String>,
    pub special_music: Option<String>,
    pub childrens_story: Option<String>,
    pub afternoon_program: Option<String>,
    pub created_at: Option<DateTime<Utc>>,
    pub updated_at: Option<DateTime<Utc>>,
}

// Contact form models
#[derive(Debug, Serialize, Deserialize)]
pub struct ContactRequest {
    pub first_name: String,
    pub last_name: String,
    pub email: String,
    pub phone: Option<String>,
    pub message: String,
    pub subject: Option<String>,
}

#[derive(Debug)]
pub struct Contact {
    pub first_name: String,
    pub last_name: String,
    pub email: String,
    pub phone: Option<String>,
    pub message: String,
}

#[derive(Debug)]
pub struct ContactEmail {
    pub first_name: String,
    pub last_name: String,
    pub email: String,
    pub phone: Option<String>,
    pub message: String,
    pub subject: Option<String>,
}

// V2 Contact form models - simplified with just 'name'
#[derive(Debug, Serialize, Deserialize)]
pub struct ContactRequestV2 {
    pub name: String,
    pub email: String,
    pub phone: Option<String>,
    pub message: String,
    pub subject: Option<String>,
}

// V2 API Models with enhanced timezone handling
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EventV2 {
    pub id: Uuid,
    pub title: String,
    pub description: String,
    pub start_time: DateTimeWithTimezone,
    pub end_time: DateTimeWithTimezone,
    pub location: String,
    pub location_url: Option<String>,
    pub image: Option<String>,
    pub thumbnail: Option<String>,
    pub category: String,
    pub is_featured: Option<bool>,
    pub recurring_type: Option<String>,
    pub timezone: String,
    pub approved_from: Option<String>,
    pub created_at: Option<DateTimeWithTimezone>,
    pub updated_at: Option<DateTimeWithTimezone>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PendingEventV2 {
    pub id: Uuid,
    pub title: String,
    pub description: String,
    pub start_time: DateTimeWithTimezone,
    pub end_time: DateTimeWithTimezone,
    pub location: String,
    pub location_url: Option<String>,
    pub image: Option<String>,
    pub thumbnail: Option<String>,
    pub category: String,
    pub is_featured: Option<bool>,
    pub recurring_type: Option<String>,
    pub timezone: String,
    pub approval_status: Option<String>,
    pub submitted_at: Option<DateTimeWithTimezone>,
    pub bulletin_week: String,
    pub admin_notes: Option<String>,
    pub submitter_email: Option<String>,
    pub email_sent: Option<bool>,
    pub pending_email_sent: Option<bool>,
    pub rejection_email_sent: Option<bool>,
    pub approval_email_sent: Option<bool>,
    pub created_at: Option<DateTimeWithTimezone>,
    pub updated_at: Option<DateTimeWithTimezone>,
}

#[derive(Debug, Deserialize)]
pub struct CreateEventRequestV2 {
    pub title: String,
    pub description: String,
    pub start_time: String,
    pub end_time: String,
    pub location: String,
    pub location_url: Option<String>,
    pub category: String,
    pub is_featured: Option<bool>,
    pub recurring_type: Option<String>,
    pub timezone: Option<String>,
}

#[derive(Debug, Deserialize)]
pub struct SubmitEventRequestV2 {
    pub title: String,
    pub description: String,
    pub start_time: String,
    pub end_time: String,
    pub location: String,
    pub location_url: Option<String>,
    pub category: String,
    pub is_featured: Option<bool>,
    pub recurring_type: Option<String>,
    pub bulletin_week: String,
    pub submitter_email: Option<String>,
    pub timezone: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BulletinV2 {
    pub id: Uuid,
    pub title: String,
    pub date: NaiveDate,
    pub url: Option<String>,
    pub cover_image: Option<String>,
    pub cover_image_url: Option<String>,
    pub pdf_url: Option<String>,
    pub is_active: Option<bool>,
    pub pdf_file: Option<String>,
    pub sabbath_school: Option<String>,
    pub divine_worship: Option<String>,
    pub scripture_reading: Option<String>,
    pub sunset: Option<String>,
    pub pdf_path: Option<String>,
    pub created_at: Option<DateTimeWithTimezone>,
    pub updated_at: Option<DateTimeWithTimezone>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ScheduleV2 {
    pub id: Uuid,
    pub date: NaiveDate,
    pub song_leader: Option<String>,
    pub ss_teacher: Option<String>,
    pub ss_leader: Option<String>,
    pub mission_story: Option<String>,
    pub special_program: Option<String>,
    pub sermon_speaker: Option<String>,
    pub scripture: Option<String>,
    pub offering: Option<String>,
    pub deacons: Option<String>,
    pub special_music: Option<String>,
    pub childrens_story: Option<String>,
    pub afternoon_program: Option<String>,
    pub created_at: Option<DateTimeWithTimezone>,
    pub updated_at: Option<DateTimeWithTimezone>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BibleVerseV2 {
    pub id: Uuid,
    pub reference: String,
    pub text: String,
    pub is_active: Option<bool>,
    pub created_at: Option<DateTimeWithTimezone>,
    pub updated_at: Option<DateTimeWithTimezone>,
}

// SanitizeOutput trait implementations
impl SanitizeOutput for Bulletin {
    fn sanitize_output(mut self) -> Self {
        self.title = sanitize_string(self.title);
        self.sabbath_school = sanitize_option_string(self.sabbath_school);
        self.divine_worship = sanitize_option_string(self.divine_worship);
        self.scripture_reading = sanitize_option_string(self.scripture_reading);
        self.sunset = sanitize_option_string(self.sunset);
        self
    }
}

impl SanitizeOutput for BulletinV2 {
    fn sanitize_output(mut self) -> Self {
        self.title = sanitize_string(self.title);
        self.sabbath_school = sanitize_option_string(self.sabbath_school);
        self.divine_worship = sanitize_option_string(self.divine_worship);
        self.scripture_reading = sanitize_option_string(self.scripture_reading);
        self.sunset = sanitize_option_string(self.sunset);
        self
    }
}

impl SanitizeOutput for Event {
    fn sanitize_output(mut self) -> Self {
        self.title = sanitize_string(self.title);
        self.description = sanitize_string(self.description);
        self.location = sanitize_string(self.location);
        self.category = sanitize_string(self.category);
        self.location_url = sanitize_option_string(self.location_url);
        self.approved_from = sanitize_option_string(self.approved_from);
        self
    }
}

impl SanitizeOutput for EventV2 {
    fn sanitize_output(mut self) -> Self {
        self.title = sanitize_string(self.title);
        self.description = sanitize_string(self.description);
        self.location = sanitize_string(self.location);
        self.category = sanitize_string(self.category);
        self.location_url = sanitize_option_string(self.location_url);
        self.approved_from = sanitize_option_string(self.approved_from);
        self
    }
}

impl SanitizeOutput for PendingEvent {
    fn sanitize_output(mut self) -> Self {
        self.title = sanitize_string(self.title);
        self.description = sanitize_string(self.description);
        self.location = sanitize_string(self.location);
        self.category = sanitize_string(self.category);
        self.location_url = sanitize_option_string(self.location_url);
        self.admin_notes = sanitize_option_string(self.admin_notes);
        self.submitter_email = sanitize_option_string(self.submitter_email);
        self.bulletin_week = sanitize_string(self.bulletin_week);
        self
    }
}

impl SanitizeOutput for PendingEventV2 {
    fn sanitize_output(mut self) -> Self {
        self.title = sanitize_string(self.title);
        self.description = sanitize_string(self.description);
        self.location = sanitize_string(self.location);
        self.category = sanitize_string(self.category);
        self.location_url = sanitize_option_string(self.location_url);
        self.admin_notes = sanitize_option_string(self.admin_notes);
        self.submitter_email = sanitize_option_string(self.submitter_email);
        self.bulletin_week = sanitize_string(self.bulletin_week);
        self
    }
}

impl SanitizeOutput for BibleVerse {
    fn sanitize_output(mut self) -> Self {
        self.reference = sanitize_string(self.reference);
        self.text = sanitize_string(self.text);
        self
    }
}

impl SanitizeOutput for BibleVerseV2 {
    fn sanitize_output(mut self) -> Self {
        self.reference = sanitize_string(self.reference);
        self.text = sanitize_string(self.text);
        self
    }
}

impl SanitizeOutput for Member {
    fn sanitize_output(mut self) -> Self {
        self.first_name = sanitize_string(self.first_name);
        self.last_name = sanitize_string(self.last_name);
        self.address = sanitize_option_string(self.address);
        self.notes = sanitize_option_string(self.notes);
        self.emergency_contact_name = sanitize_option_string(self.emergency_contact_name);
        self.membership_status = sanitize_option_string(self.membership_status);
        self
    }
}

impl SanitizeOutput for Schedule {
    fn sanitize_output(mut self) -> Self {
        self.song_leader = sanitize_option_string(self.song_leader);
        self.ss_teacher = sanitize_option_string(self.ss_teacher);
        self.ss_leader = sanitize_option_string(self.ss_leader);
        self.mission_story = sanitize_option_string(self.mission_story);
        self.special_program = sanitize_option_string(self.special_program);
        self.sermon_speaker = sanitize_option_string(self.sermon_speaker);
        self.scripture = sanitize_option_string(self.scripture);
        self.offering = sanitize_option_string(self.offering);
        self.deacons = sanitize_option_string(self.deacons);
        self.special_music = sanitize_option_string(self.special_music);
        self.childrens_story = sanitize_option_string(self.childrens_story);
        self.afternoon_program = sanitize_option_string(self.afternoon_program);
        self
    }
}

impl SanitizeOutput for ScheduleV2 {
    fn sanitize_output(mut self) -> Self {
        self.song_leader = sanitize_option_string(self.song_leader);
        self.ss_teacher = sanitize_option_string(self.ss_teacher);
        self.ss_leader = sanitize_option_string(self.ss_leader);
        self.mission_story = sanitize_option_string(self.mission_story);
        self.special_program = sanitize_option_string(self.special_program);
        self.sermon_speaker = sanitize_option_string(self.sermon_speaker);
        self.scripture = sanitize_option_string(self.scripture);
        self.offering = sanitize_option_string(self.offering);
        self.deacons = sanitize_option_string(self.deacons);
        self.special_music = sanitize_option_string(self.special_music);
        self.childrens_story = sanitize_option_string(self.childrens_story);
        self.afternoon_program = sanitize_option_string(self.afternoon_program);
        self
    }
}

// Implement for collections
impl<T: SanitizeOutput> SanitizeOutput for Vec<T> {
    fn sanitize_output(self) -> Self {
        self.into_iter().map(|item| item.sanitize_output()).collect()
    }
}

impl<T: SanitizeOutput> SanitizeOutput for Option<T> {
    fn sanitize_output(self) -> Self {
        self.map(|item| item.sanitize_output())
    }
}

impl<T: SanitizeOutput> SanitizeOutput for PaginatedResponse<T> {
    fn sanitize_output(mut self) -> Self {
        self.items = self.items.sanitize_output();
        self
    }
}

impl SanitizeOutput for Personnel {
    fn sanitize_output(mut self) -> Self {
        self.ss_leader = sanitize_string(self.ss_leader);
        self.ss_teacher = sanitize_string(self.ss_teacher);
        self.mission_story = sanitize_string(self.mission_story);
        self.song_leader = sanitize_string(self.song_leader);
        self.announcements = sanitize_string(self.announcements);
        self.offering = sanitize_string(self.offering);
        self.special_music = sanitize_string(self.special_music);
        self.speaker = sanitize_string(self.speaker);
        self
    }
}

impl SanitizeOutput for ScheduleData {
    fn sanitize_output(mut self) -> Self {
        self.date = sanitize_string(self.date);
        self.personnel = self.personnel.sanitize_output();
        self
    }
}

impl SanitizeOutput for ConferenceData {
    fn sanitize_output(mut self) -> Self {
        self.date = sanitize_string(self.date);
        self.offering_focus = sanitize_string(self.offering_focus);
        self.sunset_tonight = sanitize_string(self.sunset_tonight);
        self.sunset_next_friday = sanitize_string(self.sunset_next_friday);
        self
    }
}

impl SanitizeOutput for ChurchConfig {
    fn sanitize_output(mut self) -> Self {
        self.church_name = sanitize_string(self.church_name);
        self.contact_email = sanitize_string(self.contact_email);
        self.contact_phone = sanitize_option_string(self.contact_phone);
        self.church_address = sanitize_string(self.church_address);
        self.po_box = sanitize_option_string(self.po_box);
        self.google_maps_url = sanitize_option_string(self.google_maps_url);
        self.about_text = sanitize_string(self.about_text);
        self.jellyfin_server_url = sanitize_option_string(self.jellyfin_server_url);
        self.api_keys = self.api_keys.sanitize_output();
        self
    }
}

impl SanitizeOutput for User {
    fn sanitize_output(mut self) -> Self {
        self.username = sanitize_string(self.username);
        self.email = sanitize_option_string(self.email);
        self.name = sanitize_option_string(self.name);
        self.avatar_url = sanitize_option_string(self.avatar_url);
        self.role = sanitize_option_string(self.role);
        self
    }
}
