import Foundation

/// Resolves Bedrock signing credentials + region for the configured auth mode.
///
/// Shared by the main usage fetch (`BedrockAPIFetchStrategy`) and the daily
/// cost-history refresh (`CostUsageFetcher`) so both honor AWS-profile auth
/// identically instead of the history path silently requiring static keys.
enum BedrockCredentialResolver {
    struct Resolved {
        let credentials: BedrockAWSSigner.Credentials
        let region: String
    }

    static func resolve(
        environment: [String: String],
        resolveAWSBinary: ([String: String]) -> String? = { BinaryLocator.resolveAWSBinary(env: $0) },
        makeProvider: (String) -> BedrockProfileCredentialProvider = {
            BedrockProfileCredentialProvider.live(awsBinaryPath: $0)
        }) async throws -> Resolved
    {
        switch BedrockSettingsReader.authMode(environment: environment) {
        case .keys:
            guard let accessKeyID = BedrockSettingsReader.accessKeyID(environment: environment),
                  let secretAccessKey = BedrockSettingsReader.secretAccessKey(environment: environment)
            else {
                throw BedrockUsageError.missingCredentials
            }
            let credentials = BedrockAWSSigner.Credentials(
                accessKeyID: accessKeyID,
                secretAccessKey: secretAccessKey,
                sessionToken: BedrockSettingsReader.sessionToken(environment: environment))
            return Resolved(
                credentials: credentials,
                region: BedrockSettingsReader.region(environment: environment))

        case .profile:
            guard let profile = BedrockSettingsReader.profile(environment: environment) else {
                throw BedrockUsageError.missingCredentials
            }
            guard let awsBinary = resolveAWSBinary(environment) else {
                throw BedrockUsageError.awsCLINotFound
            }
            let cliEnvironment = Self.profileCLIEnvironment(environment)
            let provider = makeProvider(awsBinary)
            let credentials = try await provider.exportCredentials(profile: profile, environment: cliEnvironment)
            let region = try await Self.resolveRegion(
                provider: provider,
                profile: profile,
                environment: cliEnvironment)
            return Resolved(credentials: credentials, region: region)
        }
    }

    private static func profileCLIEnvironment(_ environment: [String: String]) -> [String: String] {
        var cliEnvironment = environment
        // `--profile` selects the requested profile. Leaving AWS_PROFILE set can
        // break assume-role profiles that use `credential_source = Environment`;
        // keep the source credential variables themselves available.
        cliEnvironment[BedrockSettingsReader.profileKey] = nil
        return cliEnvironment
    }

    private static func resolveRegion(
        provider: BedrockProfileCredentialProvider,
        profile: String,
        environment: [String: String]) async throws -> String
    {
        if let explicit = BedrockSettingsReader.cleaned(environment[BedrockSettingsReader.regionKeys[0]])
            ?? BedrockSettingsReader.cleaned(environment[BedrockSettingsReader.regionKeys[1]])
        {
            return explicit
        }
        if let derived = try await provider.resolveRegion(profile: profile, environment: environment) {
            return derived
        }
        return BedrockSettingsReader.defaultRegion
    }
}
