use serde::{Deserialize, Serialize};

pub const CRATE_PURPOSE: &str = "browser ui shell route and state contracts";

#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct BrowserUiRoute {
    pub route: String,
    pub label: String,
    pub feature_id: String,
    pub requires_session: bool,
    pub api_endpoint: Option<String>,
}

#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct BrowserUiSecurityPolicy {
    pub session_cookie_name: String,
    pub csrf_header: String,
    pub cors_mode: String,
    pub content_security_policy: String,
    pub secret_handling: String,
}

#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct BrowserUiShellContract {
    pub boundary_id: String,
    pub implementation_status: String,
    pub routes: Vec<BrowserUiRoute>,
    pub sidebar_order: Vec<String>,
    pub topbar_context_order: Vec<String>,
    pub page_header_regions: Vec<String>,
    pub action_filter_controls: Vec<String>,
    pub secondary_inspector_regions: Vec<String>,
    pub mobile_layout_rules: Vec<String>,
    pub api_endpoints: Vec<String>,
    pub api_client_contracts: Vec<String>,
    pub state_contracts: Vec<String>,
    pub accessibility_checks: Vec<String>,
    pub responsive_breakpoints: Vec<String>,
    pub security: BrowserUiSecurityPolicy,
}

pub fn browser_ui_shell_contract() -> BrowserUiShellContract {
    BrowserUiShellContract {
        boundary_id: "bnd:bucketwarden.browser-ui.foundation-slice".to_string(),
        implementation_status: "implemented".to_string(),
        routes: browser_ui_routes(),
        sidebar_order: browser_ui_sidebar_order(),
        topbar_context_order: browser_ui_topbar_context_order(),
        page_header_regions: browser_ui_page_header_regions(),
        action_filter_controls: browser_ui_action_filter_controls(),
        secondary_inspector_regions: browser_ui_secondary_inspector_regions(),
        mobile_layout_rules: browser_ui_mobile_layout_rules(),
        api_endpoints: browser_ui_api_endpoints(),
        api_client_contracts: browser_ui_api_client_contracts(),
        state_contracts: browser_ui_state_contracts(),
        accessibility_checks: browser_ui_accessibility_checks(),
        responsive_breakpoints: browser_ui_responsive_breakpoints(),
        security: browser_ui_security_policy(),
    }
}

pub fn browser_ui_routes() -> Vec<BrowserUiRoute> {
    [
        (
            "/ui/login",
            "Login",
            "feat:bucketwarden.ui.browser.auth.login",
            false,
            Some("/ui/api/login"),
        ),
        (
            "/ui",
            "Overview",
            "feat:bucketwarden.ui.browser.shell.persistent-layout",
            true,
            Some("/ui/api/overview"),
        ),
        (
            "/ui/reports",
            "Reports",
            "feat:bucketwarden.ui.browser.reports.health",
            true,
            Some("/ui/api/reports"),
        ),
        (
            "/ui/buckets",
            "Buckets",
            "feat:bucketwarden.ui.browser.buckets.list",
            true,
            Some("/ui/api/buckets"),
        ),
        (
            "/ui/governance",
            "Governance",
            "feat:bucketwarden.ui.browser.governance.object-retention",
            true,
            Some("/ui/api/object-governance"),
        ),
        (
            "/ui/audit",
            "Audit",
            "feat:bucketwarden.ui.browser.audit.log",
            true,
            Some("/ui/api/audit"),
        ),
        (
            "/ui/evidence",
            "Evidence",
            "feat:bucketwarden.ui.browser.evidence.list",
            true,
            Some("/ui/api/evidence"),
        ),
        (
            "/ui/settings",
            "Settings",
            "feat:bucketwarden.ui.browser.shell.topbar-context",
            true,
            Some("/ui/api/preferences"),
        ),
        (
            "/ui/v1",
            "Overview v1",
            "feat:bucketwarden.ui.browser.shell.route-aware-pages",
            true,
            Some("/api/v1/overview"),
        ),
        (
            "/ui/v1/login",
            "Login v1",
            "feat:bucketwarden.ui.browser.auth.login",
            false,
            Some("/api/v1/login"),
        ),
        (
            "/ui/v1/reports",
            "Reports v1",
            "feat:bucketwarden.ui.browser.reports.health",
            true,
            Some("/api/v1/reports"),
        ),
        (
            "/ui/v1/buckets",
            "Buckets v1",
            "feat:bucketwarden.ui.browser.buckets.list",
            true,
            Some("/api/v1/buckets"),
        ),
        (
            "/ui/v1/governance",
            "Governance v1",
            "feat:bucketwarden.ui.browser.governance.object-retention",
            true,
            Some("/api/v1/object-governance"),
        ),
        (
            "/ui/v1/audit",
            "Audit v1",
            "feat:bucketwarden.ui.browser.audit.log",
            true,
            Some("/api/v1/audit"),
        ),
        (
            "/ui/v1/evidence",
            "Evidence v1",
            "feat:bucketwarden.ui.browser.evidence.list",
            true,
            Some("/api/v1/evidence"),
        ),
        (
            "/ui/v1/settings",
            "Settings v1",
            "feat:bucketwarden.ui.browser.shell.topbar-context",
            true,
            Some("/api/v1/preferences"),
        ),
    ]
    .into_iter()
    .map(
        |(route, label, feature_id, requires_session, api_endpoint)| BrowserUiRoute {
            route: route.to_string(),
            label: label.to_string(),
            feature_id: feature_id.to_string(),
            requires_session,
            api_endpoint: api_endpoint.map(str::to_string),
        },
    )
    .collect()
}

