use std::sync::Arc;

use axum::{
    extract::{Extension, Path, Query, State},
    http::StatusCode,
    response::IntoResponse,
    Json,
};
use ontoref_derive::onto_api;
use serde::{Deserialize, Serialize};
use tracing::{error, info};

use crate::error::{auth, http, infrastructure, ControlCenterError};
use crate::middleware::auth::SecurityContext;
use crate::middleware::cedar::{SecretAccessContext, SecretAuthorizationRequest, SecretCedarAuthz};
use crate::services::secret_sharing::CreateGrantRequest as ServiceCreateGrantRequest;
use crate::services::secrets::{
    CreateSecretRequest as ServiceCreateSecretRequest,
    ListSecretsRequest as ServiceListSecretsRequest, SecretType,
    UpdateSecretRequest as ServiceUpdateSecretRequest,
};
use crate::services::AccessPermission;
use crate::AppState;

/// Request to create or update a secret
#[derive(Debug, Serialize, Deserialize)]
pub struct CreateSecretRequest {
    /// Secret path (e.g., "database/prod/password")
    pub path: String,
    /// Secret value (plaintext, will be encrypted)
    pub value: String,
    /// Workspace identifier
    pub workspace_id: String,
    /// Infrastructure identifier (optional)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub infra_id: Option<String>,
    /// Domain/service grouping
    pub domain: String,
    /// Secret type classification
    pub secret_type: SecretType,
    /// Optional tags for organization
    #[serde(default)]
    pub tags: Vec<String>,
    /// Optional TTL in seconds
    #[serde(skip_serializing_if = "Option::is_none")]
    pub ttl_seconds: Option<i64>,
    /// Enable auto-rotation
    #[serde(default)]
    pub auto_rotate: bool,
    /// Auto-rotation interval in days
    #[serde(skip_serializing_if = "Option::is_none")]
    pub rotation_interval_days: Option<i32>,
    /// Optional encryption context for AAD
    #[serde(skip_serializing_if = "Option::is_none")]
    pub context: Option<String>,
    /// Metadata (tags, description, owner, etc.)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub metadata: Option<serde_json::Value>,
}

/// Request to update an existing secret
#[derive(Debug, Serialize, Deserialize)]
pub struct UpdateSecretRequest {
    /// New secret value
    pub value: String,
    /// Optional tags
    #[serde(default)]
    pub tags: Vec<String>,
    /// Optional TTL in seconds
    #[serde(skip_serializing_if = "Option::is_none")]
    pub ttl_seconds: Option<i64>,
    /// Enable auto-rotation
    #[serde(default)]
    pub auto_rotate: bool,
    /// Auto-rotation interval in days
    #[serde(skip_serializing_if = "Option::is_none")]
    pub rotation_interval_days: Option<i32>,
    /// Optional encryption context
    #[serde(skip_serializing_if = "Option::is_none")]
    pub context: Option<String>,
    /// Updated metadata
    #[serde(skip_serializing_if = "Option::is_none")]
    pub metadata: Option<serde_json::Value>,
}

/// Response for secret creation/update
#[derive(Debug, Serialize, Deserialize)]
pub struct SecretResponse {
    pub id: String,
    pub path: String,
    pub version: i32,
    pub workspace_id: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub infra_id: Option<String>,
    pub domain: String,
    pub secret_type: SecretType,
    pub tags: Vec<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub ttl_seconds: Option<i64>,
    pub auto_rotate: bool,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub rotation_interval_days: Option<i32>,
    pub created_at: String,
    pub updated_at: String,
    pub created_by: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub metadata: Option<serde_json::Value>,
}

/// Response for secret retrieval (includes decrypted value)
#[derive(Debug, Serialize, Deserialize)]
pub struct SecretValueResponse {
    pub id: String,
    pub path: String,
    pub value: String, // Decrypted value
    pub version: i32,
    pub workspace_id: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub infra_id: Option<String>,
    pub domain: String,
    pub secret_type: SecretType,
    pub tags: Vec<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub ttl_seconds: Option<i64>,
    pub auto_rotate: bool,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub rotation_interval_days: Option<i32>,
    pub created_at: String,
    pub updated_at: String,
    pub created_by: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub metadata: Option<serde_json::Value>,
}

/// Response for listing secrets
#[derive(Debug, Serialize, Deserialize)]
pub struct ListSecretsResponse {
    pub secrets: Vec<SecretResponse>,
    pub total: usize,
}

