import Foundation

public enum VertexAIProviderDescriptor {
    public static let descriptor: ProviderDescriptor = Self.makeDescriptor()

    static func makeDescriptor() -> ProviderDescriptor {
        ProviderDescriptor(
            id: .vertexai,
            metadata: ProviderMetadata(
                id: .vertexai,
                displayName: "Vertex AI",
                shortDisplayName: "Vertex",
                sessionLabel: "Requests",
                weeklyLabel: "Tokens",
                opusLabel: nil,
                supportsOpus: false,
                supportsCredits: false,
                creditsHint: "",
                toggleTitle: "Show Vertex AI usage",
                cliName: "vertexai",
                defaultEnabled: false,
                widgetSelectable: false,
                isPrimaryProvider: false,
                usesAccountFallback: false,
                debugLogUnavailableMessage: "Vertex AI debug log not yet implemented",
                dashboardURL: "https://console.cloud.google.com/vertex-ai",
                statusPageURL: nil,
                statusLinkURL: "https://status.cloud.google.com"),
            branding: ProviderBranding(
                iconStyle: .init(provider: .vertexai),
                iconResourceName: "ProviderIcon-vertexai",
                color: ProviderColor(red: 66 / 255, green: 133 / 255, blue: 244 / 255),
                confettiPalette: [
                    ProviderColor(hex: 0x4285F4),
                    ProviderColor(hex: 0xEA4335),
                    ProviderColor(hex: 0xFBBC04),
                ]),
            tokenCost: ProviderTokenCostConfig(
                supportsTokenCost: true,
                noDataMessage: { "No Vertex AI cost data found in Claude logs. Ensure entries include Vertex metadata."
                },
                menuHintLines: [.localized("cost_estimate_hint")],
                supportsTokenSnapshot: true),
            presentation: ProviderUsagePresentation(menuCard: ProviderMenuCardPresentation(
                supportsInlineTokenCostDashboard: true)),
            fetchPlan: ProviderFetchPlan(
                sourceModes: [.auto, .oauth],
                pipeline: ProviderFetchPipeline(resolveStrategies: { _ in [VertexAIOAuthFetchStrategy()] })),
            cli: ProviderCLIConfig(
                name: "vertexai",
                versionDetector: nil))
    }
}

struct VertexAIOAuthFetchStrategy: ProviderFetchStrategy {
    let id: String = "vertexai.oauth"
    let kind: ProviderFetchKind = .oauth

    func isAvailable(_ context: ProviderFetchContext) async -> Bool {
        VertexAIOAuthCredentialsStore.hasCredentials(environment: context.env)
    }

    func fetch(_ context: ProviderFetchContext) async throws -> ProviderFetchResult {
        var credentials = try await VertexAIOAuthCredentialsStore.loadForFetch(environment: context.env)

        // Refresh token if expired
        if credentials.needsRefresh {
            credentials = try await VertexAITokenRefresher.refresh(credentials)
            try VertexAIOAuthCredentialsStore.save(credentials)
        }

        // Fetch quota usage from Cloud Monitoring. If no data is found (e.g., no recent
        // Vertex AI requests), return an empty snapshot so token costs can still display.
        let usage: VertexAIUsageResponse?
        do {
            usage = try await VertexAIUsageFetcher.fetchUsage(
                accessToken: credentials.accessToken,
                projectId: credentials.projectId)
        } catch VertexAIFetchError.noData {
            // No quota data is fine - token costs from local logs can still be shown.
            usage = nil
        }

        return self.makeResult(
            usage: Self.mapUsage(usage, credentials: credentials),
            sourceLabel: "oauth")
    }

    func shouldFallback(on error: Error, context _: ProviderFetchContext) -> Bool {
        if error is VertexAIOAuthCredentialsError {
            return true
        }
        if let fetchError = error as? VertexAIFetchError {
            switch fetchError {
            case .unauthorized, .forbidden:
                return true
            default:
                return false
            }
        }
        return false
    }

    private static func mapUsage(
        _ response: VertexAIUsageResponse?,
        credentials: VertexAIOAuthCredentials) -> UsageSnapshot
    {
        // Token cost is fetched separately via CostUsageScanner from local Claude logs.
        // Quota usage from Cloud Monitoring is optional - we still show token costs if unavailable.

        let identity = ProviderIdentitySnapshot(
            providerID: .vertexai,
            accountEmail: credentials.email,
            accountOrganization: credentials.projectId,
            loginMethod: "gcloud")

        return UsageSnapshot(
            primary: nil,
            secondary: nil,
            providerCost: nil,
            updatedAt: Date(),
            identity: identity)
    }
}
