use std::sync::Arc;

use axum::{
    extract::{Path, State},
    routing::{get, post},
    Json, Router,
};
use serde::{Deserialize, Serialize};
use uuid::Uuid;

use crate::db;
use crate::middleware::auth::AuthUser;
use crate::models::error::{ApiError, ApiResult};
use crate::models::modules::{ModuleWithOwnership, PurchasedModule};
use crate::services::module_installer::ModuleInstaller;
use crate::services::nats_bridge::NatsBridge;
use crate::AppState;

pub fn router() -> Router<Arc<AppState>> {
    Router::new()
        .route("/catalog", get(get_catalog))
        .route("/my-modules", get(get_my_modules))
        .route("/purchase", post(purchase_module))
        .route("/install", post(install_module))
        .route("/:module_id/installation-status", get(get_installation_status))
}

/// GET /api/modules/catalog
/// Returns all modules with is_purchased flag for the authenticated user's license.
async fn get_catalog(
    State(state): State<Arc<AppState>>,
    auth: AuthUser,
) -> ApiResult<Json<CatalogResponse>> {
    let license_id = auth.license_id.ok_or_else(|| {
        ApiError::BadRequest("No license associated with this user".to_string())
    })?;

    let catalog = db::modules::get_catalog_with_ownership(&state.db, license_id).await?;

    Ok(Json(CatalogResponse { modules: catalog }))
}

/// GET /api/modules/my-modules
/// Returns purchased modules with installation status.
async fn get_my_modules(
    State(state): State<Arc<AppState>>,
    auth: AuthUser,
) -> ApiResult<Json<MyModulesResponse>> {
    let license_id = auth.license_id.ok_or_else(|| {
        ApiError::BadRequest("No license associated with this user".to_string())
    })?;

    let modules = db::modules::get_purchased_modules(&state.db, license_id).await?;

    Ok(Json(MyModulesResponse { modules }))
}

/// POST /api/modules/purchase
/// Initiate module purchase (stub for Phase 4 — payment integration is XO's direct touch).
/// For MVP, immediately records the purchase without payment gateway.
async fn purchase_module(
    State(state): State<Arc<AppState>>,
    auth: AuthUser,
    Json(req): Json<PurchaseRequest>,
) -> ApiResult<Json<PurchaseResponse>> {
    let license_id = auth.license_id.ok_or_else(|| {
        ApiError::BadRequest("No license associated with this user".to_string())
    })?;

    // Verify module exists
    let module = db::modules::get_module_by_id(&state.db, req.module_id)
        .await?
        .ok_or_else(|| ApiError::NotFound("Module not found".to_string()))?;

    // Check if already purchased
    let already_purchased = db::modules::is_module_purchased(&state.db, license_id, req.module_id).await?;
    if already_purchased {
        return Err(ApiError::Conflict("Module already purchased".to_string()));
    }

    // Record purchase (no payment gateway for MVP — stub transaction)
    let purchase_id = db::modules::record_module_purchase(
        &state.db,
        license_id,
        req.module_id,
        Some("STUB_TRANSACTION"), // TODO: Replace with real PayPal transaction ID
        Some(module.price_usd),
    ).await?;

    tracing::info!(
        "Module purchase recorded: license={}, module={}, purchase_id={}",
        license_id, req.module_id, purchase_id
    );

    Ok(Json(PurchaseResponse {
        success: true,
        purchase_id,
        message: "Module purchased successfully (payment stub)".to_string(),
    }))
}

/// POST /api/modules/install
/// Trigger module installation (calls panel adapter or companion agent).
async fn install_module(
    State(state): State<Arc<AppState>>,
    auth: AuthUser,
    Json(req): Json<InstallRequest>,
) -> ApiResult<Json<InstallResponse>> {
    let license_id = auth.license_id.ok_or_else(|| {
        ApiError::BadRequest("No license associated with this user".to_string())
    })?;

    // Verify ownership
    let is_purchased = db::modules::is_module_purchased(&state.db, license_id, req.module_id).await?;
    if !is_purchased {
        return Err(ApiError::Forbidden);
    }

    // Verify module exists and get plugin file URL
    let module = db::modules::get_module_by_id(&state.db, req.module_id)
        .await?
        .ok_or_else(|| ApiError::NotFound("Module not found".to_string()))?;

    // Ensure NATS is available
    let nats_client = state
        .nats
        .as_ref()
        .ok_or_else(|| ApiError::Internal("NATS not available".to_string()))?;

    let nats_bridge = Arc::new(NatsBridge::new(nats_client.clone()));
    let installer = ModuleInstaller::new(
        state.db.clone(),
        nats_bridge,
        state.config.encryption_key.clone(),
    );

    // Set status to 'installing' immediately
    db::modules::update_installation_status(
        &state.db,
        license_id,
        req.module_id,
        "installing",
        None,
    ).await?;

    // Spawn background task for installation
    let module_name = module.name.clone();
    tokio::spawn(async move {
        if let Err(e) = installer.install_module(license_id, req.module_id).await {
            tracing::error!(
                "Module installation failed for license {} module {}: {}",
                license_id,
                req.module_id,
                e
            );
        }
    });

    tracing::info!(
        "Module installation triggered: license={}, module={}",
        license_id, req.module_id
    );

    Ok(Json(InstallResponse {
        success: true,
        message: format!("Installation of '{}' started. Check status for progress.", module_name),
    }))
}

/// GET /api/modules/:module_id/installation-status
/// Get installation status for a specific module.
async fn get_installation_status(
    State(state): State<Arc<AppState>>,
    auth: AuthUser,
    Path(module_id): Path<Uuid>,
) -> ApiResult<Json<InstallationStatusResponse>> {
    let license_id = auth.license_id.ok_or_else(|| {
        ApiError::BadRequest("No license associated with this user".to_string())
    })?;

    let installation = db::modules::get_module_installation_status(&state.db, license_id, module_id).await?;

    Ok(Json(InstallationStatusResponse {
        module_id,
        status: installation.as_ref().map(|i| i.status.clone()),
        installed_at: installation.as_ref().and_then(|i| i.installed_at),
        error_message: installation.and_then(|i| i.error_message),
    }))
}

// ===== Request/Response Types =====

#[derive(Debug, Deserialize)]
struct PurchaseRequest {
    module_id: Uuid,
}

#[derive(Debug, Serialize)]
struct PurchaseResponse {
    success: bool,
    purchase_id: Uuid,
    message: String,
}

#[derive(Debug, Deserialize)]
struct InstallRequest {
    module_id: Uuid,
}

#[derive(Debug, Serialize)]
struct InstallResponse {
    success: bool,
    message: String,
}

#[derive(Debug, Serialize)]
struct CatalogResponse {
    modules: Vec<ModuleWithOwnership>,
}

#[derive(Debug, Serialize)]
struct MyModulesResponse {
    modules: Vec<PurchasedModule>,
}

#[derive(Debug, Serialize)]
struct InstallationStatusResponse {
    module_id: Uuid,
    status: Option<String>,
    installed_at: Option<chrono::DateTime<chrono::Utc>>,
    error_message: Option<String>,
}