/// Response for secret history/versions
#[derive(Debug, Serialize, Deserialize)]
pub struct SecretVersion {
    pub version: i32,
    pub created_at: String,
    pub created_by: String,
    pub deleted: bool,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct SecretHistoryResponse {
    pub path: String,
    pub versions: Vec<SecretVersion>,
}

/// Query parameters for listing secrets
#[derive(Debug, Deserialize)]
pub struct ListSecretsQuery {
    /// Filter by workspace
    #[serde(default)]
    pub workspace_id: Option<String>,
    /// Filter by domain
    #[serde(default)]
    pub domain: Option<String>,
    /// Filter by tag
    #[serde(default)]
    pub tag: Option<String>,
    /// Search by path prefix
    #[serde(default)]
    pub prefix: Option<String>,
    /// Pagination limit
    #[serde(default = "default_limit")]
    pub limit: usize,
    /// Pagination offset
    #[serde(default)]
    pub offset: usize,
}

fn default_limit() -> usize {
    100
}

/// Handler: Create a new secret
#[onto_api(
    method = "POST",
    path = "/secrets",
    description = "Create a new secret",
    auth = "admin",
    actors = "developer",
    tags = "secrets",
    feature = ""
)]
pub async fn create_secret(
    State(app_state): State<Arc<AppState>>,
    Extension(security_ctx): Extension<SecurityContext>,
    Json(request): Json<CreateSecretRequest>,
) -> Result<impl IntoResponse, ControlCenterError> {
    let service = &app_state.secrets_service;
    info!(
        user_id = %security_ctx.user_id,
        path = %request.path,
        workspace = %request.workspace_id,
        "Creating vault secret"
    );

    // Build Cedar authorization request
    let secret_context = SecretAccessContext {
        workspace_id: request.workspace_id.clone(),
        domain: request.domain.clone(),
        secret_type: format!("{:?}", request.secret_type),
        tags: request.tags.clone(),
        is_expired: false,
        ttl_hours: request.ttl_seconds.unwrap_or(0) / 3600,
        auto_rotate: request.auto_rotate,
    };

    let authz_request = SecretAuthorizationRequest {
        user_id: security_ctx.user_id,
        roles: security_ctx.roles.clone(),
        teams: derive_teams_from_roles(&security_ctx.roles), // Phase 2: Derive from roles
        secret_context,
        action: "create".to_string(),
        mfa_verified: security_ctx.mfa_verified,
        ip_address: security_ctx
            .ip_address
            .clone()
            .unwrap_or_else(|| "127.0.0.1".to_string()), // Phase 2: Real IP extraction
        time: chrono::Utc::now().to_rfc3339(),
        approval_id: security_ctx.approval_id.clone(), // Phase 2: From request headers
    };

    // Perform Cedar authorization
    let cedar_authz = SecretCedarAuthz::new();
    cedar_authz.authorize(&authz_request).await.map_err(|_| {
        error!(
            user_id = %security_ctx.user_id,
            path = %request.path,
            "Cedar authorization denied for secret creation"
        );
        ControlCenterError::Auth(auth::forbidden("Authorization denied by security policy"))
    })?;

    // Create secret via service layer
    let user_id_str = security_ctx.user_id.to_string();
    let secret = service
        .create_secret(ServiceCreateSecretRequest {
            path: &request.path,
            value: &request.value,
            workspace_id: &request.workspace_id,
            infra_id: request.infra_id.as_deref(),
            domain: &request.domain,
            secret_type: request.secret_type,
            tags: request.tags,
            ttl_seconds: request.ttl_seconds,
            auto_rotate: request.auto_rotate,
            rotation_interval_days: request.rotation_interval_days,
            context: request.context.as_deref(),
            metadata: request.metadata,
            user_id: &user_id_str,
        })
        .await
        .map_err(|e| {
            error!(error = %e, "Failed to create secret");
            ControlCenterError::from(infrastructure::internal_error(&format!(
                "Failed to create secret: {}",
                e
            )))
        })?;

    info!(
        user_id = %security_ctx.user_id,
        path = %request.path,
        secret_id = %secret.id,
        "Secret created successfully"
    );

    Ok((StatusCode::CREATED, Json(secret)))
}

