//! Policy management handlers for Trust Pack import/export and blessing.

use axum::{http::StatusCode, Json};
use std::path::PathBuf;
use tracing::instrument;

use crate::{
    dto::aphoria::{
        BlessRequest, BlessResponse, ExportPolicyRequest, ExportPolicyResponse,
        ImportPolicyRequest, ImportPolicyResponse,
    },
    error::{ApiError, Result},
};

/// Bless a code pattern as the authoritative standard.
///
/// Creates an assertion with the actual predicate and value that becomes
/// the authoritative standard for future scans.
#[utoipa::path(
    post,
    path = "/v1/aphoria/bless",
    request_body = BlessRequest,
    responses(
        (status = 201, description = "Pattern blessed successfully", body = BlessResponse),
        (status = 400, description = "Invalid request", body = crate::dto::ErrorResponse),
        (status = 500, description = "Internal server error", body = crate::dto::ErrorResponse),
    ),
    tag = "aphoria"
)]
#[instrument(skip_all, fields(concept_path = %req.concept_path, predicate = %req.predicate))]
pub async fn bless(Json(req): Json<BlessRequest>) -> Result<(StatusCode, Json<BlessResponse>)> {
    // Load config from current directory
    let config_path = std::env::current_dir()
        .map_err(|e| ApiError::Internal(format!("Failed to get current directory: {}", e)))?
        .join("aphoria.toml");

    let config = if config_path.exists() {
        aphoria::AphoriaConfig::from_file(&config_path)
            .map_err(|e| ApiError::Internal(format!("Failed to load config: {}", e)))?
    } else {
        aphoria::AphoriaConfig::default()
    };

    // Create bless args
    let args = aphoria::BlessArgs {
        concept_path: req.concept_path.clone(),
        predicate: req.predicate.clone(),
        value: req.value,
        reason: req.reason,
    };

    // Execute bless operation
    aphoria::bless(args, &config)
        .await
        .map_err(|e| ApiError::Internal(format!("Bless failed: {}", e)))?;

    Ok((
        StatusCode::CREATED,
        Json(BlessResponse {
            success: true,
            message: "Pattern blessed as authoritative standard".to_string(),
            concept_path: req.concept_path,
        }),
    ))
}

/// Export policy assertions as a Trust Pack.
///
/// Collects all acknowledged conflicts and manual aliases into a signed
/// Trust Pack that can be shared with other projects.
#[utoipa::path(
    post,
    path = "/v1/aphoria/policy/export",
    request_body = ExportPolicyRequest,
    responses(
        (status = 200, description = "Policy exported successfully", body = ExportPolicyResponse),
        (status = 400, description = "Invalid request", body = crate::dto::ErrorResponse),
        (status = 500, description = "Internal server error", body = crate::dto::ErrorResponse),
    ),
    tag = "aphoria"
)]
#[instrument(skip_all, fields(name = %req.name))]
pub async fn export_policy(
    Json(req): Json<ExportPolicyRequest>,
) -> Result<Json<ExportPolicyResponse>> {
    use aphoria::TrustPack;

    // Load config
    let config_path = std::env::current_dir()
        .map_err(|e| ApiError::Internal(format!("Failed to get current directory: {}", e)))?
        .join("aphoria.toml");

    let config = if config_path.exists() {
        aphoria::AphoriaConfig::from_file(&config_path)
            .map_err(|e| ApiError::Internal(format!("Failed to load config: {}", e)))?
    } else {
        aphoria::AphoriaConfig::default()
    };

    // Determine output path
    let output_path = req
        .output_path
        .map(PathBuf::from)
        .unwrap_or_else(|| PathBuf::from(format!("{}.pack", req.name)));

    // Execute export
    aphoria::export_policy(req.name.clone(), output_path.clone(), &config)
        .await
        .map_err(|e| ApiError::Internal(format!("Export failed: {}", e)))?;

    // Load the pack to get stats
    let pack = TrustPack::load(&output_path)
        .map_err(|e| ApiError::Internal(format!("Failed to read exported pack: {}", e)))?;

    let issuer_hex = hex::encode(&pack.header.issuer_id[..4]);

    Ok(Json(ExportPolicyResponse {
        pack_path: Some(output_path.to_string_lossy().to_string()),
        assertions_count: pack.assertions.len(),
        aliases_count: pack.aliases.len(),
        issuer_hex,
        pack_name: pack.header.name,
        pack_version: pack.header.version,
    }))
}

/// Import a Trust Pack into the local Episteme.
///
/// Loads and verifies the pack's signature, then imports assertions
/// and aliases into the local storage.
#[utoipa::path(
    post,
    path = "/v1/aphoria/policy/import",
    request_body = ImportPolicyRequest,
    responses(
        (status = 200, description = "Policy imported successfully", body = ImportPolicyResponse),
        (status = 400, description = "Invalid request", body = crate::dto::ErrorResponse),
        (status = 404, description = "Pack file not found", body = crate::dto::ErrorResponse),
        (status = 500, description = "Internal server error", body = crate::dto::ErrorResponse),
    ),
    tag = "aphoria"
)]
#[instrument(skip_all, fields(pack_path = %req.pack_path))]
pub async fn import_policy(
    Json(req): Json<ImportPolicyRequest>,
) -> Result<Json<ImportPolicyResponse>> {
    use aphoria::TrustPack;

    let pack_path = PathBuf::from(&req.pack_path);

    // Check file exists
    if !pack_path.exists() {
        return Err(ApiError::NotFound(format!("Pack file not found: {}", req.pack_path)));
    }

    // Load config
    let config_path = std::env::current_dir()
        .map_err(|e| ApiError::Internal(format!("Failed to get current directory: {}", e)))?
        .join("aphoria.toml");

    let config = if config_path.exists() {
        aphoria::AphoriaConfig::from_file(&config_path)
            .map_err(|e| ApiError::Internal(format!("Failed to load config: {}", e)))?
    } else {
        aphoria::AphoriaConfig::default()
    };

    // Load pack first to get metadata
    let pack = TrustPack::load(&pack_path)
        .map_err(|e| ApiError::Internal(format!("Failed to load pack: {}", e)))?;

    let pack_name = pack.header.name.clone();
    let pack_version = pack.header.version.clone();
    let issuer_hex = hex::encode(&pack.header.issuer_id[..4]);

    // Execute import
    let stats = aphoria::import_policy(pack_path, &config)
        .await
        .map_err(|e| ApiError::Internal(format!("Import failed: {}", e)))?;

    Ok(Json(ImportPolicyResponse {
        success: true,
        assertions_imported: stats.assertions_imported,
        aliases_imported: stats.aliases_imported,
        pack_name,
        pack_version,
        issuer_hex,
    }))
}
