use super::*;

#[path = "tests/policy_auth_parser.rs"]
mod policy_auth_parser;

fn args(values: &[&str]) -> Vec<String> {
    values.iter().map(|value| value.to_string()).collect()
}

#[test]
fn parses_health_alias_and_config_path() {
    assert_eq!(
        parse_operator_command(&args(&["bucketwarden", "--health"])).unwrap(),
        OperatorCommand::Health { config_path: None }
    );
    assert_eq!(
        parse_operator_command(&args(&[
            "bucketwarden",
            "health",
            "--config",
            "config.json"
        ]))
        .unwrap(),
        OperatorCommand::Health {
            config_path: Some("config.json".to_string())
        }
    );
}

#[test]
fn parses_global_config_before_subcommand_dispatch() {
    assert_eq!(
        parse_operator_command(&args(&[
            "bucketwarden",
            "--config",
            "config.json",
            "health"
        ]))
        .unwrap(),
        OperatorCommand::Health {
            config_path: Some("config.json".to_string())
        }
    );
    assert_eq!(
        parse_operator_command(&args(&[
            "bucketwarden",
            "--config",
            "global.json",
            "health",
            "--config",
            "local.json"
        ]))
        .unwrap(),
        OperatorCommand::Health {
            config_path: Some("local.json".to_string())
        }
    );
}

#[test]
fn parses_global_output_flags_and_version() {
    assert_eq!(
        parse_operator_command(&args(&["bucketwarden", "--version"])).unwrap(),
        OperatorCommand::Version
    );
    assert_eq!(
        parse_operator_command(&args(&["bucketwarden", "--quiet"])).unwrap(),
        OperatorCommand::Global {
            options: GlobalOptions {
                quiet: true,
                verbose: 0,
            },
            command: Box::new(OperatorCommand::DefaultStatus),
        }
    );
    assert_eq!(
        parse_operator_command(&args(&["bucketwarden", "--verbose", "diagnostics"])).unwrap(),
        OperatorCommand::Global {
            options: GlobalOptions {
                quiet: false,
                verbose: 1,
            },
            command: Box::new(OperatorCommand::Diagnostics { config_path: None }),
        }
    );
}

#[test]
fn parses_config_validate() {
    assert_eq!(
        parse_operator_command(&args(&[
            "bucketwarden",
            "config",
            "validate",
            "--config",
            "config.json"
        ]))
        .unwrap(),
        OperatorCommand::ConfigValidate {
            config_path: "config.json".to_string()
        }
    );
}

#[test]
fn parses_readiness_diagnostics_audit_and_replication() {
    assert_eq!(
        parse_operator_command(&args(&["bucketwarden", "readiness"])).unwrap(),
        OperatorCommand::Readiness { config_path: None }
    );
    assert_eq!(
        parse_operator_command(&args(&["bucketwarden", "diagnostics"])).unwrap(),
        OperatorCommand::Diagnostics { config_path: None }
    );
    assert_eq!(
        parse_operator_command(&args(&["bucketwarden", "metrics"])).unwrap(),
        OperatorCommand::Metrics { config_path: None }
    );
    assert_eq!(
        parse_operator_command(&args(&["bucketwarden", "ops", "report", "health"])).unwrap(),
        OperatorCommand::OpsReportHealth {
            config_path: None,
            bucket: None,
        }
    );
    assert_eq!(
        parse_operator_command(&args(&["bucketwarden", "audit", "export"])).unwrap(),
        OperatorCommand::AuditExport { config_path: None }
    );
    assert_eq!(
        parse_operator_command(&args(&["bucketwarden", "replication", "status"])).unwrap(),
        OperatorCommand::ReplicationStatus { config_path: None }
    );
}