/// Handler: Get a secret value (decrypted)
#[onto_api(
    method = "GET",
    path = "/secrets/{path}",
    description = "Get a secret value by path",
    auth = "admin",
    actors = "developer",
    tags = "secrets",
    feature = ""
)]
pub async fn get_secret(
    State(app_state): State<Arc<AppState>>,
    Extension(security_ctx): Extension<SecurityContext>,
    Path(path): Path<String>,
    Query(query): Query<GetSecretQuery>,
) -> Result<impl IntoResponse, ControlCenterError> {
    let service = &app_state.secrets_service;
    info!(
        user_id = %security_ctx.user_id,
        path = %path,
        "Retrieving vault secret"
    );

    // Get secret metadata first to extract context for authorization
    let secret = service
        .get_secret(
            &path,
            query.version,
            query.context.as_deref(),
            &security_ctx.user_id.to_string(),
        )
        .await
        .map_err(|e| {
            error!(error = %e, path = %path, "Failed to retrieve secret");
            match e.to_string().as_str() {
                s if s.contains("not found") => ControlCenterError::from(
                    infrastructure::internal_error(&format!("Secret not found: {}", path)),
                ),
                _ => ControlCenterError::from(infrastructure::internal_error(&format!(
                    "Failed to retrieve secret: {}",
                    e
                ))),
            }
        })?;

    // Build Cedar authorization request
    let secret_context = SecretAccessContext {
        workspace_id: secret.workspace_id.clone(),
        domain: secret.domain.clone(),
        secret_type: format!("{:?}", secret.secret_type),
        tags: secret.tags.clone(),
        is_expired: false,
        ttl_hours: secret.ttl_seconds.unwrap_or(0) / 3600,
        auto_rotate: secret.auto_rotate,
    };

    let authz_request = SecretAuthorizationRequest {
        user_id: security_ctx.user_id,
        roles: security_ctx.roles.clone(),
        teams: vec![],
        secret_context,
        action: "access".to_string(),
        mfa_verified: security_ctx.mfa_verified,
        ip_address: "0.0.0.0".to_string(),
        time: chrono::Utc::now().to_rfc3339(),
        approval_id: None,
    };

    // Perform Cedar authorization
    let cedar_authz = SecretCedarAuthz::new();
    cedar_authz.authorize(&authz_request).await.map_err(|_| {
        error!(
            user_id = %security_ctx.user_id,
            path = %path,
            "Cedar authorization denied for secret access"
        );
        ControlCenterError::Auth(auth::forbidden("Authorization denied by security policy"))
    })?;

    info!(
        user_id = %security_ctx.user_id,
        path = %path,
        "Secret retrieved successfully"
    );

    Ok(Json(secret))
}

#[derive(Debug, Deserialize)]
pub struct GetSecretQuery {
    #[serde(default)]
    pub version: Option<i32>,
    #[serde(default)]
    pub context: Option<String>,
}

/// Handler: List secrets
#[onto_api(
    method = "GET",
    path = "/secrets",
    description = "List all secrets",
    auth = "admin",
    actors = "developer",
    tags = "secrets",
    feature = ""
)]
pub async fn list_secrets(
    State(app_state): State<Arc<AppState>>,
    Extension(security_ctx): Extension<SecurityContext>,
    Query(query): Query<ListSecretsQuery>,
) -> Result<impl IntoResponse, ControlCenterError> {
    let service = &app_state.secrets_service;
    info!(
        user_id = %security_ctx.user_id,
        prefix = ?query.prefix,
        "Listing vault secrets"
    );

    let user_id_str = security_ctx.user_id.to_string();
    let (secrets, total) = service
        .list_secrets(ServiceListSecretsRequest {
            workspace_id: query.workspace_id.as_deref(),
            domain: query.domain.as_deref(),
            tag: query.tag.as_deref(),
            prefix: query.prefix.as_deref(),
            limit: query.limit,
            offset: query.offset,
            user_id: &user_id_str,
        })
        .await
        .map_err(|e| {
            error!(error = %e, "Failed to list secrets");
            ControlCenterError::from(infrastructure::internal_error(&format!(
                "Failed to list secrets: {}",
                e
            )))
        })?;

    Ok(Json(ListSecretsResponse { secrets, total }))
}