pub fn browser_ui_sidebar_order() -> Vec<String> {
    [
        "Login",
        "Overview",
        "Reports",
        "Buckets",
        "Governance",
        "Audit",
        "Evidence",
        "Settings",
    ]
    .into_iter()
    .map(str::to_string)
    .collect()
}

pub fn browser_ui_topbar_context_order() -> Vec<String> {
    [
        "route title",
        "route summary",
        "selected tenant",
        "selected bucket",
        "selected object",
        "principal session",
        "refresh controls",
    ]
    .into_iter()
    .map(str::to_string)
    .collect()
}

pub fn browser_ui_page_header_regions() -> Vec<String> {
    [
        "primary route heading",
        "route purpose summary",
        "selected resource context",
        "view-level action filter bar",
    ]
    .into_iter()
    .map(str::to_string)
    .collect()
}

pub fn browser_ui_action_filter_controls() -> Vec<String> {
    [
        "global search query",
        "bucket prefix filter",
        "status/outcome filter",
        "sort order",
        "manual refresh button",
        "auto refresh interval selector",
    ]
    .into_iter()
    .map(str::to_string)
    .collect()
}

pub fn browser_ui_secondary_inspector_regions() -> Vec<String> {
    [
        "selected bucket summary",
        "selected object summary",
        "selected version summary",
        "active governance constraints",
        "current error or denied reason",
    ]
    .into_iter()
    .map(str::to_string)
    .collect()
}

pub fn browser_ui_mobile_layout_rules() -> Vec<String> {
    [
        "sidebar collapses above content",
        "topbar context wraps without overlap",
        "action/filter controls stack in document order",
        "secondary inspector moves below primary content",
        "tables preserve readable cells with overflow wrapping",
    ]
    .into_iter()
    .map(str::to_string)
    .collect()
}

pub fn browser_ui_api_endpoints() -> Vec<String> {
    [
        "GET /ui",
        "GET /ui/v1",
        "GET /ui/v1/login",
        "GET /ui/v1/reports",
        "GET /ui/v1/buckets",
        "GET /ui/v1/governance",
        "GET /ui/v1/audit",
        "GET /ui/v1/evidence",
        "GET /ui/v1/settings",
        "GET /ui/assets/app.css",
        "GET /ui/assets/app.js",
        "GET /ui/assets/bucketwarden-monogram.png",
        "GET /ui/assets/favicon.png",
        "GET /ui/v1/assets/app.css",
        "GET /ui/v1/assets/app.js",
        "GET /ui/v1/assets/bucketwarden-monogram.png",
        "GET /ui/v1/assets/favicon.png",
        "POST /api/v1/login",
        "POST /api/v1/logout",
        "GET /api/v1/current-user",
        "GET /api/v1/overview",
        "GET /api/v1/reports",
        "GET /api/v1/reports/health",
        "GET /api/v1/reports/config",
        "GET /api/v1/evidence",
        "GET /api/v1/evidence-export",
        "GET /api/v1/audit",
        "GET /api/v1/buckets",
        "GET /api/v1/buckets/{bucket}",
        "GET /api/v1/buckets/{bucket}/objects",
        "GET /api/v1/object-versions",
        "GET /api/v1/object-governance",
        "GET /api/v1/object-lock-retention",
        "GET /api/v1/legal-hold",
        "GET /api/v1/preferences",
        "PUT /api/v1/preferences",
        "POST /ui/api/login",
        "POST /ui/api/logout",
        "GET /ui/api/current-user",
        "GET /ui/api/overview",
        "GET /ui/api/reports",
        "GET /ui/api/reports/health",
        "GET /ui/api/reports/config",
        "GET /ui/api/reports/admin-surfaces",
        "GET /ui/api/reports/incident",
        "GET /ui/api/evidence",
        "GET /ui/api/evidence-export",
        "GET /ui/api/metrics",
        "GET /ui/api/audit",
        "GET /ui/api/buckets",
        "GET /ui/api/buckets/{bucket}",
        "GET /ui/api/buckets/{bucket}/objects",
        "GET /ui/api/object-versions",
        "GET /ui/api/object-governance",
        "GET /ui/api/object-lock-retention",
        "GET /ui/api/legal-hold",
        "GET /ui/api/preferences",
        "PUT /ui/api/preferences",
    ]
    .into_iter()
    .map(str::to_string)
    .collect()
}