#[test]
fn parses_ops_report_commands_with_bucket_and_incident_flags() {
    assert_eq!(
        parse_operator_command(&args(&[
            "bucketwarden",
            "ops",
            "report",
            "config",
            "--bucket",
            "archive-001"
        ]))
        .unwrap(),
        OperatorCommand::OpsReportConfig {
            config_path: None,
            bucket: Some("archive-001".to_string())
        }
    );
    assert_eq!(
        parse_operator_command(&args(&[
            "bucketwarden",
            "ops",
            "report",
            "admin-surfaces",
            "--config",
            "config.json"
        ]))
        .unwrap(),
        OperatorCommand::OpsReportAdminSurfaces {
            config_path: Some("config.json".to_string()),
            bucket: None
        }
    );
    assert_eq!(
        parse_operator_command(&args(&[
            "bucketwarden",
            "ops",
            "report",
            "incident",
            "--type",
            "quota_pressure",
            "--bucket",
            "archive-001"
        ]))
        .unwrap(),
        OperatorCommand::OpsReportIncident {
            config_path: None,
            bucket: Some("archive-001".to_string()),
            incident_type: "quota_pressure".to_string()
        }
    );
    assert_eq!(
        parse_operator_command(&args(&["bucketwarden", "ops", "report", "evidence-export"]))
            .unwrap(),
        OperatorCommand::OpsReportEvidenceExport {
            config_path: None,
            bucket: None
        }
    );
}

#[test]
fn parses_s3_serve_defaults_and_overrides() {
    assert_eq!(
        parse_operator_command(&args(&["bucketwarden", "s3", "serve"])).unwrap(),
        OperatorCommand::S3Serve {
            bind: "127.0.0.1:9000".to_string(),
            console_bind: "127.0.0.1:9001".to_string(),
            config_path: None,
            principal: "boto3".to_string(),
            access_key_id: "AKIDEXAMPLE".to_string(),
            secret_access_key: "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY".to_string(),
            storage: S3ServeStorage::Filesystem {
                data_dir: ".bucketwarden/data".to_string(),
            },
        }
    );
    assert_eq!(
        parse_operator_command(&args(&[
            "bucketwarden",
            "s3",
            "serve",
            "--bind",
            "127.0.0.1:39009",
            "--console-bind",
            "127.0.0.1:39010",
            "--config",
            "config.json",
            "--principal",
            "alice",
            "--access-key",
            "AKIAALICE",
            "--secret-key",
            "alice-secret",
        ]))
        .unwrap(),
        OperatorCommand::S3Serve {
            bind: "127.0.0.1:39009".to_string(),
            console_bind: "127.0.0.1:39010".to_string(),
            config_path: Some("config.json".to_string()),
            principal: "alice".to_string(),
            access_key_id: "AKIAALICE".to_string(),
            secret_access_key: "alice-secret".to_string(),
            storage: S3ServeStorage::Filesystem {
                data_dir: ".bucketwarden/data".to_string(),
            },
        }
    );
}

#[test]
fn parses_s3_serve_storage_modes() {
    assert_eq!(
        parse_operator_command(&args(&[
            "bucketwarden",
            "s3",
            "serve",
            "--storage",
            "filesystem",
            "--data-dir",
            "state/s3",
        ]))
        .unwrap(),
        OperatorCommand::S3Serve {
            bind: "127.0.0.1:9000".to_string(),
            console_bind: "127.0.0.1:9001".to_string(),
            config_path: None,
            principal: "boto3".to_string(),
            access_key_id: "AKIDEXAMPLE".to_string(),
            secret_access_key: "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY".to_string(),
            storage: S3ServeStorage::Filesystem {
                data_dir: "state/s3".to_string(),
            },
        }
    );
    assert_eq!(
        parse_operator_command(&args(&["bucketwarden", "s3", "serve", "--in-memory"])).unwrap(),
        OperatorCommand::S3Serve {
            bind: "127.0.0.1:9000".to_string(),
            console_bind: "127.0.0.1:9001".to_string(),
            config_path: None,
            principal: "boto3".to_string(),
            access_key_id: "AKIDEXAMPLE".to_string(),
            secret_access_key: "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY".to_string(),
            storage: S3ServeStorage::InMemory,
        }
    );
}