/// Handler: Update a secret (creates new version)
#[onto_api(
    method = "PUT",
    path = "/secrets/{path}",
    description = "Update a secret, creating a new version",
    auth = "admin",
    actors = "developer",
    tags = "secrets",
    feature = ""
)]
pub async fn update_secret(
    State(app_state): State<Arc<AppState>>,
    Extension(security_ctx): Extension<SecurityContext>,
    Path(path): Path<String>,
    Json(request): Json<UpdateSecretRequest>,
) -> Result<impl IntoResponse, ControlCenterError> {
    let service = &app_state.secrets_service;
    info!(
        user_id = %security_ctx.user_id,
        path = %path,
        "Updating vault secret"
    );

    // Get secret metadata first to extract context for authorization
    let existing_secret = service
        .get_secret(
            &path,
            None,
            request.context.as_deref(),
            &security_ctx.user_id.to_string(),
        )
        .await
        .map_err(|e| {
            error!(error = %e, path = %path, "Failed to retrieve secret for authorization");
            ControlCenterError::from(infrastructure::internal_error(&format!(
                "Failed to retrieve secret: {}",
                e
            )))
        })?;

    // Build Cedar authorization request
    let secret_context = SecretAccessContext {
        workspace_id: existing_secret.workspace_id.clone(),
        domain: existing_secret.domain.clone(),
        secret_type: format!("{:?}", existing_secret.secret_type),
        tags: existing_secret.tags.clone(),
        is_expired: false,
        ttl_hours: request.ttl_seconds.unwrap_or(0) / 3600,
        auto_rotate: request.auto_rotate,
    };

    let authz_request = SecretAuthorizationRequest {
        user_id: security_ctx.user_id,
        roles: security_ctx.roles.clone(),
        teams: vec![],
        secret_context,
        action: "update".to_string(),
        mfa_verified: security_ctx.mfa_verified,
        ip_address: "0.0.0.0".to_string(),
        time: chrono::Utc::now().to_rfc3339(),
        approval_id: None,
    };

    // Perform Cedar authorization
    let cedar_authz = SecretCedarAuthz::new();
    cedar_authz.authorize(&authz_request).await.map_err(|_| {
        error!(
            user_id = %security_ctx.user_id,
            path = %path,
            "Cedar authorization denied for secret update"
        );
        ControlCenterError::Auth(auth::forbidden("Authorization denied by security policy"))
    })?;

    let user_id_str = security_ctx.user_id.to_string();
    let secret = service
        .update_secret(ServiceUpdateSecretRequest {
            path: &path,
            value: &request.value,
            tags: if request.tags.is_empty() {
                None
            } else {
                Some(request.tags)
            },
            ttl_seconds: request.ttl_seconds,
            auto_rotate: if request.auto_rotate {
                Some(request.auto_rotate)
            } else {
                None
            },
            rotation_interval_days: request.rotation_interval_days,
            context: request.context.as_deref(),
            metadata: request.metadata,
            user_id: &user_id_str,
        })
        .await
        .map_err(|e| {
            error!(error = %e, path = %path, "Failed to update secret");
            ControlCenterError::from(infrastructure::internal_error(&format!(
                "Failed to update secret: {}",
                e
            )))
        })?;

    info!(
        user_id = %security_ctx.user_id,
        path = %path,
        version = secret.version,
        "Secret updated successfully"
    );

    Ok(Json(secret))
}

/// Handler: Delete a secret
#[onto_api(
    method = "DELETE",
    path = "/secrets/{path}",
    description = "Delete a secret",
    auth = "admin",
    actors = "developer",
    tags = "secrets",
    feature = ""
)]
pub async fn delete_secret(
    State(app_state): State<Arc<AppState>>,
    Extension(security_ctx): Extension<SecurityContext>,
    Path(path): Path<String>,
) -> Result<impl IntoResponse, ControlCenterError> {
    let service = &app_state.secrets_service;
    info!(
        user_id = %security_ctx.user_id,
        path = %path,
        "Deleting vault secret"
    );

    // Get secret metadata first to extract context for authorization
    let existing_secret = service
        .get_secret(&path, None, None, &security_ctx.user_id.to_string())
        .await
        .map_err(|e| {
            error!(error = %e, path = %path, "Failed to retrieve secret for authorization");
            ControlCenterError::from(infrastructure::internal_error(&format!(
                "Failed to retrieve secret: {}",
                e
            )))
        })?;

    // Build Cedar authorization request
    let secret_context = SecretAccessContext {
        workspace_id: existing_secret.workspace_id.clone(),
        domain: existing_secret.domain.clone(),
        secret_type: format!("{:?}", existing_secret.secret_type),
        tags: existing_secret.tags.clone(),
        is_expired: false,
        ttl_hours: existing_secret.ttl_seconds.unwrap_or(0) / 3600,
        auto_rotate: existing_secret.auto_rotate,
    };

    let authz_request = SecretAuthorizationRequest {
        user_id: security_ctx.user_id,
        roles: security_ctx.roles.clone(),
        teams: derive_teams_from_roles(&security_ctx.roles), // Phase 2: Derive from roles
        secret_context,
        action: "delete".to_string(),
        mfa_verified: security_ctx.mfa_verified,
        ip_address: security_ctx
            .ip_address
            .clone()
            .unwrap_or_else(|| "127.0.0.1".to_string()), // Phase 2: Real IP extraction
        time: chrono::Utc::now().to_rfc3339(),
        approval_id: security_ctx.approval_id.clone(), // Phase 2: From request headers
    };

    // Perform Cedar authorization
    let cedar_authz = SecretCedarAuthz::new();
    cedar_authz.authorize(&authz_request).await.map_err(|_| {
        error!(
            user_id = %security_ctx.user_id,
            path = %path,
            "Cedar authorization denied for secret deletion"
        );
        ControlCenterError::Auth(auth::forbidden("Authorization denied by security policy"))
    })?;

    service
        .delete_secret(&path, &security_ctx.user_id.to_string())
        .await
        .map_err(|e| {
            error!(error = %e, path = %path, "Failed to delete secret");
            ControlCenterError::from(infrastructure::internal_error(&format!(
                "Failed to delete secret: {}",
                e
            )))
        })?;

    info!(
        user_id = %security_ctx.user_id,
        path = %path,
        "Secret deleted successfully"
    );

    Ok(StatusCode::NO_CONTENT)
}