pub fn browser_ui_api_client_contracts() -> Vec<String> {
    [
        "session credential header x-bucketwarden-ui-access-key",
        "normalized JSON error envelopes",
        "login/logout/current-user lifecycle",
        "versioned /api/v1 route ownership for /ui/v1",
        "legacy same-origin /ui/api route ownership",
    ]
    .into_iter()
    .map(str::to_string)
    .collect()
}

pub fn browser_ui_state_contracts() -> Vec<String> {
    [
        "route loading state",
        "empty collection state",
        "unauthenticated route guard",
        "denied and failed API states",
        "sessionStorage without shared-secret persistence",
    ]
    .into_iter()
    .map(str::to_string)
    .collect()
}

pub fn browser_ui_accessibility_checks() -> Vec<String> {
    [
        "keyboard navigation landmarks",
        "landmark roles for navigation, main, and status regions",
        "labels for credential fields and route controls",
        "visible focus state for links, buttons, and inputs",
        "aria-live status text for loading, empty, and error states",
        "keyboard-operable navigation without pointer-only actions",
    ]
    .into_iter()
    .map(str::to_string)
    .collect()
}

pub fn browser_ui_responsive_breakpoints() -> Vec<String> {
    ["compact: 360px", "tablet: 768px", "desktop: 1120px"]
        .into_iter()
        .map(str::to_string)
        .collect()
}

pub fn browser_ui_security_policy() -> BrowserUiSecurityPolicy {
    BrowserUiSecurityPolicy {
        session_cookie_name: "bwui_session".to_string(),
        csrf_header: "x-bucketwarden-csrf-token".to_string(),
        cors_mode: "same-origin operator console".to_string(),
        content_security_policy:
            "default-src 'self'; script-src 'self'; style-src 'self'; connect-src 'self'"
                .to_string(),
        secret_handling: "shared secrets are submitted only to login API and never rendered"
            .to_string(),
    }
}

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

    #[test]
    fn shell_contract_exposes_first_boundary_runtime_surfaces() {
        let contract = browser_ui_shell_contract();

        assert_eq!(contract.implementation_status, "implemented");
        assert!(contract.routes.iter().any(|route| {
            route.feature_id == "feat:bucketwarden.ui.browser.shell.persistent-layout"
        }));
        assert!(contract.routes.iter().any(|route| {
            route.feature_id == "feat:bucketwarden.ui.browser.shell.route-aware-pages"
        }));
        assert_eq!(
            contract.sidebar_order,
            [
                "Login",
                "Overview",
                "Reports",
                "Buckets",
                "Governance",
                "Audit",
                "Evidence",
                "Settings"
            ]
        );
        assert!(contract
            .topbar_context_order
            .iter()
            .any(|region| region == "refresh controls"));
        assert!(contract
            .action_filter_controls
            .iter()
            .any(|control| control == "global search query"));
        assert!(contract
            .secondary_inspector_regions
            .iter()
            .any(|region| region == "selected object summary"));
        assert!(contract
            .mobile_layout_rules
            .iter()
            .any(|rule| rule == "sidebar collapses above content"));
        assert!(contract
            .state_contracts
            .iter()
            .any(|state| state.contains("empty collection state")));
        assert!(contract
            .api_client_contracts
            .iter()
            .any(|contract| contract.contains("normalized JSON error")));
        assert!(contract
            .responsive_breakpoints
            .iter()
            .any(|breakpoint| breakpoint.contains("tablet")));
    }

    #[test]
    fn routes_keep_ui_and_versioned_ui_ownership_separate() {
        let routes = browser_ui_routes();

        assert!(routes
            .iter()
            .any(|route| route.route == "/ui" && route.requires_session));
        assert!(routes
            .iter()
            .any(|route| route.route == "/ui/v1" && route.requires_session));
        assert!(routes
            .iter()
            .any(|route| route.route == "/ui/login" && !route.requires_session));
    }
}
