use serde::{Deserialize, Serialize};
use sqlx::PgPool;
use time::OffsetDateTime;
use uuid::Uuid;

// Site settings models

#[derive(Debug, Clone, sqlx::FromRow)]
pub struct DbSiteIdentity {
    pub id: i32,
    pub display_name: String,
    pub occupation: String,
    pub bio: String,
    pub site_title: String,
    pub created_at: OffsetDateTime,
    pub updated_at: OffsetDateTime,
}

#[derive(Debug, Clone, sqlx::FromRow)]
pub struct DbSocialLink {
    pub id: Uuid,
    pub platform: String,
    pub label: String,
    pub value: String,
    pub icon: String,
    pub visible: bool,
    pub display_order: i32,
    pub created_at: OffsetDateTime,
    pub updated_at: OffsetDateTime,
}

// API response types
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ApiSiteIdentity {
    #[serde(rename = "displayName")]
    pub display_name: String,
    pub occupation: String,
    pub bio: String,
    #[serde(rename = "siteTitle")]
    pub site_title: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ApiSocialLink {
    pub id: String,
    pub platform: String,
    pub label: String,
    pub value: String,
    pub icon: String,
    pub visible: bool,
    #[serde(rename = "displayOrder")]
    pub display_order: i32,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ApiSiteSettings {
    pub identity: ApiSiteIdentity,
    #[serde(rename = "socialLinks")]
    pub social_links: Vec<ApiSocialLink>,
}

// Request types for updates
#[derive(Debug, Deserialize, Serialize)]
pub struct UpdateSiteIdentityRequest {
    #[serde(rename = "displayName")]
    pub display_name: String,
    pub occupation: String,
    pub bio: String,
    #[serde(rename = "siteTitle")]
    pub site_title: String,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct UpdateSocialLinkRequest {
    pub id: String,
    pub platform: String,
    pub label: String,
    pub value: String,
    pub icon: String,
    pub visible: bool,
    #[serde(rename = "displayOrder")]
    pub display_order: i32,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct UpdateSiteSettingsRequest {
    pub identity: UpdateSiteIdentityRequest,
    #[serde(rename = "socialLinks")]
    pub social_links: Vec<UpdateSocialLinkRequest>,
}

// Conversion implementations
impl DbSiteIdentity {
    pub fn to_api(&self) -> ApiSiteIdentity {
        ApiSiteIdentity {
            display_name: self.display_name.clone(),
            occupation: self.occupation.clone(),
            bio: self.bio.clone(),
            site_title: self.site_title.clone(),
        }
    }
}

impl DbSocialLink {
    pub fn to_api(&self) -> ApiSocialLink {
        ApiSocialLink {
            id: self.id.to_string(),
            platform: self.platform.clone(),
            label: self.label.clone(),
            value: self.value.clone(),
            icon: self.icon.clone(),
            visible: self.visible,
            display_order: self.display_order,
        }
    }
}

// Query functions
pub async fn get_site_settings(pool: &PgPool) -> Result<ApiSiteSettings, sqlx::Error> {
    // Get identity (single row)
    let identity = sqlx::query_as!(
        DbSiteIdentity,
        r#"
        SELECT id, display_name, occupation, bio, site_title, created_at, updated_at
        FROM site_identity
        WHERE id = 1
        "#
    )
    .fetch_one(pool)
    .await?;

    // Get social links (ordered)
    let social_links = sqlx::query_as!(
        DbSocialLink,
        r#"
        SELECT id, platform, label, value, icon, visible, display_order, created_at, updated_at
        FROM social_links
        ORDER BY display_order ASC
        "#
    )
    .fetch_all(pool)
    .await?;

    Ok(ApiSiteSettings {
        identity: identity.to_api(),
        social_links: social_links.into_iter().map(|sl| sl.to_api()).collect(),
    })
}

pub async fn update_site_identity(
    pool: &PgPool,
    req: &UpdateSiteIdentityRequest,
) -> Result<DbSiteIdentity, sqlx::Error> {
    sqlx::query_as!(
        DbSiteIdentity,
        r#"
        UPDATE site_identity
        SET display_name = $1, occupation = $2, bio = $3, site_title = $4
        WHERE id = 1
        RETURNING id, display_name, occupation, bio, site_title, created_at, updated_at
        "#,
        req.display_name,
        req.occupation,
        req.bio,
        req.site_title
    )
    .fetch_one(pool)
    .await
}

pub async fn update_social_link(
    pool: &PgPool,
    link_id: Uuid,
    req: &UpdateSocialLinkRequest,
) -> Result<DbSocialLink, sqlx::Error> {
    sqlx::query_as!(
        DbSocialLink,
        r#"
        UPDATE social_links
        SET platform = $2, label = $3, value = $4, icon = $5, visible = $6, display_order = $7
        WHERE id = $1
        RETURNING id, platform, label, value, icon, visible, display_order, created_at, updated_at
        "#,
        link_id,
        req.platform,
        req.label,
        req.value,
        req.icon,
        req.visible,
        req.display_order
    )
    .fetch_one(pool)
    .await
}

pub async fn update_site_settings(
    pool: &PgPool,
    req: &UpdateSiteSettingsRequest,
) -> Result<ApiSiteSettings, sqlx::Error> {
    // Update identity
    let identity = update_site_identity(pool, &req.identity).await?;

    // Update each social link
    let mut updated_links = Vec::new();
    for link_req in &req.social_links {
        let link_id = Uuid::parse_str(&link_req.id).map_err(|_| {
            sqlx::Error::Decode(Box::new(std::io::Error::new(
                std::io::ErrorKind::InvalidData,
                "Invalid UUID format",
            )))
        })?;
        let link = update_social_link(pool, link_id, link_req).await?;
        updated_links.push(link);
    }

    Ok(ApiSiteSettings {
        identity: identity.to_api(),
        social_links: updated_links.into_iter().map(|sl| sl.to_api()).collect(),
    })
}