/// Handler: Get secret history/versions
#[onto_api(
    method = "GET",
    path = "/secrets/{path}/history",
    description = "Get version history for a secret",
    auth = "admin",
    actors = "developer",
    tags = "secrets",
    feature = ""
)]
pub async fn get_secret_history(
    State(app_state): State<Arc<AppState>>,
    Extension(security_ctx): Extension<SecurityContext>,
    Path(path): Path<String>,
) -> Result<impl IntoResponse, ControlCenterError> {
    let service = &app_state.secrets_service;
    info!(
        user_id = %security_ctx.user_id,
        path = %path,
        "Retrieving secret history"
    );

    let history = service
        .get_secret_history(&path, &security_ctx.user_id.to_string())
        .await
        .map_err(|e| {
            error!(error = %e, path = %path, "Failed to retrieve secret history");
            ControlCenterError::from(infrastructure::internal_error(&format!(
                "Failed to retrieve secret history: {}",
                e
            )))
        })?;

    Ok(Json(history))
}

/// Handler: Restore a specific version of a secret
#[onto_api(
    method = "POST",
    path = "/secrets/{path}/restore/{version}",
    description = "Restore a secret to a specific version",
    auth = "admin",
    actors = "developer",
    tags = "secrets",
    feature = ""
)]
pub async fn restore_secret_version(
    State(app_state): State<Arc<AppState>>,
    Extension(security_ctx): Extension<SecurityContext>,
    Path((path, version)): Path<(String, i32)>,
) -> Result<impl IntoResponse, ControlCenterError> {
    let service = &app_state.secrets_service;
    info!(
        user_id = %security_ctx.user_id,
        path = %path,
        version = version,
        "Restoring secret version"
    );

    // Get secret metadata first to extract context for authorization
    let existing_secret = service
        .get_secret(&path, None, None, &security_ctx.user_id.to_string())
        .await
        .map_err(|e| {
            error!(error = %e, path = %path, "Failed to retrieve secret for authorization");
            ControlCenterError::from(infrastructure::internal_error(&format!(
                "Failed to retrieve secret: {}",
                e
            )))
        })?;

    // Build Cedar authorization request
    let secret_context = SecretAccessContext {
        workspace_id: existing_secret.workspace_id.clone(),
        domain: existing_secret.domain.clone(),
        secret_type: format!("{:?}", existing_secret.secret_type),
        tags: existing_secret.tags.clone(),
        is_expired: false,
        ttl_hours: existing_secret.ttl_seconds.unwrap_or(0) / 3600,
        auto_rotate: existing_secret.auto_rotate,
    };

    let authz_request = SecretAuthorizationRequest {
        user_id: security_ctx.user_id,
        roles: security_ctx.roles.clone(),
        teams: derive_teams_from_roles(&security_ctx.roles), // Phase 2: Derive from roles
        secret_context,
        action: "update".to_string(), // Restore is a type of update
        mfa_verified: security_ctx.mfa_verified,
        ip_address: security_ctx
            .ip_address
            .clone()
            .unwrap_or_else(|| "127.0.0.1".to_string()), // Phase 2: Real IP extraction
        time: chrono::Utc::now().to_rfc3339(),
        approval_id: security_ctx.approval_id.clone(), // Phase 2: From request headers
    };

    // Perform Cedar authorization
    let cedar_authz = SecretCedarAuthz::new();
    cedar_authz.authorize(&authz_request).await.map_err(|_| {
        error!(
            user_id = %security_ctx.user_id,
            path = %path,
            "Cedar authorization denied for secret restore"
        );
        ControlCenterError::Auth(auth::forbidden("Authorization denied by security policy"))
    })?;

    let secret = service
        .restore_secret_version(&path, version, &security_ctx.user_id.to_string())
        .await
        .map_err(|e| {
            error!(error = %e, path = %path, version = version, "Failed to restore secret version");
            ControlCenterError::from(infrastructure::internal_error(&format!(
                "Failed to restore secret version: {}",
                e
            )))
        })?;

    info!(
        user_id = %security_ctx.user_id,
        path = %path,
        restored_version = version,
        new_version = secret.version,
        "Secret version restored successfully"
    );

    Ok(Json(secret))
}

/// Phase 2: Derive team memberships from user roles
///
/// Maps user roles to team assignments for Cedar context building.
/// This function expands roles like "admin", "developer", etc. into team
/// affiliations.
fn derive_teams_from_roles(roles: &[String]) -> Vec<String> {
    roles
        .iter()
        .filter_map(|role| {
            // Map roles to teams
            match role.as_str() {
                "admin" => Some("security_team".to_string()),
                "security_admin" => Some("security_team".to_string()),
                "developer" => Some("engineering_team".to_string()),
                "operator" => Some("operations_team".to_string()),
                "database_admin" => Some("data_team".to_string()),
                _ => None,
            }
        })
        .collect()
}

