use chrono::{DateTime, NaiveDate, Utc};
use rust_decimal::Decimal;
use serde::{Deserialize, Serialize};
use sqlx::FromRow;
use uuid::Uuid;

use super::{BaseFields, WorkStatus};

/// One-time project or job
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
pub struct Project {
    #[sqlx(flatten)]
    #[serde(flatten)]
    pub base: BaseFields,
    pub customer_id: Uuid,
    pub name: String,
    pub date: NaiveDate,
    pub status: WorkStatus,
    pub labor: Option<Decimal>,
    pub amount: Option<Decimal>,
    pub notes: Option<String>,
    pub calendar_event_id: Option<String>,
    pub wave_service_id: Option<String>,

    // Either account_address_id OR freeform address fields (mutually exclusive)
    // Note: Cannot use AddressFields here as these are all Option<T>
    pub account_address_id: Option<Uuid>,
    pub street_address: Option<String>,
    pub city: Option<String>,
    pub state: Option<String>,
    pub zip_code: Option<String>,
}

impl Project {
    /// Validate that either account_address_id OR freeform address is provided, not both
    pub fn validate_address(&self) -> Result<(), &'static str> {
        let has_account_address = self.account_address_id.is_some();
        let has_freeform = self.street_address.is_some()
            || self.city.is_some()
            || self.state.is_some()
            || self.zip_code.is_some();

        match (has_account_address, has_freeform) {
            (true, true) => Err("Cannot have both account_address_id and freeform address"),
            (false, false) => Err("Must have either account_address_id or freeform address"),
            _ => Ok(()),
        }
    }
}

/// Team member assignment to a project (many-to-many join table)
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
pub struct ProjectTeamMember {
    pub id: Uuid,
    pub project_id: Uuid,
    pub team_profile_id: Uuid,
    pub created_at: DateTime<Utc>,
}