#[test]
fn rejects_invalid_s3_serve_storage_flags() {
    let error = parse_operator_command(&args(&[
        "bucketwarden",
        "s3",
        "serve",
        "--storage",
        "sqlite",
    ]))
    .unwrap_err();
    assert!(error.contains("invalid s3 serve storage mode"));

    let error = parse_operator_command(&args(&[
        "bucketwarden",
        "s3",
        "serve",
        "--in-memory",
        "--data-dir",
        "state/s3",
    ]))
    .unwrap_err();
    assert!(error.contains("cannot use `--data-dir` with in-memory"));
}

#[test]
fn parses_auth_and_policy_operator_commands() {
    assert_eq!(
        parse_operator_command(&args(&["bucketwarden", "policy", "analyze"])).unwrap(),
        OperatorCommand::PolicyAnalyze
    );
    assert_eq!(
        parse_operator_command(&args(&[
            "bucketwarden",
            "auth",
            "report",
            "identity-providers"
        ]))
        .unwrap(),
        OperatorCommand::AuthReportIdentityProviders
    );
    assert_eq!(
        parse_operator_command(&args(&["bucketwarden", "auth", "report", "credentials"])).unwrap(),
        OperatorCommand::AuthReportCredentials
    );
    assert_eq!(
        parse_operator_command(&args(&[
            "bucketwarden",
            "auth",
            "report",
            "temporary-credentials"
        ]))
        .unwrap(),
        OperatorCommand::AuthReportTemporaryCredentials
    );
    assert_eq!(
        parse_operator_command(&args(&[
            "bucketwarden",
            "auth",
            "role",
            "list",
            "--principal",
            "alice"
        ]))
        .unwrap(),
        OperatorCommand::AuthRoleList {
            principal: "alice".to_string()
        }
    );
}

#[test]
fn rejects_unknown_commands() {
    let error = parse_operator_command(&args(&["bucketwarden", "bogus"])).unwrap_err();
    assert!(error.contains("unknown command `bogus`"));
}

#[test]
fn readiness_diagnostics_and_metrics_use_ops_reports() {
    let readiness: serde_json::Value =
        serde_json::from_str(&readiness_json(None).expect("readiness")).expect("json");
    assert_eq!(readiness["status"], "degraded");
    assert_eq!(readiness["checks"]["runtime"], "degraded");
    assert!(readiness["issues"]
        .as_array()
        .expect("issues")
        .iter()
        .any(|issue| issue.as_str() == Some("runtime has no buckets")));

    let diagnostics: serde_json::Value =
        serde_json::from_str(&diagnostics_json(None).expect("diagnostics")).expect("json");
    assert_eq!(diagnostics["status"], "degraded");
    assert!(diagnostics["config_report"]["active_storage_backend"].is_string());
    assert!(diagnostics["evidence_export"]["audit_event_count"].is_number());

    let metrics = metrics_text(None).expect("metrics");
    assert!(metrics.contains("bucketwarden_runtime_ready 0"));
    assert!(metrics.contains("bucketwarden_operator_issue_count 1"));
}

#[test]
fn ops_report_helpers_surface_runtime_native_reports() {
    let health: serde_json::Value =
        serde_json::from_str(&ops_report_health_json(None, None).expect("health")).expect("json");
    assert_eq!(health["scope"], "runtime");

    let admin: serde_json::Value = serde_json::from_str(
        &ops_report_admin_surfaces_json(None, None).expect("admin surface report"),
    )
    .expect("json");
    assert!(admin["storage_backend_admin_surfaces"].is_array());

    let incident: serde_json::Value = serde_json::from_str(
        &ops_report_incident_json(None, None, "credential_leak").expect("incident report"),
    )
    .expect("json");
    assert_eq!(incident["incident_type"], "credential_leak");

    let evidence: serde_json::Value = serde_json::from_str(
        &ops_report_evidence_export_json(None, None).expect("evidence export"),
    )
    .expect("json");
    assert!(evidence["snapshot_json"].is_string());
}