// ============== PHASE 3.1: ROTATION HANDLERS ==============

/// Request to force rotate a secret
#[derive(Debug, Serialize, Deserialize)]
pub struct ForceRotateRequest {
    /// Reason for the rotation
    #[serde(default)]
    pub reason: String,
}

/// Response for rotation status
#[derive(Debug, Serialize, Deserialize)]
pub struct RotationStatusResponse {
    /// Secret path
    pub path: String,
    /// Current rotation status: "pending", "in_progress", "completed",
    /// "failed", "disabled"
    pub status: String,
    /// Next scheduled rotation time
    pub next_rotation: String,
    /// Last rotation time (if completed)
    pub last_rotation: Option<String>,
    /// Days until next rotation
    pub days_remaining: i32,
    /// Failure count (if failed)
    pub failure_count: i32,
}

/// Handler: Force rotate a secret
#[onto_api(
    method = "POST",
    path = "/secrets/{path}/rotate",
    description = "Force rotate a secret",
    auth = "admin",
    actors = "developer",
    tags = "secrets",
    feature = ""
)]
pub async fn force_rotate_secret(
    State(app_state): State<Arc<AppState>>,
    Extension(security_ctx): Extension<SecurityContext>,
    Path(path): Path<String>,
    Json(request): Json<ForceRotateRequest>,
) -> Result<impl IntoResponse, ControlCenterError> {
    info!(
        user_id = %security_ctx.user_id,
        path = %path,
        reason = %request.reason,
        "Force rotating secret"
    );

    // Get secret to check authorization
    let secret = app_state
        .secrets_service
        .get_secret(&path, None, None, &security_ctx.user_id.to_string())
        .await
        .map_err(|e| {
            error!(error = %e, path = %path, "Failed to retrieve secret");
            ControlCenterError::from(infrastructure::internal_error(&format!(
                "Secret not found: {}",
                path
            )))
        })?;

    // Build Cedar authorization request for rotation
    let secret_context = SecretAccessContext {
        workspace_id: secret.workspace_id.clone(),
        domain: secret.domain.clone(),
        secret_type: format!("{:?}", secret.secret_type),
        tags: secret.tags.clone(),
        is_expired: false,
        ttl_hours: secret.ttl_seconds.unwrap_or(0) / 3600,
        auto_rotate: secret.auto_rotate,
    };

    let authz_request = SecretAuthorizationRequest {
        user_id: security_ctx.user_id,
        roles: security_ctx.roles.clone(),
        teams: derive_teams_from_roles(&security_ctx.roles),
        secret_context,
        action: "rotate".to_string(),
        mfa_verified: security_ctx.mfa_verified,
        ip_address: security_ctx
            .ip_address
            .clone()
            .unwrap_or_else(|| "127.0.0.1".to_string()),
        time: chrono::Utc::now().to_rfc3339(),
        approval_id: security_ctx.approval_id.clone(),
    };

    // Perform Cedar authorization
    let cedar_authz = SecretCedarAuthz::new();
    cedar_authz.authorize(&authz_request).await.map_err(|_| {
        error!(
            user_id = %security_ctx.user_id,
            path = %path,
            "Cedar authorization denied for rotation"
        );
        ControlCenterError::Auth(auth::forbidden("Authorization denied by security policy"))
    })?;

    // Create rotation schedule for this secret
    let rotation_service = &app_state.rotation_scheduler;
    let schedule = rotation_service
        .create_schedule(&path, "database", "prod")
        .await
        .map_err(|e| {
            error!(error = %e, path = %path, "Failed to create rotation schedule");
            ControlCenterError::from(infrastructure::internal_error(&format!(
                "Failed to create rotation schedule: {}",
                e
            )))
        })?;

    info!(
        user_id = %security_ctx.user_id,
        path = %path,
        "Secret rotation scheduled"
    );

    // Calculate days remaining
    let now = chrono::Utc::now();
    let next = chrono::DateTime::parse_from_rfc3339(&schedule.next_rotation)
        .ok()
        .map(|dt| dt.with_timezone(&chrono::Utc))
        .map(|dt| (dt.timestamp() - now.timestamp()) / 86400)
        .unwrap_or(0) as i32;

    Ok((
        StatusCode::ACCEPTED,
        Json(RotationStatusResponse {
            path,
            status: format!("{:?}", schedule.status).to_lowercase(),
            next_rotation: schedule.next_rotation.clone(),
            last_rotation: schedule.last_rotation.clone(),
            days_remaining: next,
            failure_count: schedule.failure_count,
        }),
    ))
}

