use serde::{Deserialize, Serialize};
use serde_json::{Value, json};

use crate::BillingProvider;
use crate::grants::{BillingGrantSourceKind, billing_grant_catalog};
use crate::providers::BillingProviderResourceKind;

const ATHENA_ERROR_DOCS_BASE_URL: &str = "https://docs.athena-cluster.com";

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct BillingGrantDescriptorView {
    pub key: &'static str,
    pub resource: &'static str,
    pub action: &'static str,
    pub description: &'static str,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct BillingGrantCountsContract {
    pub grants: usize,
    pub source_kinds: usize,
    pub reconcile_resource_kinds: usize,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct BillingSeedSqlPathContract {
    pub mollie: &'static str,
    pub stripe: &'static str,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct BillingConnectionsContract {
    pub list_endpoint: &'static str,
    pub create_endpoint: &'static str,
    pub get_endpoint: &'static str,
    pub update_endpoint: &'static str,
    pub delete_endpoint: &'static str,
    pub reconcile_endpoint: &'static str,
    pub webhook_events_endpoint: &'static str,
    pub seed_sql: BillingSeedSqlPathContract,
    pub seed_sql_examples: BillingSeedSqlPathContract,
    pub request_examples: Value,
    pub table_sql: &'static str,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct BillingWebhookSinksContract {
    pub helper_endpoint: &'static str,
    pub provision_endpoint: &'static str,
    pub seed_sql: &'static str,
    pub table_sql: &'static str,
    pub target_table_sql_example: &'static str,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct BillingAthenaAuthRuntimeEnvContract {
    pub base_url: &'static str,
    pub path: &'static str,
    pub api_key: &'static str,
    pub header_name: &'static str,
    pub timeout_ms: &'static str,
    pub fail_mode: &'static str,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct BillingAthenaAuthContract {
    pub rights_catalog_endpoint: &'static str,
    pub grant_catalog_endpoint: &'static str,
    pub sync_source_endpoint: &'static str,
    pub sync_source_action: &'static str,
    pub preferred_sync_source_endpoint: &'static str,
    pub preferred_sync_source_action: &'static str,
    pub sync_rights_source_endpoint: &'static str,
    pub sync_rights_source_action: &'static str,
    pub sync_billing_endpoint: &'static str,
    pub sync_billing_action: &'static str,
    pub preferred_sync_billing_endpoint: &'static str,
    pub preferred_sync_billing_action: &'static str,
    pub sync_rights_billing_endpoint: &'static str,
    pub sync_rights_billing_action: &'static str,
    pub runtime_env: BillingAthenaAuthRuntimeEnvContract,
    pub grant_named_runtime_env_aliases: BillingAthenaAuthRuntimeEnvContract,
    pub legacy_runtime_env_aliases: BillingAthenaAuthRuntimeEnvContract,
    pub replace_source_endpoint: &'static str,
    pub replace_source_action: &'static str,
    pub request_contract: Value,
    pub request_shape: Value,
    pub reconcile_request_shape: Value,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct BillingAthenaAuthBootstrapRuntimeEnvContract {
    pub base_url: &'static str,
    pub path: &'static str,
    pub api_key: &'static str,
    pub header_name: &'static str,
    pub timeout_ms: &'static str,
    pub fail_mode: &'static str,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct BillingAthenaAuthBootstrapContract {
    pub rights_catalog_endpoint: &'static str,
    pub grant_catalog_endpoint: &'static str,
    pub sync_source_endpoint: &'static str,
    pub sync_source_action: &'static str,
    pub preferred_sync_source_endpoint: &'static str,
    pub preferred_sync_source_action: &'static str,
    pub sync_rights_source_endpoint: &'static str,
    pub sync_rights_source_action: &'static str,
    pub sync_billing_endpoint: &'static str,
    pub sync_billing_action: &'static str,
    pub preferred_sync_billing_endpoint: &'static str,
    pub preferred_sync_billing_action: &'static str,
    pub sync_rights_billing_endpoint: &'static str,
    pub sync_rights_billing_action: &'static str,
    pub runtime_env: BillingAthenaAuthBootstrapRuntimeEnvContract,
    pub grant_named_runtime_env_aliases: BillingAthenaAuthBootstrapRuntimeEnvContract,
    pub legacy_runtime_env_aliases: BillingAthenaAuthBootstrapRuntimeEnvContract,
    pub replace_source_endpoint: &'static str,
    pub replace_source_action: &'static str,
    pub request_contract: Value,
    pub request_shape: Value,
    pub reconcile_request_shape: Value,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct BillingGrantsContract {
    pub grants: Vec<BillingGrantDescriptorView>,
    pub counts: BillingGrantCountsContract,
    pub route_key: String,
    pub source_kinds: Vec<&'static str>,
    pub document_kinds: Vec<&'static str>,
    pub reconcile_resource_kinds: Vec<&'static str>,
    pub provider_catalog_endpoint: &'static str,
    pub connections: BillingConnectionsContract,
    pub webhook_sinks: BillingWebhookSinksContract,
    pub athena_auth: BillingAthenaAuthContract,
    pub bootstrap: BillingIntegrationBootstrapContract,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct BillingProvidersIntegrationContract {
    pub billing_grants_endpoint: &'static str,
    pub webhook_sink_helper_endpoint: &'static str,
    pub webhook_sink_provision_endpoint: &'static str,
    pub webhook_route_trigger: String,
    pub connection_create_endpoint: &'static str,
    pub connection_seed_sql: BillingSeedSqlPathContract,
    pub connection_seed_sql_examples: BillingSeedSqlPathContract,
    pub connection_request_examples: Value,
    pub seed_sql: &'static str,
    pub table_sql: &'static str,
    pub bootstrap: BillingIntegrationBootstrapContract,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct BillingProviderErrorContract {
    pub code: String,
    pub error_number: u32,
    pub status: u16,
    pub description: String,
    pub docs_url: String,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct BillingProviderVerificationContract {
    pub verification_modes: Vec<String>,
    pub signature_header_name: Option<String>,
    pub signing_secret_config_fields: Vec<String>,
    pub notes: Vec<String>,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct BillingProviderProjectionContract {
    pub canonical_document_kinds: Vec<String>,
    pub refetch_resource_kinds: Vec<String>,
    pub notes: Vec<String>,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct BillingProviderRuntimeContract {
    pub webhook_route_template: String,
    pub webhook_route_trigger: String,
    pub connection_create_endpoint: String,
    pub connection_reconcile_endpoint: String,
    pub verification: BillingProviderVerificationContract,
    pub projection: BillingProviderProjectionContract,
    pub athena_errors: Vec<BillingProviderErrorContract>,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct BillingSinkIntegrationContract {
    pub provider_catalog_endpoint: &'static str,
    pub billing_grants_endpoint: &'static str,
    pub webhook_route_trigger: String,
    pub webhook_route_template: &'static str,
    pub athena_auth: BillingAthenaAuthContract,
    pub bootstrap: BillingIntegrationBootstrapContract,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct BillingIntegrationBootstrapContract {
    pub provider_catalog_endpoint: &'static str,
    pub billing_grants_endpoint: &'static str,
    pub rights_catalog_endpoint: &'static str,
    pub error_catalog_endpoint: &'static str,
    pub docs_base_url: &'static str,
    pub webhook_route_template: &'static str,
    pub webhook_route_trigger: String,
    pub connection_create_endpoint: &'static str,
    pub connection_reconcile_endpoint: &'static str,
    pub connection_seed_sql: BillingSeedSqlPathContract,
    pub connection_seed_sql_examples: BillingSeedSqlPathContract,
    pub connection_request_examples: Value,
    pub canonical_table_sql: &'static str,
    pub canonical_target_table_sql_example: &'static str,
    pub webhook_sink_helper_endpoint: &'static str,
    pub webhook_sink_provision_endpoint: &'static str,
    pub webhook_sink_seed_sql: &'static str,
    pub athena_auth: BillingAthenaAuthBootstrapContract,
}

fn docs_url_for_error_number(error_number: u32) -> String {
    format!("{ATHENA_ERROR_DOCS_BASE_URL}/{error_number:04}")
}

fn billing_provider_error_contract(
    code: &'static str,
    error_number: u32,
    status: u16,
    description: &'static str,
) -> BillingProviderErrorContract {
    BillingProviderErrorContract {
        code: code.to_string(),
        error_number,
        status,
        description: description.to_string(),
        docs_url: docs_url_for_error_number(error_number),
    }
}

pub fn billing_grant_descriptor_views() -> Vec<BillingGrantDescriptorView> {
    billing_grant_catalog()
        .iter()
        .map(|grant| BillingGrantDescriptorView {
            key: grant.key,
            resource: grant.resource,
            action: grant.action,
            description: grant.description,
        })
        .collect()
}

pub fn billing_source_kinds() -> Vec<&'static str> {
    vec![
        BillingGrantSourceKind::Payment.as_str(),
        BillingGrantSourceKind::Subscription.as_str(),
        BillingGrantSourceKind::Invoice.as_str(),
    ]
}

pub fn billing_document_kinds() -> Vec<&'static str> {
    billing_source_kinds()
}

pub fn billing_reconcile_resource_kinds() -> Vec<&'static str> {
    vec![
        BillingProviderResourceKind::Payment.as_str(),
        BillingProviderResourceKind::PaymentLink.as_str(),
        BillingProviderResourceKind::Subscription.as_str(),
        BillingProviderResourceKind::Invoice.as_str(),
    ]
}

pub fn billing_connection_seed_sql_paths() -> BillingSeedSqlPathContract {
    BillingSeedSqlPathContract {
        mollie: "sql/billing_seed_mollie_example.sql",
        stripe: "sql/billing_seed_stripe_example.sql",
    }
}

pub fn billing_connection_seed_sql_examples() -> BillingSeedSqlPathContract {
    billing_connection_seed_sql_paths()
}

pub fn billing_connection_request_examples() -> Value {
    json!({
        "mollie": {
            "ownerKind": "org",
            "ownerId": "org_123",
            "provider": "mollie",
            "mode": "test",
            "status": "active",
            "credentialKind": "advanced_access_token",
            "providerAccountId": "org_abc",
            "providerProfileId": "pfl_123",
            "scopes": [
                "payments.read",
                "payments.write",
                "customers.read",
                "customers.write",
                "subscriptions.read",
                "subscriptions.write",
                "profiles.write"
            ],
            "config": {
                "apiKey": "replace-me-mollie-access-token",
                "signingSecrets": ["replace-me-mollie-webhook-secret"]
            },
            "metadata": {
                "origin": "admin.bootstrap",
                "notes": "Replace placeholder values before persisting a real Mollie connection.",
                "webhookIngress": {
                    "athenaBaseUrl": "https://mirror2.athena-cluster.com",
                    "allowUnsignedHookPing": true
                }
            }
        },
        "stripe": {
            "ownerKind": "org",
            "ownerId": "org_123",
            "provider": "stripe",
            "mode": "test",
            "status": "active",
            "credentialKind": "secret_key",
            "providerAccountId": "acct_123",
            "providerProfileId": "acct_123",
            "scopes": [
                "read_only",
                "customers.read",
                "payment_intents.read",
                "checkout.sessions.read",
                "invoices.read",
                "subscriptions.read"
            ],
            "config": {
                "apiKey": "replace-me-stripe-secret-key",
                "webhookSigningSecrets": ["whsec_replace_me"]
            },
            "metadata": {
                "origin": "admin.bootstrap",
                "notes": "Replace placeholder values before persisting a real Stripe connection."
            }
        }
    })
}

pub fn billing_athena_auth_contract() -> BillingAthenaAuthContract {
    BillingAthenaAuthContract {
        rights_catalog_endpoint: "/admin/rights/catalog",
        grant_catalog_endpoint: "/admin/grant/list",
        sync_source_endpoint: "/admin/grant-assignment/sync-source",
        sync_source_action: "admin.grant_assignment.sync_source",
        preferred_sync_source_endpoint: "/admin/rights/sync-source",
        preferred_sync_source_action: "admin.rights.sync_source",
        sync_rights_source_endpoint: "/admin/rights/assignment/sync-source",
        sync_rights_source_action: "admin.rights.assignment.sync_source",
        sync_billing_endpoint: "/admin/grant-assignment/sync-billing",
        sync_billing_action: "admin.grant_assignment.sync_billing",
        preferred_sync_billing_endpoint: "/admin/rights/sync-billing",
        preferred_sync_billing_action: "admin.rights.sync_billing",
        sync_rights_billing_endpoint: "/admin/rights/assignment/sync-billing",
        sync_rights_billing_action: "admin.rights.assignment.sync_billing",
        runtime_env: BillingAthenaAuthRuntimeEnvContract {
            base_url: "ATHENA_NATIVE_RIGHT_SYNC_BASE_URL",
            path: "ATHENA_NATIVE_RIGHT_SYNC_PATH",
            api_key: "ATHENA_NATIVE_RIGHT_SYNC_API_KEY",
            header_name: "ATHENA_NATIVE_RIGHT_SYNC_HEADER_NAME",
            timeout_ms: "ATHENA_NATIVE_RIGHT_SYNC_TIMEOUT_MS",
            fail_mode: "ATHENA_NATIVE_RIGHT_SYNC_FAIL_MODE",
        },
        grant_named_runtime_env_aliases: BillingAthenaAuthRuntimeEnvContract {
            base_url: "ATHENA_NATIVE_GRANT_SYNC_BASE_URL",
            path: "ATHENA_NATIVE_GRANT_SYNC_PATH",
            api_key: "ATHENA_NATIVE_GRANT_SYNC_API_KEY",
            header_name: "ATHENA_NATIVE_GRANT_SYNC_HEADER_NAME",
            timeout_ms: "ATHENA_NATIVE_GRANT_SYNC_TIMEOUT_MS",
            fail_mode: "ATHENA_NATIVE_GRANT_SYNC_FAIL_MODE",
        },
        legacy_runtime_env_aliases: BillingAthenaAuthRuntimeEnvContract {
            base_url: "ATHENA_BILLING_AUTH_SYNC_BASE_URL",
            path: "ATHENA_BILLING_AUTH_SYNC_PATH",
            api_key: "ATHENA_BILLING_AUTH_SYNC_API_KEY",
            header_name: "ATHENA_BILLING_AUTH_SYNC_HEADER_NAME",
            timeout_ms: "ATHENA_BILLING_AUTH_SYNC_TIMEOUT_MS",
            fail_mode: "ATHENA_BILLING_AUTH_SYNC_FAIL_MODE",
        },
        replace_source_endpoint: "/admin/grant-assignment/replace-source",
        replace_source_action: "admin.grant_assignment.replace_source",
        request_contract: json!({
            "rightKeys": "native Athena Auth sync keys; preferred input contract for modular rights domains",
            "grantKeys": "compatibility alias for older grant-first callers; Athena Auth still persists the same resolved assignments",
            "rightModules": "preferred grouped module input for modular rights domains; billing keys are grouped under the billing module",
            "grantModules": "compatibility alias for older grant-first module callers",
            "nativeRightModules": "resolved grouped native-right module descriptors returned by Athena Auth and billing helper output surfaces",
            "nativeRights": "resolved native right descriptors returned by Athena Auth output surfaces",
            "unknownRightKeys": "requested keys that are not present in the configured native rights catalog",
            "projectionMetadata": "billing document metadata forwarded onto Athena Auth source assignments; payments can carry providerSubscriptionId when recurring provider events project through payment-first webhooks"
        }),
        request_shape: json!({
            "subjectKind": "user|org|workspace|tenant",
            "subjectId": "subject-id",
            "sourceKind": "payment|subscription|invoice",
            "sourceRef": "provider-resource-id",
            "rightKeys": ["payment-link.paid"],
            "grantKeys": ["payment-link.paid"],
            "rightModules": [{
                "key": "billing",
                "rightKeys": ["payment-link.paid"]
            }],
            "metadata": {
                "documentKind": "payment",
                "provider": "mollie",
                "status": "paid",
                "providerPaymentId": "tr_123",
                "providerSubscriptionId": "sub_123",
                "providerPaymentLinkId": "pl_123",
                "isPaymentLink": true,
                "origin": "billing.webhook"
            }
        }),
        reconcile_request_shape: json!({
            "resourceKind": "payment|payment_link|subscription|invoice",
            "providerRef": "provider-resource-id",
            "providerCustomerRef": "customer-id-for-subscription-lookups"
        }),
    }
}

pub fn billing_athena_auth_bootstrap_contract() -> BillingAthenaAuthBootstrapContract {
    let contract = billing_athena_auth_contract();
    BillingAthenaAuthBootstrapContract {
        rights_catalog_endpoint: contract.rights_catalog_endpoint,
        grant_catalog_endpoint: contract.grant_catalog_endpoint,
        sync_source_endpoint: contract.sync_source_endpoint,
        sync_source_action: contract.sync_source_action,
        preferred_sync_source_endpoint: contract.preferred_sync_source_endpoint,
        preferred_sync_source_action: contract.preferred_sync_source_action,
        sync_rights_source_endpoint: contract.sync_rights_source_endpoint,
        sync_rights_source_action: contract.sync_rights_source_action,
        sync_billing_endpoint: contract.sync_billing_endpoint,
        sync_billing_action: contract.sync_billing_action,
        preferred_sync_billing_endpoint: contract.preferred_sync_billing_endpoint,
        preferred_sync_billing_action: contract.preferred_sync_billing_action,
        sync_rights_billing_endpoint: contract.sync_rights_billing_endpoint,
        sync_rights_billing_action: contract.sync_rights_billing_action,
        runtime_env: BillingAthenaAuthBootstrapRuntimeEnvContract {
            base_url: contract.runtime_env.base_url,
            path: contract.runtime_env.path,
            api_key: contract.runtime_env.api_key,
            header_name: contract.runtime_env.header_name,
            timeout_ms: contract.runtime_env.timeout_ms,
            fail_mode: contract.runtime_env.fail_mode,
        },
        grant_named_runtime_env_aliases: BillingAthenaAuthBootstrapRuntimeEnvContract {
            base_url: contract.grant_named_runtime_env_aliases.base_url,
            path: contract.grant_named_runtime_env_aliases.path,
            api_key: contract.grant_named_runtime_env_aliases.api_key,
            header_name: contract.grant_named_runtime_env_aliases.header_name,
            timeout_ms: contract.grant_named_runtime_env_aliases.timeout_ms,
            fail_mode: contract.grant_named_runtime_env_aliases.fail_mode,
        },
        legacy_runtime_env_aliases: BillingAthenaAuthBootstrapRuntimeEnvContract {
            base_url: contract.legacy_runtime_env_aliases.base_url,
            path: contract.legacy_runtime_env_aliases.path,
            api_key: contract.legacy_runtime_env_aliases.api_key,
            header_name: contract.legacy_runtime_env_aliases.header_name,
            timeout_ms: contract.legacy_runtime_env_aliases.timeout_ms,
            fail_mode: contract.legacy_runtime_env_aliases.fail_mode,
        },
        replace_source_endpoint: contract.replace_source_endpoint,
        replace_source_action: contract.replace_source_action,
        request_contract: contract.request_contract,
        request_shape: contract.request_shape,
        reconcile_request_shape: contract.reconcile_request_shape,
    }
}

pub fn billing_grants_contract(route_key: &str) -> BillingGrantsContract {
    let grants = billing_grant_descriptor_views();
    let source_kinds = billing_source_kinds();
    let reconcile_resource_kinds = billing_reconcile_resource_kinds();

    BillingGrantsContract {
        counts: BillingGrantCountsContract {
            grants: grants.len(),
            source_kinds: source_kinds.len(),
            reconcile_resource_kinds: reconcile_resource_kinds.len(),
        },
        grants,
        route_key: route_key.to_string(),
        source_kinds,
        document_kinds: billing_document_kinds(),
        reconcile_resource_kinds,
        provider_catalog_endpoint: "/admin/billing/providers",
        connections: BillingConnectionsContract {
            list_endpoint: "/admin/billing/clients/{client_name}/connections",
            create_endpoint: "/admin/billing/clients/{client_name}/connections",
            get_endpoint: "/admin/billing/clients/{client_name}/connections/{connection_id}",
            update_endpoint: "/admin/billing/clients/{client_name}/connections/{connection_id}",
            delete_endpoint: "/admin/billing/clients/{client_name}/connections/{connection_id}",
            reconcile_endpoint: "/admin/billing/clients/{client_name}/connections/{connection_id}/reconcile",
            webhook_events_endpoint: "/admin/billing/clients/{client_name}/webhook-events",
            seed_sql: billing_connection_seed_sql_paths(),
            seed_sql_examples: billing_connection_seed_sql_examples(),
            request_examples: billing_connection_request_examples(),
            table_sql: "sql/billing.sql",
        },
        webhook_sinks: BillingWebhookSinksContract {
            helper_endpoint: "/admin/webhook-sinks/helpers/billing",
            provision_endpoint: "/admin/billing/clients/{client_name}/webhook-sinks/provision",
            seed_sql: "sql/billing_webhook_sinks_seed.sql",
            table_sql: "sql/billing.sql",
            target_table_sql_example: "sql/billing_target_schema_billing_example.sql",
        },
        athena_auth: billing_athena_auth_contract(),
        bootstrap: billing_integration_bootstrap_contract(route_key),
    }
}

pub fn billing_providers_integration_contract(
    route_key: &str,
) -> BillingProvidersIntegrationContract {
    BillingProvidersIntegrationContract {
        billing_grants_endpoint: "/admin/billing/grants",
        webhook_sink_helper_endpoint: "/admin/webhook-sinks/helpers/billing",
        webhook_sink_provision_endpoint: "/admin/billing/clients/{client_name}/webhook-sinks/provision",
        webhook_route_trigger: route_key.to_string(),
        connection_create_endpoint: "/admin/billing/clients/{client_name}/connections",
        connection_seed_sql: billing_connection_seed_sql_paths(),
        connection_seed_sql_examples: billing_connection_seed_sql_examples(),
        connection_request_examples: billing_connection_request_examples(),
        seed_sql: "sql/billing_webhook_sinks_seed.sql",
        table_sql: "sql/billing.sql",
        bootstrap: billing_integration_bootstrap_contract(route_key),
    }
}

pub fn billing_integration_bootstrap_contract(
    route_key: &str,
) -> BillingIntegrationBootstrapContract {
    BillingIntegrationBootstrapContract {
        provider_catalog_endpoint: "/admin/billing/providers",
        billing_grants_endpoint: "/admin/billing/grants",
        rights_catalog_endpoint: "/admin/rights/catalog",
        error_catalog_endpoint: "/admin/errors/catalog",
        docs_base_url: ATHENA_ERROR_DOCS_BASE_URL,
        webhook_route_template: "/billing/providers/{provider}/clients/{client_name}/connections/{connection_id}/webhook",
        webhook_route_trigger: route_key.to_string(),
        connection_create_endpoint: "/admin/billing/clients/{client_name}/connections",
        connection_reconcile_endpoint: "/admin/billing/clients/{client_name}/connections/{connection_id}/reconcile",
        connection_seed_sql: billing_connection_seed_sql_paths(),
        connection_seed_sql_examples: billing_connection_seed_sql_examples(),
        connection_request_examples: billing_connection_request_examples(),
        canonical_table_sql: "sql/billing.sql",
        canonical_target_table_sql_example: "sql/billing_target_schema_billing_example.sql",
        webhook_sink_helper_endpoint: "/admin/webhook-sinks/helpers/billing",
        webhook_sink_provision_endpoint: "/admin/billing/clients/{client_name}/webhook-sinks/provision",
        webhook_sink_seed_sql: "sql/billing_webhook_sinks_seed.sql",
        athena_auth: billing_athena_auth_bootstrap_contract(),
    }
}

pub fn billing_provider_runtime_contract(
    provider: BillingProvider,
    route_key: &str,
) -> BillingProviderRuntimeContract {
    let projection: BillingProviderProjectionContract = BillingProviderProjectionContract {
        canonical_document_kinds: billing_document_kinds()
            .into_iter()
            .map(ToString::to_string)
            .collect(),
        refetch_resource_kinds: billing_reconcile_resource_kinds()
            .into_iter()
            .map(ToString::to_string)
            .collect(),
        notes: match provider {
            BillingProvider::Mollie => vec![
                "Classic Mollie payment callbacks fetch the canonical payment by id after Athena accepts the webhook request.".to_string(),
                "Next-gen Mollie events can project payments, balance-transaction-backed payment refetches, payment-link-backed payments, subscriptions, and sales invoices.".to_string(),
            ],
            BillingProvider::Stripe => vec![
                "Stripe webhook events project snapshot payloads into canonical payments, subscriptions, invoices, and Checkout Session-backed payment-link flows.".to_string(),
                "Stripe reconciliation uses the same resource-kind coverage as webhook projection for payment, payment_link, subscription, and invoice lookups.".to_string(),
            ],
        },
    };

    let verification: BillingProviderVerificationContract = match provider {
        BillingProvider::Mollie => BillingProviderVerificationContract {
            verification_modes: vec![
                "classic_unsigned".to_string(),
                "next_gen_signature".to_string(),
            ],
            signature_header_name: Some("x-mollie-signature".to_string()),
            signing_secret_config_fields: vec!["signingSecrets".to_string()],
            notes: vec![
                "Classic Mollie payment callbacks are unsigned and carry only the payment id, so Athena fetches the upstream payment after route-level acceptance.".to_string(),
                "Next-gen Mollie events must match one configured X-Mollie-Signature secret before Athena projects the payload.".to_string(),
            ],
        },
        BillingProvider::Stripe => BillingProviderVerificationContract {
            verification_modes: vec!["stripe_signature".to_string()],
            signature_header_name: Some("stripe-signature".to_string()),
            signing_secret_config_fields: vec!["webhookSigningSecrets".to_string()],
            notes: vec![
                "Stripe requires a Stripe-Signature header that matches one configured webhook signing secret within Athena's configured timestamp tolerance.".to_string(),
            ],
        },
    };

    let athena_errors: Vec<BillingProviderErrorContract> = match provider {
        BillingProvider::Mollie => vec![
            billing_provider_error_contract(
                "MOLLIE_WEBHOOK_REJECTED",
                4001,
                401,
                "Athena rejected the Mollie webhook after signature or payload verification failed.",
            ),
            billing_provider_error_contract(
                "BILLING_CONNECTION_CONFIG_INVALID",
                4005,
                500,
                "The stored billing provider connection config is invalid.",
            ),
            billing_provider_error_contract(
                "BILLING_ADAPTER_FAILED",
                4006,
                502,
                "The upstream billing provider adapter failed while fetching or projecting provider state.",
            ),
            billing_provider_error_contract(
                "BILLING_WEBHOOK_PAYLOAD_UNSUPPORTED",
                4010,
                422,
                "The billing webhook payload was valid but Athena does not project that event shape yet.",
            ),
            billing_provider_error_contract(
                "BILLING_PROVIDER_RESPONSE_INVALID",
                4011,
                502,
                "Athena could not parse the upstream billing provider response or webhook payload.",
            ),
            billing_provider_error_contract(
                "BILLING_PROVIDER_HTTP_FAILED",
                4012,
                502,
                "Athena could not complete the required upstream billing provider HTTP request.",
            ),
        ],
        BillingProvider::Stripe => vec![
            billing_provider_error_contract(
                "STRIPE_WEBHOOK_REJECTED",
                4009,
                401,
                "Athena rejected the Stripe webhook after signature or payload verification failed.",
            ),
            billing_provider_error_contract(
                "BILLING_CONNECTION_CONFIG_INVALID",
                4005,
                500,
                "The stored billing provider connection config is invalid.",
            ),
            billing_provider_error_contract(
                "BILLING_ADAPTER_FAILED",
                4006,
                502,
                "The upstream billing provider adapter failed while fetching or projecting provider state.",
            ),
            billing_provider_error_contract(
                "BILLING_WEBHOOK_PAYLOAD_UNSUPPORTED",
                4010,
                422,
                "The billing webhook payload was valid but Athena does not project that event shape yet.",
            ),
            billing_provider_error_contract(
                "BILLING_PROVIDER_RESPONSE_INVALID",
                4011,
                502,
                "Athena could not parse the upstream billing provider response or webhook payload.",
            ),
            billing_provider_error_contract(
                "BILLING_PROVIDER_HTTP_FAILED",
                4012,
                502,
                "Athena could not complete the required upstream billing provider HTTP request.",
            ),
        ],
    };

    BillingProviderRuntimeContract {
        webhook_route_template:
            "/billing/providers/{provider}/clients/{client_name}/connections/{connection_id}/webhook"
                .to_string(),
        webhook_route_trigger: route_key.to_string(),
        connection_create_endpoint:
            "/admin/billing/clients/{client_name}/connections".to_string(),
        connection_reconcile_endpoint:
            "/admin/billing/clients/{client_name}/connections/{connection_id}/reconcile"
                .to_string(),
        verification,
        projection,
        athena_errors,
    }
}

pub fn billing_sink_integration_contract(route_key: &str) -> BillingSinkIntegrationContract {
    BillingSinkIntegrationContract {
        provider_catalog_endpoint: "/admin/billing/providers",
        billing_grants_endpoint: "/admin/billing/grants",
        webhook_route_trigger: route_key.to_string(),
        webhook_route_template: "/billing/providers/{provider}/clients/{client_name}/connections/{connection_id}/webhook",
        athena_auth: billing_athena_auth_contract(),
        bootstrap: billing_integration_bootstrap_contract(route_key),
    }
}

#[cfg(test)]
mod tests {
    use super::{
        billing_athena_auth_contract, billing_grant_descriptor_views, billing_grants_contract,
        billing_integration_bootstrap_contract, billing_provider_runtime_contract,
        billing_providers_integration_contract, billing_reconcile_resource_kinds,
        billing_sink_integration_contract,
    };
    use crate::BillingProvider;
    use serde_json::json;

    #[test]
    fn billing_grants_contract_keeps_rights_first_request_shape() {
        let contract = billing_grants_contract("billing_document_upserted");

        assert_eq!(contract.grants, billing_grant_descriptor_views());
        assert_eq!(
            contract.athena_auth.request_shape["rightModules"][0]["key"],
            json!("billing")
        );
        assert_eq!(
            contract.athena_auth.request_shape["rightKeys"],
            json!(["payment-link.paid"])
        );
        assert_eq!(
            contract.athena_auth.request_shape["grantKeys"],
            json!(["payment-link.paid"])
        );
        assert_eq!(
            contract.athena_auth.runtime_env.base_url,
            "ATHENA_NATIVE_RIGHT_SYNC_BASE_URL"
        );
    }

    #[test]
    fn provider_integration_contract_stays_aligned_with_grants_contract() {
        let grants = billing_grants_contract("billing_document_upserted");
        let providers = billing_providers_integration_contract("billing_document_upserted");

        assert_eq!(providers.billing_grants_endpoint, "/admin/billing/grants");
        assert_eq!(
            providers.webhook_sink_helper_endpoint,
            grants.webhook_sinks.helper_endpoint
        );
        assert_eq!(
            providers.connection_request_examples["mollie"]["provider"],
            json!("mollie")
        );
        assert_eq!(
            providers.connection_request_examples["stripe"]["provider"],
            json!("stripe")
        );
        assert_eq!(
            grants.reconcile_resource_kinds,
            billing_reconcile_resource_kinds()
        );
        assert_eq!(providers.bootstrap, grants.bootstrap);
    }

    #[test]
    fn athena_auth_contract_preserves_runtime_alias_families() {
        let contract = billing_athena_auth_contract();

        assert_eq!(
            contract.grant_named_runtime_env_aliases.path,
            "ATHENA_NATIVE_GRANT_SYNC_PATH"
        );
        assert_eq!(
            contract.legacy_runtime_env_aliases.base_url,
            "ATHENA_BILLING_AUTH_SYNC_BASE_URL"
        );
    }

    #[test]
    fn sink_integration_contract_reuses_shared_auth_contract() {
        let contract = billing_sink_integration_contract("billing_document_upserted");

        assert_eq!(
            contract.provider_catalog_endpoint,
            "/admin/billing/providers"
        );
        assert_eq!(contract.billing_grants_endpoint, "/admin/billing/grants");
        assert_eq!(contract.webhook_route_trigger, "billing_document_upserted");
        assert_eq!(
            contract.athena_auth.preferred_sync_billing_endpoint,
            "/admin/rights/sync-billing"
        );
        assert_eq!(
            contract.bootstrap.error_catalog_endpoint,
            "/admin/errors/catalog"
        );
        assert_eq!(
            contract.bootstrap.docs_base_url,
            "https://docs.athena-cluster.com"
        );
    }

    #[test]
    fn provider_runtime_contract_surfaces_provider_specific_verification_and_error_docs() {
        let mollie =
            billing_provider_runtime_contract(BillingProvider::Mollie, "billing_document_upserted");
        let stripe =
            billing_provider_runtime_contract(BillingProvider::Stripe, "billing_document_upserted");

        assert_eq!(
            mollie.verification.verification_modes,
            vec!["classic_unsigned", "next_gen_signature"]
        );
        assert_eq!(
            stripe.verification.signing_secret_config_fields,
            vec!["webhookSigningSecrets"]
        );
        assert_eq!(
            mollie.athena_errors[0].docs_url,
            "https://docs.athena-cluster.com/4001"
        );
        assert_eq!(stripe.athena_errors[0].code, "STRIPE_WEBHOOK_REJECTED");
        assert_eq!(
            stripe.projection.refetch_resource_kinds,
            billing_reconcile_resource_kinds()
        );
    }

    #[test]
    fn bootstrap_contract_unifies_routes_sql_and_error_docs() {
        let contract = billing_integration_bootstrap_contract("billing_document_upserted");

        assert_eq!(
            contract.provider_catalog_endpoint,
            "/admin/billing/providers"
        );
        assert_eq!(contract.billing_grants_endpoint, "/admin/billing/grants");
        assert_eq!(contract.rights_catalog_endpoint, "/admin/rights/catalog");
        assert_eq!(contract.error_catalog_endpoint, "/admin/errors/catalog");
        assert_eq!(contract.docs_base_url, "https://docs.athena-cluster.com");
        assert_eq!(
            contract.connection_seed_sql.mollie,
            "sql/billing_seed_mollie_example.sql"
        );
        assert_eq!(
            contract.canonical_target_table_sql_example,
            "sql/billing_target_schema_billing_example.sql"
        );
        assert_eq!(
            contract.athena_auth.preferred_sync_source_endpoint,
            "/admin/rights/sync-source"
        );
    }
}
