use jiff::civil::Date;
use serde::{Deserialize, Serialize};
use uuid::Uuid;

use crate::{repositories::image_repository::ImageId, sql_uuid_newtype, types::user::FromRow};

#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct PortraitId(Uuid);
sql_uuid_newtype!(PortraitId);

#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct PartnerId(Uuid);
sql_uuid_newtype!(PartnerId);

#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct PartnerDetailsId(Uuid);
sql_uuid_newtype!(PartnerDetailsId);

#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct AgendaId(Uuid);
sql_uuid_newtype!(AgendaId);

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NewPortrait {
    pub(crate) sort_number: i64,
    pub(crate) title: String,
    pub(crate) name: String,
    pub(crate) image_id: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Portrait {
    pub(crate) portrait_id: PortraitId,
    pub(crate) sort_number: i64,
    pub(crate) title: String,
    pub(crate) name: String,
    pub(crate) image_id: String,
    pub(crate) image_name: String,
}

impl FromRow for Portrait {
    fn try_from_row(row: &rusqlite::Row) -> Result<Self, rusqlite::Error> {
        let portrait = Self {
            portrait_id: row.get("portrait_id")?,
            sort_number: row.get("sort_number")?,
            title: row.get("title")?,
            name: row.get("name")?,
            image_id: row.get("image_id")?,
            image_name: row.get("image_name")?,
        };
        Ok(portrait)
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NewPartner {
    pub(crate) company_name: String,
    pub(crate) logo_image_id: ImageId,
    pub(crate) partner_details: Option<NewPartnerDetails>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NewPartnerDetails {
    pub(crate) sector: String,
    pub(crate) activity: String,
    pub(crate) location: String,
    pub(crate) website: String,
    pub(crate) contact: String,
    pub(crate) member_date: Date,
    pub(crate) right_picture_id: ImageId,
    pub(crate) left_picture_id: ImageId,
    pub(crate) right_text: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Partner {
    pub(crate) partner_id: PartnerId,
    pub(crate) company_name: String,
    pub(crate) logo_image_id: ImageId,
    pub(crate) partner_details: Option<PartnerDetails>,
}

impl FromRow for Partner {
    fn try_from_row(row: &rusqlite::Row) -> Result<Self, rusqlite::Error> {
        let partner_details_id: Option<PartnerDetailsId> = row.get("partner_details_id")?;

        let mut partner_details = None;

        if let Some(partner_details_id) = partner_details_id {
            partner_details = Some(PartnerDetails {
                partner_details_id,
                partner_id: row.get("partner_id")?,
                sector: row.get("sector")?,
                activity: row.get("activity")?,
                location: row.get("location")?,
                website: row.get("website")?,
                contact: row.get("contact")?,
                member_date: row.get("member_date")?,
                right_picture_id: row.get("right_picture_id")?,
                left_picture_id: row.get("left_picture_id")?,
                right_text: row.get("right_text")?,
            });
        }

        let partner = Partner {
            partner_id: row.get("partner_id")?,
            company_name: row.get("company_name")?,
            logo_image_id: row.get("logo_image_id")?,
            partner_details,
        };

        Ok(partner)
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PartnerDetails {
    pub(crate) partner_details_id: PartnerDetailsId,
    pub(crate) partner_id: PartnerId,
    pub(crate) sector: String,
    pub(crate) activity: String,
    pub(crate) location: String,
    pub(crate) website: String,
    pub(crate) contact: String,
    pub(crate) member_date: Date,
    pub(crate) right_picture_id: Option<ImageId>,
    pub(crate) left_picture_id: Option<ImageId>,
    pub(crate) right_text: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NewAgenda {
    pub(crate) sort_date: Date,
    pub(crate) date: String,
    pub(crate) title: String,
    pub(crate) entry: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Agenda {
    pub(crate) agenda_id: AgendaId,
    pub(crate) sort_date: Date,
    pub(crate) date: String,
    pub(crate) title: String,
    pub(crate) entry: String,
}

impl FromRow for Agenda {
    fn try_from_row(row: &rusqlite::Row) -> Result<Self, rusqlite::Error> {
        let agenda = Agenda {
            agenda_id: row.get("agenda_id")?,
            sort_date: row.get("sort_date")?,
            date: row.get("date")?,
            title: row.get("title")?,
            entry: row.get("entry")?,
        };

        Ok(agenda)
    }
}