/// Handler: Get rotation status for a secret
#[onto_api(
    method = "GET",
    path = "/secrets/{path}/rotation-status",
    description = "Get rotation status for a secret",
    auth = "admin",
    actors = "developer",
    tags = "secrets",
    feature = ""
)]
pub async fn get_rotation_status(
    State(app_state): State<Arc<AppState>>,
    Extension(security_ctx): Extension<SecurityContext>,
    Path(path): Path<String>,
) -> Result<impl IntoResponse, ControlCenterError> {
    info!(
        user_id = %security_ctx.user_id,
        path = %path,
        "Getting rotation status"
    );

    let rotation_service = &app_state.rotation_scheduler;
    let schedule = rotation_service
        .get_schedule(&path)
        .await
        .map_err(|e| {
            error!(error = %e, path = %path, "Failed to get rotation schedule");
            ControlCenterError::from(infrastructure::internal_error(&format!(
                "Failed to get rotation schedule: {}",
                e
            )))
        })?
        .ok_or_else(|| {
            ControlCenterError::from(infrastructure::internal_error(&format!(
                "No rotation schedule for: {}",
                path
            )))
        })?;

    // Calculate days remaining
    let now = chrono::Utc::now();
    let next = chrono::DateTime::parse_from_rfc3339(&schedule.next_rotation)
        .ok()
        .map(|dt| dt.with_timezone(&chrono::Utc))
        .map(|dt| (dt.timestamp() - now.timestamp()) / 86400)
        .unwrap_or(0) as i32;

    Ok(Json(RotationStatusResponse {
        path,
        status: format!("{:?}", schedule.status).to_lowercase(),
        next_rotation: schedule.next_rotation.clone(),
        last_rotation: schedule.last_rotation.clone(),
        days_remaining: next,
        failure_count: schedule.failure_count,
    }))
}

// ============== PHASE 3.2: SECRET SHARING HANDLERS ==============

/// Request to create a secret grant
#[derive(Debug, Serialize, Deserialize)]
pub struct CreateGrantRequest {
    /// Source workspace ID
    pub source_workspace: String,
    /// Target workspace ID
    pub target_workspace: String,
    /// Permission level: "read", "read_write", "rotate"
    pub permission: String,
    /// Whether approval is required
    #[serde(default)]
    pub require_approval: bool,
}

/// Response for grant operations
#[derive(Debug, Serialize, Deserialize)]
pub struct GrantResponse {
    pub grant_id: String,
    pub secret_path: String,
    pub source_workspace: String,
    pub target_workspace: String,
    pub permission: String,
    pub status: String,
    pub granted_at: String,
    pub access_count: usize,
}

/// Handler: Create a secret grant (sharing)
#[onto_api(
    method = "POST",
    path = "/secrets/{path}/grant",
    description = "Create a grant to share a secret",
    auth = "admin",
    actors = "developer",
    tags = "secrets",
    feature = ""
)]
pub async fn create_grant(
    State(app_state): State<Arc<AppState>>,
    Extension(security_ctx): Extension<SecurityContext>,
    Path(path): Path<String>,
    Json(request): Json<CreateGrantRequest>,
) -> Result<impl IntoResponse, ControlCenterError> {
    info!(
        user_id = %security_ctx.user_id,
        path = %path,
        target_workspace = %request.target_workspace,
        "Creating secret grant"
    );

    let secret_sharing = &app_state.secret_sharing;
    let permission = match request.permission.as_str() {
        "read" => AccessPermission::Read,
        "read_write" => AccessPermission::ReadWrite,
        "rotate" => AccessPermission::Rotate,
        _ => {
            return Err(ControlCenterError::from(infrastructure::internal_error(
                "Invalid permission level",
            )))
        }
    };

    let user_id = security_ctx.user_id.to_string();
    let grant = secret_sharing
        .create_grant(ServiceCreateGrantRequest {
            secret_path: &path,
            source_workspace: &request.source_workspace,
            target_workspace: &request.target_workspace,
            grantee: &user_id,
            permission,
            reason: None,
            require_approval: request.require_approval,
            granted_by: &user_id,
        })
        .await
        .map_err(|e| {
            error!(error = %e, path = %path, "Failed to create grant");
            ControlCenterError::from(infrastructure::internal_error(&format!(
                "Failed to create grant: {}",
                e
            )))
        })?;

    info!(
        user_id = %security_ctx.user_id,
        grant_id = %grant.id,
        "Secret grant created"
    );

    Ok((
        StatusCode::CREATED,
        Json(GrantResponse {
            grant_id: grant.id,
            secret_path: grant.secret_path,
            source_workspace: grant.source_workspace,
            target_workspace: grant.target_workspace,
            permission: format!("{:?}", grant.permission).to_lowercase(),
            status: format!("{:?}", grant.status).to_lowercase(),
            granted_at: grant.created_at,
            access_count: grant.access_count as usize,
        }),
    ))
}

/// Request to revoke a grant
#[derive(Debug, Serialize, Deserialize)]
pub struct RevokeGrantRequest {
    /// Reason for revocation
    #[serde(default)]
    pub reason: String,
}

