use serde::{Deserialize, Serialize};

pub const CRATE_PURPOSE: &str = "server-side console report api boundary";
pub const CONSOLE_API_BOUNDARY_ID: &str = "bnd:bucketwarden.browser-ui.console-report-api-slice";

#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct ConsoleApiFeature {
    pub feature_id: String,
    pub title: String,
    pub method: String,
    pub route: String,
    pub protected: bool,
}

#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct ConsoleApiContract {
    pub boundary_id: String,
    pub implementation_status: String,
    pub features: Vec<ConsoleApiFeature>,
    pub route_groups: Vec<String>,
    pub shared_controls: Vec<String>,
    pub error_controls: Vec<String>,
}

pub fn console_api_contract() -> ConsoleApiContract {
    ConsoleApiContract {
        boundary_id: CONSOLE_API_BOUNDARY_ID.to_string(),
        implementation_status: "implemented".to_string(),
        features: console_api_features(),
        route_groups: console_api_route_groups(),
        shared_controls: console_api_shared_controls(),
        error_controls: console_api_error_controls(),
    }
}

pub fn console_api_features() -> Vec<ConsoleApiFeature> {
    [
        (
            "feat:bucketwarden.console.api.auth-login",
            "Console API auth login",
            "POST",
            "/api/v1/login",
            false,
        ),
        (
            "feat:bucketwarden.console.api.auth-current-user",
            "Console API current user",
            "GET",
            "/api/v1/current-user",
            true,
        ),
        (
            "feat:bucketwarden.console.api.auth-logout",
            "Console API auth logout",
            "POST",
            "/api/v1/logout",
            true,
        ),
        (
            "feat:bucketwarden.console.api.session-expiry",
            "Console API session expiry",
            "GET",
            "/api/v1/current-user",
            true,
        ),
        (
            "feat:bucketwarden.console.api.overview-report",
            "Console API overview report",
            "GET",
            "/api/v1/overview",
            true,
        ),
        (
            "feat:bucketwarden.console.api.health-report",
            "Console API health report",
            "GET",
            "/api/v1/reports/health",
            true,
        ),
        (
            "feat:bucketwarden.console.api.configuration-report",
            "Console API configuration report",
            "GET",
            "/api/v1/reports/config",
            true,
        ),
        (
            "feat:bucketwarden.console.api.bucket-list",
            "Console API bucket list",
            "GET",
            "/api/v1/buckets",
            true,
        ),
        (
            "feat:bucketwarden.console.api.bucket-detail",
            "Console API bucket detail",
            "GET",
            "/api/v1/buckets/{bucket}",
            true,
        ),
        (
            "feat:bucketwarden.console.api.object-list",
            "Console API object list",
            "GET",
            "/api/v1/buckets/{bucket}/objects",
            true,
        ),
        (
            "feat:bucketwarden.console.api.object-version-history",
            "Console API object version history",
            "GET",
            "/api/v1/object-versions",
            true,
        ),
        (
            "feat:bucketwarden.console.api.object-governance-summary",
            "Console API object governance summary",
            "GET",
            "/api/v1/object-governance",
            true,
        ),
        (
            "feat:bucketwarden.console.api.object-lock-retention",
            "Console API object lock retention",
            "GET",
            "/api/v1/object-lock-retention",
            true,
        ),
        (
            "feat:bucketwarden.console.api.legal-hold",
            "Console API legal hold",
            "GET",
            "/api/v1/legal-hold",
            true,
        ),
        (
            "feat:bucketwarden.console.api.audit-events",
            "Console API audit events",
            "GET",
            "/api/v1/audit",
            true,
        ),
        (
            "feat:bucketwarden.console.api.audit-filtering",
            "Console API audit filtering",
            "GET",
            "/api/v1/audit",
            true,
        ),
        (
            "feat:bucketwarden.console.api.evidence-list",
            "Console API evidence list",
            "GET",
            "/api/v1/evidence",
            true,
        ),
        (
            "feat:bucketwarden.console.api.evidence-export",
            "Console API evidence export",
            "GET",
            "/api/v1/evidence-export",
            true,
        ),
        (
            "feat:bucketwarden.console.api.preferences-read",
            "Console API preferences read",
            "GET",
            "/api/v1/preferences",
            true,
        ),
        (
            "feat:bucketwarden.console.api.preferences-write",
            "Console API preferences write",
            "PUT",
            "/api/v1/preferences",
            true,
        ),
        (
            "feat:bucketwarden.console.api.pagination-filtering-sorting",
            "Console API pagination filtering sorting",
            "GET",
            "/api/v1/*",
            true,
        ),
        (
            "feat:bucketwarden.console.api.error-envelope",
            "Console API error envelope",
            "*",
            "/api/v1/*",
            false,
        ),
    ]
    .into_iter()
    .map(
        |(feature_id, title, method, route, protected)| ConsoleApiFeature {
            feature_id: feature_id.to_string(),
            title: title.to_string(),
            method: method.to_string(),
            route: route.to_string(),
            protected,
        },
    )
    .collect()
}

pub fn console_api_route_groups() -> Vec<String> {
    [
        "auth",
        "overview and reports",
        "bucket and object explorer",
        "object governance",
        "audit and evidence",
        "preferences",
    ]
    .into_iter()
    .map(str::to_string)
    .collect()
}

pub fn console_api_shared_controls() -> Vec<String> {
    [
        "versioned /api/v1 route ownership",
        "legacy /ui/api compatibility alias",
        "authenticated access-key session guard",
        "operator action authorization",
        "pagination limit validation",
        "filter and sort validation",
        "redacted configuration output",
        "principal-scoped preferences",
    ]
    .into_iter()
    .map(str::to_string)
    .collect()
}

pub fn console_api_error_controls() -> Vec<String> {
    [
        "stable request id",
        "HTTP status",
        "service error code",
        "human message",
        "retryable flag",
        "fail-closed unauthenticated response",
        "invalid input envelope",
    ]
    .into_iter()
    .map(str::to_string)
    .collect()
}

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

    #[test]
    fn console_api_contract_tracks_all_slice_features() {
        let contract = console_api_contract();
        let feature_ids = contract
            .features
            .iter()
            .map(|feature| feature.feature_id.as_str())
            .collect::<Vec<_>>();

        assert_eq!(contract.boundary_id, CONSOLE_API_BOUNDARY_ID);
        assert_eq!(contract.implementation_status, "implemented");
        assert_eq!(contract.features.len(), 22);
        assert!(feature_ids.contains(&"feat:bucketwarden.console.api.auth-login"));
        assert!(feature_ids.contains(&"feat:bucketwarden.console.api.object-governance-summary"));
        assert!(feature_ids.contains(&"feat:bucketwarden.console.api.pagination-filtering-sorting"));
        assert!(feature_ids.contains(&"feat:bucketwarden.console.api.error-envelope"));
    }

    #[test]
    fn console_api_contract_requires_auth_error_and_query_controls() {
        let contract = console_api_contract();

        assert!(contract
            .features
            .iter()
            .any(|feature| feature.route == "/api/v1/login" && !feature.protected));
        assert!(contract
            .features
            .iter()
            .any(|feature| feature.route == "/api/v1/preferences" && feature.method == "PUT"));
        assert!(contract
            .shared_controls
            .contains(&"filter and sort validation".to_string()));
        assert!(contract
            .error_controls
            .contains(&"fail-closed unauthenticated response".to_string()));
    }
}
