pub mod account_deletion;
pub mod ui;

use axum::{
    extract::{Path, Query, State},
    response::IntoResponse,
    routing::{get, post},
    Json, Router,
};
use chrono::{DateTime, Utc};
use diesel::prelude::*;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::sync::Arc;
use uuid::Uuid;

use crate::core::bot::get_default_bot;
use crate::core::shared::schema::{
    consent_history, cookie_consents, data_deletion_requests, data_export_requests,
    legal_acceptances, legal_document_versions, legal_documents,
};
use crate::core::shared::state::AppState;

#[derive(Debug, Clone, Queryable, Insertable, AsChangeset, Serialize, Deserialize)]
#[diesel(table_name = legal_documents)]
pub struct DbLegalDocument {
    pub id: Uuid,
    pub org_id: Uuid,
    pub bot_id: Uuid,
    pub slug: String,
    pub title: String,
    pub content: String,
    pub document_type: String,
    pub version: String,
    pub effective_date: DateTime<Utc>,
    pub is_active: bool,
    pub requires_acceptance: bool,
    pub metadata: serde_json::Value,
    pub created_by: Option<Uuid>,
    pub created_at: DateTime<Utc>,
    pub updated_at: DateTime<Utc>,
}

#[derive(Debug, Clone, Queryable, Insertable, Serialize, Deserialize)]
#[diesel(table_name = legal_document_versions)]
pub struct DbDocumentVersion {
    pub id: Uuid,
    pub document_id: Uuid,
    pub version: String,
    pub content: String,
    pub change_summary: Option<String>,
    pub created_by: Option<Uuid>,
    pub created_at: DateTime<Utc>,
}

#[derive(Debug, Clone, Queryable, Insertable, AsChangeset, Serialize, Deserialize)]
#[diesel(table_name = cookie_consents)]
pub struct DbCookieConsent {
    pub id: Uuid,
    pub org_id: Uuid,
    pub bot_id: Uuid,
    pub user_id: Option<Uuid>,
    pub session_id: Option<String>,
    pub ip_address: Option<String>,
    pub user_agent: Option<String>,
    pub country_code: Option<String>,
    pub consent_necessary: bool,
    pub consent_analytics: bool,
    pub consent_marketing: bool,
    pub consent_preferences: bool,
    pub consent_functional: bool,
    pub consent_version: String,
    pub consent_given_at: DateTime<Utc>,
    pub consent_updated_at: DateTime<Utc>,
    pub consent_withdrawn_at: Option<DateTime<Utc>>,
    pub created_at: DateTime<Utc>,
}

#[derive(Debug, Clone, Queryable, Insertable, Serialize, Deserialize)]
#[diesel(table_name = consent_history)]
pub struct DbConsentHistory {
    pub id: Uuid,
    pub consent_id: Uuid,
    pub action: String,
    pub previous_consents: serde_json::Value,
    pub new_consents: serde_json::Value,
    pub ip_address: Option<String>,
    pub user_agent: Option<String>,
    pub created_at: DateTime<Utc>,
}

#[derive(Debug, Clone, Queryable, Insertable, Serialize, Deserialize)]
#[diesel(table_name = legal_acceptances)]
pub struct DbLegalAcceptance {
    pub id: Uuid,
    pub org_id: Uuid,
    pub bot_id: Uuid,
    pub user_id: Uuid,
    pub document_id: Uuid,
    pub document_version: String,
    pub accepted_at: DateTime<Utc>,
    pub ip_address: Option<String>,
    pub user_agent: Option<String>,
}

#[derive(Debug, Clone, Queryable, Insertable, AsChangeset, Serialize, Deserialize)]
#[diesel(table_name = data_deletion_requests)]
pub struct DbDeletionRequest {
    pub id: Uuid,
    pub org_id: Uuid,
    pub bot_id: Uuid,
    pub user_id: Uuid,
    pub request_type: String,
    pub status: String,
    pub reason: Option<String>,
    pub requested_at: DateTime<Utc>,
    pub scheduled_for: Option<DateTime<Utc>>,
    pub completed_at: Option<DateTime<Utc>>,
    pub confirmation_token: String,
    pub confirmed_at: Option<DateTime<Utc>>,
    pub processed_by: Option<Uuid>,
    pub notes: Option<String>,
    pub created_at: DateTime<Utc>,
    pub updated_at: DateTime<Utc>,
}