/// Handler: Revoke a secret grant
#[onto_api(
    method = "POST",
    path = "/secrets/grant/{grant_id}/revoke",
    description = "Revoke a secret grant",
    auth = "admin",
    actors = "developer",
    tags = "secrets",
    feature = ""
)]
pub async fn revoke_grant(
    State(app_state): State<Arc<AppState>>,
    Extension(security_ctx): Extension<SecurityContext>,
    Path(grant_id): Path<String>,
    Json(request): Json<RevokeGrantRequest>,
) -> Result<impl IntoResponse, ControlCenterError> {
    info!(
        user_id = %security_ctx.user_id,
        grant_id = %grant_id,
        reason = %request.reason,
        "Revoking secret grant"
    );

    let secret_sharing = &app_state.secret_sharing;
    secret_sharing
        .revoke_grant(&grant_id, &request.reason)
        .await
        .map_err(|e| {
            error!(error = %e, grant_id = %grant_id, "Failed to revoke grant");
            ControlCenterError::from(infrastructure::internal_error(&format!(
                "Failed to revoke grant: {}",
                e
            )))
        })?;

    info!(
        user_id = %security_ctx.user_id,
        grant_id = %grant_id,
        "Secret grant revoked"
    );

    Ok(StatusCode::NO_CONTENT)
}

// ============== PHASE 3.4: MONITORING HANDLERS ==============

/// Handler: Get dashboard metrics
#[onto_api(
    method = "GET",
    path = "/secrets/monitoring/dashboard",
    description = "Get secrets monitoring dashboard metrics",
    auth = "admin",
    actors = "developer",
    tags = "secrets",
    feature = ""
)]
pub async fn get_dashboard_metrics(
    State(app_state): State<Arc<AppState>>,
    Extension(_security_ctx): Extension<SecurityContext>,
) -> Result<impl IntoResponse, ControlCenterError> {
    let monitoring_service = &app_state.monitoring_service;
    let metrics = monitoring_service
        .get_dashboard_metrics()
        .await
        .map_err(|e| {
            error!(error = %e, "Failed to get dashboard metrics");
            ControlCenterError::from(infrastructure::internal_error(&format!(
                "Failed to get metrics: {}",
                e
            )))
        })?;

    Ok(Json(metrics))
}

/// Handler: Get alert summary
#[onto_api(
    method = "GET",
    path = "/secrets/monitoring/alerts",
    description = "Get secrets monitoring alert summary",
    auth = "admin",
    actors = "developer",
    tags = "secrets",
    feature = ""
)]
pub async fn get_alert_summary(
    State(app_state): State<Arc<AppState>>,
    Extension(_security_ctx): Extension<SecurityContext>,
) -> Result<impl IntoResponse, ControlCenterError> {
    let monitoring_service = &app_state.monitoring_service;
    let summary = monitoring_service.get_alert_summary().await.map_err(|e| {
        error!(error = %e, "Failed to get alert summary");
        ControlCenterError::from(infrastructure::internal_error(&format!(
            "Failed to get alerts: {}",
            e
        )))
    })?;

    Ok(Json(summary))
}

/// Handler: Get expiring secrets
#[onto_api(
    method = "GET",
    path = "/secrets/monitoring/expiring",
    description = "Get list of expiring secrets",
    auth = "admin",
    actors = "developer",
    tags = "secrets",
    feature = ""
)]
pub async fn get_expiring_secrets(
    State(app_state): State<Arc<AppState>>,
    Extension(_security_ctx): Extension<SecurityContext>,
) -> Result<impl IntoResponse, ControlCenterError> {
    let monitoring_service = &app_state.monitoring_service;
    let secrets = monitoring_service
        .get_expiring_secrets()
        .await
        .map_err(|e| {
            error!(error = %e, "Failed to get expiring secrets");
            ControlCenterError::from(infrastructure::internal_error(&format!(
                "Failed to get expiring secrets: {}",
                e
            )))
        })?;

    Ok(Json(serde_json::json!({"expiring_secrets": secrets})))
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_create_secret_request_serialization() {
        let request = CreateSecretRequest {
            path: "test/secret".to_string(),
            value: "secret_value".to_string(),
            workspace_id: "test_workspace".to_string(),
            infra_id: None,
            domain: "test_domain".to_string(),
            secret_type: SecretType::Application {
                app_name: "test_app".to_string(),
                key_type: "api_token".to_string(),
            },
            tags: vec![],
            ttl_seconds: None,
            auto_rotate: false,
            rotation_interval_days: None,
            context: Some("production".to_string()),
            metadata: None,
        };

        let json = serde_json::to_string(&request).unwrap();
        assert!(json.contains("test/secret"));
        assert!(json.contains("secret_value"));
    }

    #[test]
    fn test_default_limit() {
        assert_eq!(default_limit(), 100);
    }
}
