// Organization Branding Handlers

use axum::{
    Json,
    extract::{Path, State},
    http::StatusCode,
};
use common::models::Organization;
use serde::{Deserialize, Serialize};
use serde_json::json;
use sqlx::PgPool;
use uuid::Uuid;

use super::handlers::log_action;

#[derive(Deserialize, Serialize)]
pub struct BrandingPayload {
    pub primary_color: Option<String>,
    pub secondary_color: Option<String>,
    pub platform_name: Option<String>,
}

#[derive(Serialize)]
pub struct BrandingResponse {
    pub logo_url: Option<String>,
    pub favicon_url: Option<String>,
    pub platform_name: Option<String>,
    pub primary_color: String,
    pub secondary_color: String,
}

// Upload organization logo
pub async fn upload_organization_logo(
    claims: common::auth::Claims,
    State(pool): State<PgPool>,
    Path(org_id): Path<Uuid>,
    mut multipart: axum::extract::Multipart,
) -> Result<Json<serde_json::Value>, (StatusCode, String)> {
    // Only admins can upload logos
    if claims.role != "admin" {
        return Err((StatusCode::FORBIDDEN, "Admin access required".into()));
    }

    // Verify organization exists and user has access
    let _ = sqlx::query_as::<_, Organization>("SELECT * FROM organizations WHERE id = $1")
        .bind(org_id)
        .fetch_one(&pool)
        .await
        .map_err(|_| (StatusCode::NOT_FOUND, "Organization not found".into()))?;

    // Process multipart form
    while let Some(field) = multipart
        .next_field()
        .await
        .map_err(|e| (StatusCode::BAD_REQUEST, format!("Multipart error: {}", e)))?
    {
        let name = field.name().unwrap_or("").to_string();

        if name == "file" {
            let filename = field
                .file_name()
                .ok_or((StatusCode::BAD_REQUEST, "Missing filename".into()))?
                .to_string();

            // Validate file extension
            let ext = filename.split('.').last().unwrap_or("");
            if !["png", "jpg", "jpeg", "svg"].contains(&ext.to_lowercase().as_str()) {
                return Err((
                    StatusCode::BAD_REQUEST,
                    "Invalid file type. Only PNG, JPG, and SVG allowed".into(),
                ));
            }

            let data = field.bytes().await.map_err(|e| {
                (
                    StatusCode::INTERNAL_SERVER_ERROR,
                    format!("Failed to read file: {}", e),
                )
            })?;

            // Validate file size (max 2MB)
            if data.len() > 2 * 1024 * 1024 {
                return Err((
                    StatusCode::BAD_REQUEST,
                    "File too large. Maximum 2MB allowed".into(),
                ));
            }

            // Create uploads directory if it doesn't exist
            std::fs::create_dir_all("uploads/org-logos").map_err(|e| {
                (
                    StatusCode::INTERNAL_SERVER_ERROR,
                    format!("Failed to create directory: {}", e),
                )
            })?;

            // Generate unique filename
            let unique_filename = format!("{}_{}.{}", org_id, uuid::Uuid::new_v4(), ext);
            let filepath = format!("uploads/org-logos/{}", unique_filename);

            // Save file
            std::fs::write(&filepath, &data).map_err(|e| {
                (
                    StatusCode::INTERNAL_SERVER_ERROR,
                    format!("Failed to save file: {}", e),
                )
            })?;

            // Update organization in database
            let logo_url = format!("/{}", filepath);
            sqlx::query("UPDATE organizations SET logo_url = $1 WHERE id = $2")
                .bind(&logo_url)
                .bind(org_id)
                .execute(&pool)
                .await
                .map_err(|e| {
                    (
                        StatusCode::INTERNAL_SERVER_ERROR,
                        format!("Database error: {}", e),
                    )
                })?;

            log_action(
                &pool,
                claims.org,
                claims.sub,
                "UPDATE_LOGO",
                "Organization",
                org_id,
                json!({"logo_url": &logo_url}),
            )
            .await;

            return Ok(Json(json!({
                "logo_url": logo_url,
                "message": "Logo uploaded successfully"
            })));
        }
    }

    Err((StatusCode::BAD_REQUEST, "No file provided".into()))
}

