//
//  SubscriptionView.swift
//  PadelClub
//
//  Created by Laurent Morvillier on 13/02/2024.
//

import SwiftUI
import StoreKit
import LeStorage

extension Product.SubscriptionPeriod.Unit {
    var label: String {
        switch self {
        case .day: return "jour"
        case .week: return "semaine"
        case .month: return "mois"
        case .year: return "année"
        @unknown default: return "inconnu"
        }
    }
}
extension Product {
    var item: StoreItem {
        return StoreItem(rawValue: self.id)!
    }
    var formattedPrice: String {
        if let period = self.subscription?.subscriptionPeriod {
            return self.displayPrice + " / " + period.unit.label
        }
        return self.displayPrice
    }
}

class SubscriptionModel: ObservableObject, StoreDelegate {
    
    var storeManager: StoreManager? = nil
    @Published var error: Error? = nil
    
    @Published var isLoading: Bool = false
    @Published var selectedProduct: Product? = nil {
        didSet {
            self._computePrice()
        }
    }
    @Published var quantity: Int = 1
    @Published var products: [Product] = []
    @Published var totalPrice: String = ""

    init() {
        self.load()
    }
    
    func load() {
        self.isLoading = true
        if self.storeManager == nil {
            self.storeManager = StoreManager(delegate: self)
        }
    }
    
    func isSelected(product: Product) -> Bool {
        return self.selectedProduct == product
    }
    
    func productsReceived(products: [Product]) {
        self.isLoading = false
        self.products = products
        Logger.log("products received = \(products.count)")
    }
    
    func errorDidOccur(error: Error) {
        self.isLoading = false
        self.error = error
    }

    func purchase() async throws -> Bool {
        Logger.log("start purchase...")
        guard let product: Product = self.selectedProduct, let storeManager = self.storeManager else {
            Logger.w("missing product or store manager")
            return false
        }
        
        if product.item.isConsumable {
            if let _ = try await storeManager.purchase(product, quantity: self.quantity) {
                return true
            }
        } else {
            let _ = try await storeManager.purchase(product)
            return true
        }
        return false
    }
    
    fileprivate func _computePrice() {
        
        if let product = self.selectedProduct, let item = StoreItem(rawValue: product.id) {
            if item.isConsumable {
                let price = NSDecimalNumber(decimal: product.price).multiplying(by: NSDecimalNumber(integerLiteral: self.quantity))
                self.totalPrice = product.priceFormatStyle.format(price.decimalValue)
            } else {
                self.totalPrice = product.displayPrice
            }
        } else {
            self.totalPrice = ""
        }
    }
    
}

struct SubscriptionView: View {
    
    @ObservedObject var model: SubscriptionModel = SubscriptionModel()

    @Binding var isPresented: Bool
    
    var showLackOfPlanMessage: Bool = false
    @State var isRestoring: Bool = false
    @State var showLoginView: Bool = false
    @State var isPurchasing: Bool = false
    @State var showSuccessfulPurchaseView: Bool = false

    init(isPresented: Binding<Bool>, showLackOfPlanMessage: Bool = false) {
        self._isPresented = isPresented
        self.showLackOfPlanMessage = showLackOfPlanMessage
    }
    
    var body: some View {
        
        VStack {
            if self.showLoginView {
                LoginView { _ in
                    self.showLoginView = false
                    self._purchase()
                }
            } else {
                
                if self.showLackOfPlanMessage {
                    SubscriptionDetailView()
                }
                
                List {
                    
                    if self.model.products.count > 0 {
                        
                        ProductsSectionView(model: self.model)
                        
                        if let product = self.model.selectedProduct {
                            
                            Section {
                                
                                Button {
                                    self._purchaseIfPossible()
                                } label: {
                                    PurchaseLabelView(price: self.model.totalPrice, isPurchasing: self.isPurchasing)
                                }
                                .buttonStyle(.borderedProminent)
                                .tint(.orange)
                                .listRowBackground(Color.clear)

                            } footer: {
                                if product.item.isConsumable == false {
                                    SubscriptionFooterView()
                                        .foregroundStyle(Color(white: 0.8))
                                }
                            }
                        }
                        
                    } else {
                        NoProductView()
                            .isLoading(self.model.isLoading)
                    }
                }
                .listStyle(.grouped)
                .scrollContentBackground(.hidden)
                .background(.logoBackground)
                .toolbar {
                    ToolbarItem(placement: .navigationBarTrailing) {
                        Button("Restaurer") {
                            self._restore()
                        }.isLoading(self.isRestoring)
                    }
                }
            }
        }
        .preferredColorScheme(.dark)
        .navigationTitle("Abonnements")
        
    }
    
    fileprivate func _purchaseIfPossible() {
        if Store.main.userId != nil {
            self._purchase()
        } else {
            self.showLoginView = true
        }
    }
    
    fileprivate func _purchase() {
        
        self.isPurchasing = true

        Task {
            do {
                let success = try await self.model.purchase()
                DispatchQueue.main.async {
                    self.isPurchasing = false
                    self.showSuccessfulPurchaseView = true
                    if success {
                        self.isPresented = false
                    }
                }
            } catch {
                Logger.error(error)
                DispatchQueue.main.async {
                    self.isPurchasing = false
                }
            }
        }
    }
    