#[derive(Debug, Clone, Queryable, Insertable, AsChangeset, Serialize, Deserialize)]
#[diesel(table_name = data_export_requests)]
pub struct DbExportRequest {
    pub id: Uuid,
    pub org_id: Uuid,
    pub bot_id: Uuid,
    pub user_id: Uuid,
    pub status: String,
    pub format: String,
    pub include_sections: serde_json::Value,
    pub requested_at: DateTime<Utc>,
    pub started_at: Option<DateTime<Utc>>,
    pub completed_at: Option<DateTime<Utc>>,
    pub file_url: Option<String>,
    pub file_size: Option<i32>,
    pub expires_at: Option<DateTime<Utc>>,
    pub error_message: Option<String>,
    pub created_at: DateTime<Utc>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
#[serde(rename_all = "snake_case")]
pub enum CookieCategory {
    Necessary,
    Analytics,
    Marketing,
    Preferences,
    Functional,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CookieConsent {
    pub id: Uuid,
    pub user_id: Option<Uuid>,
    pub session_id: Option<String>,
    pub ip_address: Option<String>,
    pub consents: HashMap<CookieCategory, bool>,
    pub consent_given_at: DateTime<Utc>,
    pub consent_updated_at: DateTime<Utc>,
    pub consent_version: String,
    pub user_agent: Option<String>,
    pub country_code: Option<String>,
}

#[derive(Debug, Clone, Deserialize)]
pub struct CookieConsentRequest {
    pub session_id: Option<String>,
    pub consents: HashMap<CookieCategory, bool>,
    pub user_agent: Option<String>,
}

#[derive(Debug, Clone, Serialize)]
pub struct CookieConsentResponse {
    pub id: Uuid,
    pub consents: HashMap<CookieCategory, bool>,
    pub consent_given_at: DateTime<Utc>,
    pub consent_version: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CookiePolicy {
    pub version: String,
    pub effective_date: DateTime<Utc>,
    pub categories: Vec<CookieCategoryInfo>,
    pub last_updated: DateTime<Utc>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CookieCategoryInfo {
    pub category: CookieCategory,
    pub name: String,
    pub description: String,
    pub is_required: bool,
    pub cookies: Vec<CookieInfo>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CookieInfo {
    pub name: String,
    pub provider: String,
    pub purpose: String,
    pub expiry: String,
    pub cookie_type: CookieType,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum CookieType {
    Session,
    Persistent,
    FirstParty,
    ThirdParty,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LegalDocument {
    pub id: String,
    pub title: String,
    pub slug: String,
    pub content: String,
    pub version: String,
    pub effective_date: DateTime<Utc>,
    pub last_updated: DateTime<Utc>,
    pub document_type: LegalDocumentType,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum LegalDocumentType {
    PrivacyPolicy,
    TermsOfService,
    CookiePolicy,
    AcceptableUsePolicy,
    DataProcessingAgreement,
    GdprCompliance,
    CcpaCompliance,
}

impl std::fmt::Display for LegalDocumentType {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let s = match self {
            Self::PrivacyPolicy => "privacy_policy",
            Self::TermsOfService => "terms_of_service",
            Self::CookiePolicy => "cookie_policy",
            Self::AcceptableUsePolicy => "acceptable_use_policy",
            Self::DataProcessingAgreement => "data_processing_agreement",
            Self::GdprCompliance => "gdpr_compliance",
            Self::CcpaCompliance => "ccpa_compliance",
        };
        write!(f, "{s}")
    }
}

impl std::str::FromStr for LegalDocumentType {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "privacy_policy" => Ok(Self::PrivacyPolicy),
            "terms_of_service" => Ok(Self::TermsOfService),
            "cookie_policy" => Ok(Self::CookiePolicy),
            "acceptable_use_policy" => Ok(Self::AcceptableUsePolicy),
            "data_processing_agreement" => Ok(Self::DataProcessingAgreement),
            "gdpr_compliance" => Ok(Self::GdprCompliance),
            "ccpa_compliance" => Ok(Self::CcpaCompliance),
            _ => Err(format!("Unknown document type: {s}")),
        }
    }
}

#[derive(Debug, Clone, Serialize)]
pub struct DataDeletionResult {
    pub user_id: Uuid,
    pub consents_deleted: i32,
    pub deleted_at: DateTime<Utc>,
    pub confirmation_token: String,
}

#[derive(Debug, Clone, Serialize)]
pub struct UserDataExport {
    pub user_id: Uuid,
    pub exported_at: DateTime<Utc>,
    pub consents: Vec<CookieConsent>,
    pub format: String,
}

#[derive(Debug, Deserialize)]
pub struct ListDocumentsQuery {
    pub document_type: Option<String>,
    pub active_only: Option<bool>,
}

#[derive(Debug, Deserialize)]
pub struct CreateDocumentRequest {
    pub slug: String,
    pub title: String,
    pub content: String,
    pub document_type: LegalDocumentType,
    pub version: Option<String>,
    pub requires_acceptance: Option<bool>,
}

#[derive(Debug, Deserialize)]
pub struct UpdateDocumentRequest {
    pub title: Option<String>,
    pub content: Option<String>,
    pub is_active: Option<bool>,
    pub requires_acceptance: Option<bool>,
}

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

#[derive(Debug, Deserialize)]
pub struct DataExportRequest {
    pub format: Option<String>,
    pub sections: Option<Vec<String>>,
}

#[derive(Debug, thiserror::Error)]
pub enum LegalError {
    #[error("Not found: {0}")]
    NotFound(String),
    #[error("Validation error: {0}")]
    Validation(String),
    #[error("Database error: {0}")]
    Database(String),
    #[error("Internal error: {0}")]
    Internal(String),
}

impl IntoResponse for LegalError {
    fn into_response(self) -> axum::response::Response {
        use axum::http::StatusCode;
        let (status, message) = match &self {
            Self::NotFound(msg) => (StatusCode::NOT_FOUND, msg.clone()),
            Self::Validation(msg) => (StatusCode::BAD_REQUEST, msg.clone()),
            Self::Database(msg) | Self::Internal(msg) => {
                (StatusCode::INTERNAL_SERVER_ERROR, msg.clone())
            }
        };
        (status, Json(serde_json::json!({ "error": message }))).into_response()
    }
}

fn db_consent_to_consent(db: DbCookieConsent) -> CookieConsent {
    let mut consents = HashMap::new();
    consents.insert(CookieCategory::Necessary, db.consent_necessary);
    consents.insert(CookieCategory::Analytics, db.consent_analytics);
    consents.insert(CookieCategory::Marketing, db.consent_marketing);
    consents.insert(CookieCategory::Preferences, db.consent_preferences);
    consents.insert(CookieCategory::Functional, db.consent_functional);

    CookieConsent {
        id: db.id,
        user_id: db.user_id,
        session_id: db.session_id,
        ip_address: db.ip_address,
        consents,
        consent_given_at: db.consent_given_at,
        consent_updated_at: db.consent_updated_at,
        consent_version: db.consent_version,
        user_agent: db.user_agent,
        country_code: db.country_code,
    }
}

fn db_document_to_document(db: DbLegalDocument) -> LegalDocument {
    let document_type: LegalDocumentType = db.document_type.parse().unwrap_or(LegalDocumentType::PrivacyPolicy);

    LegalDocument {
        id: db.id.to_string(),
        title: db.title,
        slug: db.slug,
        content: db.content,
        version: db.version,
        effective_date: db.effective_date,
        last_updated: db.updated_at,
        document_type,
    }
}

fn get_default_cookie_policy() -> CookiePolicy {
    let now = Utc::now();
    CookiePolicy {
        version: "1.0.0".to_string(),
        effective_date: now,
        last_updated: now,
        categories: vec![
            CookieCategoryInfo {
                category: CookieCategory::Necessary,
                name: "Necessary".to_string(),
                description: "Essential cookies required for the website to function properly.".to_string(),
                is_required: true,
                cookies: vec![
                    CookieInfo {
                        name: "session_id".to_string(),
                        provider: "General Bots".to_string(),
                        purpose: "Session management".to_string(),
                        expiry: "Session".to_string(),
                        cookie_type: CookieType::Session,
                    },
                ],
            },
            CookieCategoryInfo {
                category: CookieCategory::Analytics,
                name: "Analytics".to_string(),
                description: "Cookies that help us understand how visitors interact with our website.".to_string(),
                is_required: false,
                cookies: vec![],
            },
            CookieCategoryInfo {
                category: CookieCategory::Marketing,
                name: "Marketing".to_string(),
                description: "Cookies used to deliver relevant advertisements.".to_string(),
                is_required: false,
                cookies: vec![],
            },
            CookieCategoryInfo {
                category: CookieCategory::Preferences,
                name: "Preferences".to_string(),
                description: "Cookies that remember your preferences and settings.".to_string(),
                is_required: false,
                cookies: vec![],
            },
            CookieCategoryInfo {
                category: CookieCategory::Functional,
                name: "Functional".to_string(),
                description: "Cookies that enable enhanced functionality.".to_string(),
                is_required: false,
                cookies: vec![],
            },
        ],
    }
}

pub async fn handle_record_consent(
    State(state): State<Arc<AppState>>,
    Json(req): Json<CookieConsentRequest>,
) -> Result<Json<CookieConsentResponse>, LegalError> {
    let pool = state.conn.clone();

    let result = tokio::task::spawn_blocking(move || {
        let mut conn = pool.get().map_err(|e| LegalError::Database(e.to_string()))?;
        let (bot_id, _bot_name) = get_default_bot(&mut conn);
        let org_id = Uuid::nil();
        let now = Utc::now();

        let mut consents = req.consents;
        consents.insert(CookieCategory::Necessary, true);

        let db_consent = DbCookieConsent {
            id: Uuid::new_v4(),
            org_id,
            bot_id,
            user_id: None,
            session_id: req.session_id,
            ip_address: None,
            user_agent: req.user_agent,
            country_code: None,
            consent_necessary: true,
            consent_analytics: *consents.get(&CookieCategory::Analytics).unwrap_or(&false),
            consent_marketing: *consents.get(&CookieCategory::Marketing).unwrap_or(&false),
            consent_preferences: *consents.get(&CookieCategory::Preferences).unwrap_or(&false),
            consent_functional: *consents.get(&CookieCategory::Functional).unwrap_or(&false),
            consent_version: "1.0.0".to_string(),
            consent_given_at: now,
            consent_updated_at: now,
            consent_withdrawn_at: None,
            created_at: now,
        };

        diesel::insert_into(cookie_consents::table)
            .values(&db_consent)
            .execute(&mut conn)
            .map_err(|e| LegalError::Database(e.to_string()))?;

        Ok::<_, LegalError>(CookieConsentResponse {
            id: db_consent.id,
            consents,
            consent_given_at: db_consent.consent_given_at,
            consent_version: db_consent.consent_version,
        })
    })
    .await
    .map_err(|e| LegalError::Internal(e.to_string()))??;

    Ok(Json(result))
}

pub async fn handle_get_consent(
    State(state): State<Arc<AppState>>,
    Path(consent_id): Path<Uuid>,
) -> Result<Json<Option<CookieConsent>>, LegalError> {
    let pool = state.conn.clone();

    let result = tokio::task::spawn_blocking(move || {
        let mut conn = pool.get().map_err(|e| LegalError::Database(e.to_string()))?;

        let db_consent: Option<DbCookieConsent> = cookie_consents::table
            .find(consent_id)
            .first(&mut conn)
            .optional()
            .map_err(|e| LegalError::Database(e.to_string()))?;

        Ok::<_, LegalError>(db_consent.map(db_consent_to_consent))
    })
    .await
    .map_err(|e| LegalError::Internal(e.to_string()))??;

    Ok(Json(result))
}

#[derive(Debug, Deserialize)]
pub struct ConsentBySessionQuery {
    pub session_id: String,
}

pub async fn handle_get_consent_by_session(
    State(state): State<Arc<AppState>>,
    Query(query): Query<ConsentBySessionQuery>,
) -> Result<Json<Option<CookieConsent>>, LegalError> {
    let pool = state.conn.clone();

    let result = tokio::task::spawn_blocking(move || {
        let mut conn = pool.get().map_err(|e| LegalError::Database(e.to_string()))?;

        let db_consent: Option<DbCookieConsent> = cookie_consents::table
            .filter(cookie_consents::session_id.eq(&query.session_id))
            .order(cookie_consents::consent_given_at.desc())
            .first(&mut conn)
            .optional()
            .map_err(|e| LegalError::Database(e.to_string()))?;

        Ok::<_, LegalError>(db_consent.map(db_consent_to_consent))
    })
    .await
    .map_err(|e| LegalError::Internal(e.to_string()))??;

    Ok(Json(result))
}

pub async fn handle_update_consent(
    State(state): State<Arc<AppState>>,
    Path(consent_id): Path<Uuid>,
    Json(req): Json<CookieConsentRequest>,
) -> Result<Json<CookieConsent>, LegalError> {
    let pool = state.conn.clone();

    let result = tokio::task::spawn_blocking(move || {
        let mut conn = pool.get().map_err(|e| LegalError::Database(e.to_string()))?;
        let now = Utc::now();

        let mut db_consent: DbCookieConsent = cookie_consents::table
            .find(consent_id)
            .first(&mut conn)
            .map_err(|_| LegalError::NotFound("Consent not found".to_string()))?;

        let previous_consents = serde_json::json!({
            "necessary": db_consent.consent_necessary,
            "analytics": db_consent.consent_analytics,
            "marketing": db_consent.consent_marketing,
            "preferences": db_consent.consent_preferences,
            "functional": db_consent.consent_functional,
        });

        let mut consents = req.consents;
        consents.insert(CookieCategory::Necessary, true);

        db_consent.consent_necessary = true;
        db_consent.consent_analytics = *consents.get(&CookieCategory::Analytics).unwrap_or(&false);
        db_consent.consent_marketing = *consents.get(&CookieCategory::Marketing).unwrap_or(&false);
        db_consent.consent_preferences = *consents.get(&CookieCategory::Preferences).unwrap_or(&false);
        db_consent.consent_functional = *consents.get(&CookieCategory::Functional).unwrap_or(&false);
        db_consent.consent_updated_at = now;

        let new_consents = serde_json::json!({
            "necessary": db_consent.consent_necessary,
            "analytics": db_consent.consent_analytics,
            "marketing": db_consent.consent_marketing,
            "preferences": db_consent.consent_preferences,
            "functional": db_consent.consent_functional,
        });

        diesel::update(cookie_consents::table.find(consent_id))
            .set(&db_consent)
            .execute(&mut conn)
            .map_err(|e| LegalError::Database(e.to_string()))?;

        let history = DbConsentHistory {
            id: Uuid::new_v4(),
            consent_id,
            action: "update".to_string(),
            previous_consents,
            new_consents,
            ip_address: None,
            user_agent: req.user_agent,
            created_at: now,
        };

        diesel::insert_into(consent_history::table)
            .values(&history)
            .execute(&mut conn)
            .map_err(|e| LegalError::Database(e.to_string()))?;

        Ok::<_, LegalError>(db_consent_to_consent(db_consent))
    })
    .await
    .map_err(|e| LegalError::Internal(e.to_string()))??;

    Ok(Json(result))
}

pub async fn handle_get_cookie_policy(
    State(_state): State<Arc<AppState>>,
) -> Result<Json<CookiePolicy>, LegalError> {
    Ok(Json(get_default_cookie_policy()))
}

pub async fn handle_list_documents(
    State(state): State<Arc<AppState>>,
    Query(query): Query<ListDocumentsQuery>,
) -> Result<Json<Vec<LegalDocument>>, LegalError> {
    let pool = state.conn.clone();

    let result = tokio::task::spawn_blocking(move || {
        let mut conn = pool.get().map_err(|e| LegalError::Database(e.to_string()))?;
        let (bot_id, _) = get_default_bot(&mut conn);

        let mut db_query = legal_documents::table
            .filter(legal_documents::bot_id.eq(bot_id))
            .into_boxed();

        if let Some(doc_type) = query.document_type {
            db_query = db_query.filter(legal_documents::document_type.eq(doc_type));
        }

        if query.active_only.unwrap_or(true) {
            db_query = db_query.filter(legal_documents::is_active.eq(true));
        }

        let db_docs: Vec<DbLegalDocument> = db_query
            .order(legal_documents::created_at.desc())
            .load(&mut conn)
            .map_err(|e| LegalError::Database(e.to_string()))?;

        let docs: Vec<LegalDocument> = db_docs.into_iter().map(db_document_to_document).collect();
        Ok::<_, LegalError>(docs)
    })
    .await
    .map_err(|e| LegalError::Internal(e.to_string()))??;

    Ok(Json(result))
}

pub async fn handle_get_document(
    State(state): State<Arc<AppState>>,
    Path(slug): Path<String>,
) -> Result<Json<Option<LegalDocument>>, LegalError> {
    let pool = state.conn.clone();

    let result = tokio::task::spawn_blocking(move || {
        let mut conn = pool.get().map_err(|e| LegalError::Database(e.to_string()))?;
        let (bot_id, _) = get_default_bot(&mut conn);

        let db_doc: Option<DbLegalDocument> = legal_documents::table
            .filter(legal_documents::bot_id.eq(bot_id))
            .filter(legal_documents::slug.eq(&slug))
            .filter(legal_documents::is_active.eq(true))
            .first(&mut conn)
            .optional()
            .map_err(|e| LegalError::Database(e.to_string()))?;

        Ok::<_, LegalError>(db_doc.map(db_document_to_document))
    })
    .await
    .map_err(|e| LegalError::Internal(e.to_string()))??;

    Ok(Json(result))
}

pub async fn handle_create_document(
    State(state): State<Arc<AppState>>,
    Json(req): Json<CreateDocumentRequest>,
) -> Result<Json<LegalDocument>, LegalError> {
    let pool = state.conn.clone();

    let result = tokio::task::spawn_blocking(move || {
        let mut conn = pool.get().map_err(|e| LegalError::Database(e.to_string()))?;
        let (bot_id, _bot_name) = get_default_bot(&mut conn);
        let org_id = Uuid::nil();
        let now = Utc::now();

        let db_doc = DbLegalDocument {
            id: Uuid::new_v4(),
            org_id,
            bot_id,
            slug: req.slug,
            title: req.title,
            content: req.content,
            document_type: req.document_type.to_string(),
            version: req.version.unwrap_or_else(|| "1.0.0".to_string()),
            effective_date: now,
            is_active: true,
            requires_acceptance: req.requires_acceptance.unwrap_or(false),
            metadata: serde_json::json!({}),
            created_by: None,
            created_at: now,
            updated_at: now,
        };

        diesel::insert_into(legal_documents::table)
            .values(&db_doc)
            .execute(&mut conn)
            .map_err(|e| LegalError::Database(e.to_string()))?;

        Ok::<_, LegalError>(db_document_to_document(db_doc))
    })
    .await
    .map_err(|e| LegalError::Internal(e.to_string()))??;

    Ok(Json(result))
}

pub async fn handle_update_document(
    State(state): State<Arc<AppState>>,
    Path(slug): Path<String>,
    Json(req): Json<UpdateDocumentRequest>,
) -> Result<Json<LegalDocument>, LegalError> {
    let pool = state.conn.clone();

    let result = tokio::task::spawn_blocking(move || {
        let mut conn = pool.get().map_err(|e| LegalError::Database(e.to_string()))?;
        let (bot_id, _) = get_default_bot(&mut conn);
        let now = Utc::now();

        let mut db_doc: DbLegalDocument = legal_documents::table
            .filter(legal_documents::bot_id.eq(bot_id))
            .filter(legal_documents::slug.eq(&slug))
            .first(&mut conn)
            .map_err(|_| LegalError::NotFound("Document not found".to_string()))?;

        if let Some(title) = req.title {
            db_doc.title = title;
        }
        if let Some(content) = req.content {
            let version_record = DbDocumentVersion {
                id: Uuid::new_v4(),
                document_id: db_doc.id,
                version: db_doc.version.clone(),
                content: db_doc.content.clone(),
                change_summary: None,
                created_by: None,
                created_at: now,
            };

            diesel::insert_into(legal_document_versions::table)
                .values(&version_record)
                .execute(&mut conn)
                .map_err(|e| LegalError::Database(e.to_string()))?;

            db_doc.content = content;
        }
        if let Some(is_active) = req.is_active {
            db_doc.is_active = is_active;
        }
        if let Some(requires_acceptance) = req.requires_acceptance {
            db_doc.requires_acceptance = requires_acceptance;
        }
        db_doc.updated_at = now;

        diesel::update(legal_documents::table.find(db_doc.id))
            .set(&db_doc)
            .execute(&mut conn)
            .map_err(|e| LegalError::Database(e.to_string()))?;

        Ok::<_, LegalError>(db_document_to_document(db_doc))
    })
    .await
    .map_err(|e| LegalError::Internal(e.to_string()))??;

    Ok(Json(result))
}

pub async fn handle_request_data_deletion(
    State(state): State<Arc<AppState>>,
    Path(user_id): Path<Uuid>,
    Json(req): Json<DataDeletionRequest>,
) -> Result<Json<DataDeletionResult>, LegalError> {
    let pool = state.conn.clone();

    let result = tokio::task::spawn_blocking(move || {
        let mut conn = pool.get().map_err(|e| LegalError::Database(e.to_string()))?;
        let (bot_id, _bot_name) = get_default_bot(&mut conn);
        let org_id = Uuid::nil();
        let now = Utc::now();
        let token = Uuid::new_v4().to_string();

        let db_request = DbDeletionRequest {
            id: Uuid::new_v4(),
            org_id,
            bot_id,
            user_id,
            request_type: "full".to_string(),
            status: "pending".to_string(),
            reason: req.reason,
            requested_at: now,
            scheduled_for: Some(now + chrono::Duration::days(30)),
            completed_at: None,
            confirmation_token: token.clone(),
            confirmed_at: None,
            processed_by: None,
            notes: None,
            created_at: now,
            updated_at: now,
        };

        diesel::insert_into(data_deletion_requests::table)
            .values(&db_request)
            .execute(&mut conn)
            .map_err(|e| LegalError::Database(e.to_string()))?;

        let deleted_consents = diesel::delete(
            cookie_consents::table
                .filter(cookie_consents::bot_id.eq(bot_id))
                .filter(cookie_consents::user_id.eq(user_id)),
        )
        .execute(&mut conn)
        .unwrap_or(0);

        Ok::<_, LegalError>(DataDeletionResult {
            user_id,
            consents_deleted: deleted_consents as i32,
            deleted_at: now,
            confirmation_token: token,
        })
    })
    .await
    .map_err(|e| LegalError::Internal(e.to_string()))??;

    Ok(Json(result))
}

pub async fn handle_export_user_data(
    State(state): State<Arc<AppState>>,
    Path(user_id): Path<Uuid>,
    Json(req): Json<DataExportRequest>,
) -> Result<Json<UserDataExport>, LegalError> {
    let pool = state.conn.clone();

    let result = tokio::task::spawn_blocking(move || {
        let mut conn = pool.get().map_err(|e| LegalError::Database(e.to_string()))?;
        let (bot_id, _bot_name) = get_default_bot(&mut conn);
        let org_id = Uuid::nil();
        let now = Utc::now();

        let format = req.format.unwrap_or_else(|| "json".to_string());
        let sections = req.sections.unwrap_or_else(|| vec!["all".to_string()]);

        let db_export = DbExportRequest {
            id: Uuid::new_v4(),
            org_id,
            bot_id,
            user_id,
            status: "completed".to_string(),
            format: format.clone(),
            include_sections: serde_json::to_value(&sections).unwrap_or_default(),
            requested_at: now,
            started_at: Some(now),
            completed_at: Some(now),
            file_url: None,
            file_size: None,
            expires_at: Some(now + chrono::Duration::days(7)),
            error_message: None,
            created_at: now,
        };

        diesel::insert_into(data_export_requests::table)
            .values(&db_export)
            .execute(&mut conn)
            .map_err(|e| LegalError::Database(e.to_string()))?;

        let db_consents: Vec<DbCookieConsent> = cookie_consents::table
            .filter(cookie_consents::bot_id.eq(bot_id))
            .filter(cookie_consents::user_id.eq(user_id))
            .load(&mut conn)
            .unwrap_or_default();

        let consents: Vec<CookieConsent> = db_consents.into_iter().map(db_consent_to_consent).collect();

        Ok::<_, LegalError>(UserDataExport {
            user_id,
            exported_at: now,
            consents,
            format,
        })
    })
    .await
    .map_err(|e| LegalError::Internal(e.to_string()))??;

    Ok(Json(result))
}

pub struct LegalService {}

impl LegalService {
    pub fn new() -> Self {
        Self {}
    }
}

impl Default for LegalService {
    fn default() -> Self {
        Self::new()
    }
}

pub fn configure_legal_routes() -> Router<Arc<AppState>> {
    Router::new()
        .route("/api/legal/consent", post(handle_record_consent))
        .route("/api/legal/consent/:consent_id", get(handle_get_consent).put(handle_update_consent))
        .route("/api/legal/consent/session", get(handle_get_consent_by_session))
        .route("/api/legal/cookies/policy", get(handle_get_cookie_policy))
        .route("/api/legal/documents", get(handle_list_documents).post(handle_create_document))
        .route("/api/legal/documents/:slug", get(handle_get_document).put(handle_update_document))
        .route("/api/legal/gdpr/delete/:user_id", post(handle_request_data_deletion))
        .route("/api/legal/gdpr/export/:user_id", post(handle_export_user_data))
}