// Upload organization favicon
pub async fn upload_organization_favicon(
    claims: common::auth::Claims,
    State(pool): State<PgPool>,
    Path(org_id): Path<Uuid>,
    mut multipart: axum::extract::Multipart,
) -> Result<Json<serde_json::Value>, (StatusCode, String)> {
    // Only admins can upload favicons
    if claims.role != "admin" {
        return Err((StatusCode::FORBIDDEN, "Admin access required".into()));
    }

    // Verify organization exists and user has access
    let _ = sqlx::query_as::<_, Organization>("SELECT * FROM organizations WHERE id = $1")
        .bind(org_id)
        .fetch_one(&pool)
        .await
        .map_err(|_| (StatusCode::NOT_FOUND, "Organization not found".into()))?;

    // Process multipart form
    while let Some(field) = multipart
        .next_field()
        .await
        .map_err(|e| (StatusCode::BAD_REQUEST, format!("Multipart error: {}", e)))?
    {
        let name = field.name().unwrap_or("").to_string();

        if name == "file" {
            let filename = field
                .file_name()
                .ok_or((StatusCode::BAD_REQUEST, "Missing filename".into()))?
                .to_string();

            // Validate file extension
            let ext = filename.split('.').last().unwrap_or("");
            if !["png", "jpg", "jpeg", "svg", "ico"].contains(&ext.to_lowercase().as_str()) {
                return Err((
                    StatusCode::BAD_REQUEST,
                    "Invalid file type. Only PNG, JPG, SVG, and ICO allowed".into(),
                ));
            }

            let data = field.bytes().await.map_err(|e| {
                (
                    StatusCode::INTERNAL_SERVER_ERROR,
                    format!("Failed to read file: {}", e),
                )
            })?;

            // Validate file size (max 512KB for favicons seems reasonable, but sticking to 1MB to be safe)
            if data.len() > 1024 * 1024 {
                return Err((
                    StatusCode::BAD_REQUEST,
                    "File too large. Maximum 1MB allowed".into(),
                ));
            }

            // Create uploads directory if it doesn't exist
            std::fs::create_dir_all("uploads/org-favicons").map_err(|e| {
                (
                    StatusCode::INTERNAL_SERVER_ERROR,
                    format!("Failed to create directory: {}", e),
                )
            })?;

            // Generate unique filename
            let unique_filename = format!("{}_{}.{}", org_id, uuid::Uuid::new_v4(), ext);
            let filepath = format!("uploads/org-favicons/{}", unique_filename);

            // Save file
            std::fs::write(&filepath, &data).map_err(|e| {
                (
                    StatusCode::INTERNAL_SERVER_ERROR,
                    format!("Failed to save file: {}", e),
                )
            })?;

            // Update organization in database
            let favicon_url = format!("/{}", filepath);
            sqlx::query("UPDATE organizations SET favicon_url = $1 WHERE id = $2")
                .bind(&favicon_url)
                .bind(org_id)
                .execute(&pool)
                .await
                .map_err(|e| {
                    (
                        StatusCode::INTERNAL_SERVER_ERROR,
                        format!("Database error: {}", e),
                    )
                })?;

            log_action(
                &pool,
                claims.org,
                claims.sub,
                "UPDATE_FAVICON",
                "Organization",
                org_id,
                json!({"favicon_url": &favicon_url}),
            )
            .await;

            return Ok(Json(json!({
                "favicon_url": favicon_url,
                "message": "Favicon uploaded successfully"
            })));
        }
    }

    Err((StatusCode::BAD_REQUEST, "No file provided".into()))
}

// Update organization branding colors
pub async fn update_organization_branding(
    claims: common::auth::Claims,
    State(pool): State<PgPool>,
    Path(org_id): Path<Uuid>,
    Json(payload): Json<BrandingPayload>,
) -> Result<Json<Organization>, (StatusCode, String)> {
    // Only admins can update branding
    if claims.role != "admin" {
        return Err((StatusCode::FORBIDDEN, "Admin access required".into()));
    }

    // Validate hex color format
    let validate_color = |color: &str| -> bool {
        color.len() == 7
            && color.starts_with('#')
            && color[1..].chars().all(|c| c.is_ascii_hexdigit())
    };

    if let Some(ref primary) = payload.primary_color {
        if !validate_color(primary) {
            return Err((
                StatusCode::BAD_REQUEST,
                "Invalid primary_color format. Use #RRGGBB".into(),
            ));
        }
    }

    if let Some(ref secondary) = payload.secondary_color {
        if !validate_color(secondary) {
            return Err((
                StatusCode::BAD_REQUEST,
                "Invalid secondary_color format. Use #RRGGBB".into(),
            ));
        }
    }

    // Update organization
    let org = sqlx::query_as::<_, Organization>(
        "UPDATE organizations 
         SET primary_color = COALESCE($1, primary_color),
             secondary_color = COALESCE($2, secondary_color),
             platform_name = COALESCE($3, platform_name),
             updated_at = NOW()
         WHERE id = $4
         RETURNING *",
    )
    .bind(&payload.primary_color)
    .bind(&payload.secondary_color)
    .bind(&payload.platform_name)
    .bind(org_id)
    .fetch_one(&pool)
    .await
    .map_err(|e| {
        (
            StatusCode::INTERNAL_SERVER_ERROR,
            format!("Database error: {}", e),
        )
    })?;

    log_action(
        &pool,
        claims.org,
        claims.sub,
        "UPDATE_BRANDING",
        "Organization",
        org_id,
        json!(payload),
    )
    .await;

    Ok(Json(org))
}

// Get organization branding (public endpoint)
pub async fn get_organization_branding(
    State(pool): State<PgPool>,
    Path(org_id): Path<Uuid>,
) -> Result<Json<BrandingResponse>, StatusCode> {
    let org = sqlx::query_as::<_, Organization>("SELECT * FROM organizations WHERE id = $1")
        .bind(org_id)
        .fetch_one(&pool)
        .await
        .map_err(|_| StatusCode::NOT_FOUND)?;

    Ok(Json(BrandingResponse {
        logo_url: org.logo_url,
        favicon_url: org.favicon_url,
        platform_name: org.platform_name,
        primary_color: org.primary_color.unwrap_or_else(|| "#3B82F6".to_string()),
        secondary_color: org.secondary_color.unwrap_or_else(|| "#8B5CF6".to_string()),
    }))
}
