import SwiftUI

/// Paywall sheet — shown from `SettingsView`'s "Auf Pro upgraden" button and
/// from `ProjectsListView` when creating a folder fails with `pro_required`.
///
/// Products and prices are loaded from `PurchaseService.loadProducts()` —
/// real, StoreKit-localized products via `StoreKitPurchaseService` by
/// default. Nothing here is hardcoded copy; if products fail to load, a
/// retry affordance is shown instead of guessing at prices.
struct PaywallView: View {
    @Environment(\.dismiss) private var dismiss
    @EnvironmentObject private var appState: AppState
    @State private var products: [PurchaseProduct] = []
    @State private var isLoadingProducts = false
    @State private var loadErrorMessage: String?
    @State private var purchasingProductID: String?
    @State private var errorMessage: String?
    @State private var purchaseCompletedMessage: String?
    @State private var isRestoring = false
    private let purchaseService: PurchaseService

    init(purchaseService: PurchaseService = StoreKitPurchaseService()) {
        self.purchaseService = purchaseService
    }

    var body: some View {
        NavigationStack {
            ScrollView {
                VStack(spacing: ZenithSpacing.md) {
                    Text("Unbegrenzt scannen, Ordner anlegen und exportieren.")
                        .zenithBodyStyle(color: .zenithMuted)
                        .multilineTextAlignment(.center)
                        .padding(.horizontal)

                    content

                    if !products.isEmpty {
                        Button {
                            Task { await restore() }
                        } label: {
                            if isRestoring {
                                ProgressView()
                            } else {
                                Text("Käufe wiederherstellen")
                            }
                        }
                        .buttonStyle(.zenithPlain)
                        .disabled(isRestoring || purchasingProductID != nil)
                    }
                }
                .padding(ZenithSpacing.sm)
            }
            .background(Color.zenithBg)
            .navigationTitle("ScanReceipts Pro")
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .cancellationAction) {
                    Button("Schließen") { dismiss() }
                }
            }
            .task {
                await loadProducts()
            }
            .alert("Kauf nicht möglich", isPresented: errorAlertBinding) {
                Button("OK", role: .cancel) {}
            } message: {
                Text(errorMessage ?? "")
            }
            .alert("Kauf abgeschlossen", isPresented: purchaseCompletedAlertBinding) {
                Button("OK", role: .cancel) { dismiss() }
            } message: {
                Text(purchaseCompletedMessage ?? "")
            }
        }
    }

    @ViewBuilder
    private var content: some View {
        if isLoadingProducts && products.isEmpty {
            ProgressView()
                .padding(.vertical, ZenithSpacing.lg)
        } else if let loadErrorMessage, products.isEmpty {
            VStack(spacing: ZenithSpacing.xs) {
                Text(loadErrorMessage)
                    .zenithBodySmStyle()
                    .multilineTextAlignment(.center)
                Button("Erneut versuchen") {
                    Task { await loadProducts() }
                }
                .buttonStyle(.zenithPlain)
            }
            .padding(.vertical, ZenithSpacing.lg)
        } else {
            ForEach(products) { product in
                productCard(product)
            }
        }
    }

    private var errorAlertBinding: Binding<Bool> {
        Binding(
            get: { errorMessage != nil },
            set: { if !$0 { errorMessage = nil } }
        )
    }

    private var purchaseCompletedAlertBinding: Binding<Bool> {
        Binding(
            get: { purchaseCompletedMessage != nil },
            set: { if !$0 { purchaseCompletedMessage = nil } }
        )
    }

    private func productCard(_ product: PurchaseProduct) -> some View {
        VStack(alignment: .leading, spacing: ZenithSpacing.xs) {
            Text(product.displayName)
                .zenithHeadlineMdStyle()
            Text(priceLabel(for: product))
                .zenithLabelMdStyle()

            Button {
                Task { await purchase(product) }
            } label: {
                if purchasingProductID == product.id {
                    ProgressView()
                        .tint(.white)
                } else {
                    Text("Kaufen")
                }
            }
            .buttonStyle(.zenithPrimary)
            .disabled(purchasingProductID != nil)
            .opacity(purchasingProductID != nil && purchasingProductID != product.id ? 0.5 : 1)
            .padding(.top, ZenithSpacing.xs)
        }
        .frame(maxWidth: .infinity, alignment: .leading)
        .zenithCard()
    }

    private func priceLabel(for product: PurchaseProduct) -> String {
        if let period = product.periodDescription {
            return "\(product.displayPrice) · \(period)"
        }
        return product.displayPrice
    }

    private func loadProducts() async {
        isLoadingProducts = true
        loadErrorMessage = nil
        defer { isLoadingProducts = false }
        do {
            products = try await purchaseService.loadProducts()
        } catch {
            loadErrorMessage = error.localizedDescription
        }
    }

    /// On success (`true`), shows a neutral completion message and dismisses
    /// once the user acknowledges it. `POST /api/webhooks/apple` now exists
    /// server-side and (given a resolvable `appAccountToken`, see
    /// `User.appleAccountToken`) does grant Pro from this purchase — but
    /// that whole path is genuinely unverified end-to-end (no real Apple
    /// Developer account/device available to generate a live transaction
    /// against it), and delivery of Apple's server notification isn't
    /// synchronous with the purchase sheet closing. So: still no "You're Pro
    /// now!" claim here — that would assert something this code hasn't
    /// actually observed happening. `false` means the user cancelled the
    /// StoreKit sheet, not an error, no message needed. A thrown error is
    /// surfaced in the existing error alert.
    private func purchase(_ product: PurchaseProduct) async {
        purchasingProductID = product.id
        defer { purchasingProductID = nil }
        do {
            let completed = try await purchaseService.purchase(
                productID: product.id,
                appAccountToken: appState.currentUser?.appleAccountToken
            )
            if completed {
                purchaseCompletedMessage = "Kauf abgeschlossen."
            }
        } catch {
            errorMessage = error.localizedDescription
        }
    }

    private func restore() async {
        isRestoring = true
        defer { isRestoring = false }
        do {
            try await purchaseService.restorePurchases()
        } catch {
            errorMessage = error.localizedDescription
        }
    }
}