    fileprivate func _restore() {
        
        Task {
            do {
                self.isRestoring = true
                try await Guard.main.refreshPurchasedAppleProducts()
                self.isRestoring = false
            } catch {
                self.isRestoring = false
                Logger.error(error)
            }
        }
    }
    
}

fileprivate struct ProductsSectionView: View {
    
    @ObservedObject var model: SubscriptionModel
    
    var body: some View {
        Section {
            ForEach(self.model.products) { product in
                ProductView(product: product,
                            model: self.model)
                .onTapGesture {
                    self.model.selectedProduct = product
                }
            }
        } header: {
            Text("Sélectionnez une offre")
        }

    }
}

fileprivate struct PurchaseLabelView: View {
    
    var price: String
    var isPurchasing: Bool
    
    var body: some View {
        HStack(alignment: .center) {
            if self.isPurchasing {
                Spacer()
                ProgressView().tint(Color.white)
                Spacer()
            } else {
                Text("Acheter")
                Spacer()
                Text(self.price)
            }
        }
        .padding(8.0)
        .fontWeight(.bold)
    }
}

fileprivate struct NoProductView: View {
    var body: some View {
        HStack {
            if let plan = Guard.main.currentPlan {
                Image(systemName: plan.systemImage)
            } else {
                Image(systemName: "questionmark.diamond.fill")
            }
            Text("Il n'y a pas de produits à vous proposer")
        }
    }
}

struct ProductView: View {
    
    var product: Product
    
    @ObservedObject var model: SubscriptionModel
    
//    @Binding var quantity: Int
//    var selected: Bool
    
    var body: some View {
        HStack {
            Image(systemName: self._image)
                .font(.system(size: 36.0))
                .foregroundColor(.orange)
            VStack(alignment: .leading) {
                Text(self.product.displayName)
                Text(self.product.formattedPrice)
                    .foregroundColor(.accentColor)
                if self._isConsumable {
                    StepperView(count: self.$model.quantity, minimum: 1, countChanged: { self.model.selectedProduct = self.product })
                        .font(.callout).foregroundColor(.accentColor)
                }
            }
            Spacer()
            if self.model.isSelected(product: self.product) {
                Image(systemName: "checkmark")
                    .foregroundColor(.accentColor)
            }
        }
        .contentShape(.rect)
        .foregroundStyle(.white)
        .frame(maxWidth: .infinity)
        .buttonStyle(.borderedProminent)
        .tint(Color.master)
        .listRowBackground(Color.clear)
    }
        
    fileprivate var _item: StoreItem? {
        return StoreItem(rawValue: self.product.id)
    }
    
    fileprivate var _isConsumable: Bool {
        return self._item?.isConsumable ?? false
    }
    
    fileprivate var _image: String {
        if let item = self._item {
            return item.systemImage
        } else {
            return "gift.circle.fill"
        }
    }
    
}

fileprivate struct SubscriptionNoProductView: View {
    
    @ObservedObject var model: SubscriptionModel
    
    var body: some View {
        VStack(alignment: .center) {
            
            if let error = self.model.error {
                Text(error.localizedDescription)
            } else {
                Text("Aucun produit disponible")
            }
            
            if self.model.isLoading {
                ProgressView()
            } else {
                Button(action: {
                    self.model.load()
                }, label: {
                    Image(systemName: "arrow.clockwise.circle.fill")
                        .font(.system(size: 64.0))
                })
            }
        }

    }
}

fileprivate struct SubscriptionFooterView: View {
    var body: some View {
        Text("Conditions d’utilisations concernant l’abonnement:\n- Le paiement sera facturé sur votre compte Apple.\n- L’abonnement est renouvelé automatiquement chaque mois, à moins d’avoir été désactivé au moins 24 heures avant la fin de la période de l’abonnement.\n- L’abonnement peut être géré par l’utilisateur et désactivé en allant dans les réglages de son compte après s’être abonné.\n- Le compte sera facturé pour le renouvellement de l'abonnement dans les 24 heures précédent la fin de la période d’abonnement.\n- Un abonnement en cours ne peut être annulé.\n- Toute partie inutilisée de l'offre gratuite, si souscrite, sera abandonnée lorsque l'utilisateur s'abonnera, dans les cas applicables.")
            .padding(.top)
    }
}

fileprivate struct SubscriptionDetailView: View {
    
    var body: some View {
        HStack {
            Image(systemName: "exclamationmark.bubble.fill")
                //.foregroundStyle(Color.accentColor)
                .font(.title)
            Text("Vous êtes arrivé à limite de votre offre actuelle. Voici ce que nous proposons pour poursuivre votre tournoi:")
                .fontWeight(.semibold)
        }
        .padding()
        .background(.orange)
        .foregroundStyle(.black)
        .clipShape(.rect(cornerRadius: 16.0))
        .padding()
    }
    
}

//#Preview {
//    SubscriptionDetailView()
//}

//#Preview {
//    NavigationStack {
//        SubscriptionView(isPresented: .constant(true), showLackOfPlanMessage: false)
//    }
//}
