//
//  StoreManager.swift
//  SodaLive
//
//  Created by klaus on 2023/08/11.
//
//  Ref.
//  https://www.youtube.com/watch?v=qyKmpr9EjwU
//  https://nicgoon.tistory.com/205
//  https://charlie-choi.tistory.com/241
//  https://eunjo-princess.tistory.com/20
//  https://developer.apple.com/documentation/storekit/in-app_purchase/original_api_for_in-app_purchase/validating_receipts_with_the_app_store#//apple_ref/doc/uid/TP40010573-CH104-SW2
//  https://velog.io/@givepro91/%EC%9D%B8%EC%95%B1%EA%B2%B0%EC%A0%9C-%EC%84%9C%EB%B2%84-%EA%B0%9C%EB%B0%9C
//  https://twih1203.medium.com/swift-%EC%9D%B8%EC%95%B1-%EA%B2%B0%EC%A0%9C-%EA%B5%AC%ED%98%84-ff4b2d20a260
//

import Foundation
import StoreKit

class StoreManager: NSObject, ObservableObject {
    @Published var errorMessage = ""
    @Published var isShowPopup = false
    @Published var isLoading = false
    
    @Published var products = [SKProduct]()
    
    var onSuccessPayment: ((String, Int) -> Void)?
    var chargeId: Int!
    
    var request: SKProductsRequest!
    
    func getProducts() {
        isLoading = true
        products.removeAll()
        
        let request = SKProductsRequest(productIdentifiers: [
            "\(Bundle.main.bundleIdentifier!).can_35",
            "\(Bundle.main.bundleIdentifier!).can_55",
            "\(Bundle.main.bundleIdentifier!).can_105",
            "\(Bundle.main.bundleIdentifier!).can_350",
            "\(Bundle.main.bundleIdentifier!).can_550",
            "\(Bundle.main.bundleIdentifier!).can_1170",
            "\(Bundle.main.bundleIdentifier!).can_3580",
            "\(Bundle.main.bundleIdentifier!).can_5750",
        ])
        request.delegate = self
        request.start()
    }
    
    func payment(product: SKProduct, chargeId: Int) {
        isLoading = true
        self.chargeId = chargeId
        let payment = SKPayment(product: product)
        SKPaymentQueue.default().add(self)
        SKPaymentQueue.default().add(payment)
    }
}

extension StoreManager: SKProductsRequestDelegate {
    func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
        if !response.products.isEmpty {
            let products = response.products.sorted { $0.price.compare($1.price) == .orderedAscending }
            
            for product in products {
                DispatchQueue.main.async {
                    self.products.append(product)
                }
            }
        }
        
        DispatchQueue.main.async { [unowned self] in
            self.isLoading = false
        }
        self.request = nil
    }
    
    func request(_ request: SKRequest, didFailWithError error: Error) {
        self.request = nil
        DEBUG_LOG("상품불러오기 실패: \(error)")
        DispatchQueue.main.async { [unowned self] in
            self.isLoading = false
            errorMessage = "상품을 불러오지 못했습니다.\n다시 시도해 주세요."
            self.isShowPopup = true
        }
    }
}

extension StoreManager: SKPaymentTransactionObserver {
    func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
        for transaction in transactions {
            switch(transaction.transactionState) {
            case .purchasing:
                DEBUG_LOG("결제 진행 중...")
                break
                
            case .purchased:
                isLoading = false
                DEBUG_LOG("결제 완료")
                complete(transaction: transaction)
                break
                
            case .failed:
                isLoading = false
                DEBUG_LOG("결제 실패")
                fail(transaction: transaction)
                break
                
            case .deferred:
                isLoading = false
                DEBUG_LOG("아이폰이 잠김 등의 이유로 결제를 진행하지 못했습니다.")
                errorMessage = "아이폰이 잠김 등의 이유로 결제를 진행하지 못했습니다."
                isShowPopup = true
                
                SKPaymentQueue.default().finishTransaction(transaction)
                SKPaymentQueue.default().remove(self)
                break
                
            case .restored:
                isLoading = false
                DEBUG_LOG("상품 검증을 하였습니다.")
                errorMessage = "상품 검증을 하였습니다."
                isShowPopup = true
                
                SKPaymentQueue.default().finishTransaction(transaction)
                SKPaymentQueue.default().remove(self)
                break
                
            @unknown default:
                isLoading = false
                DEBUG_LOG("알 수 없는 오류가 발생했습니다.")
                errorMessage = "알 수 없는 오류가 발생했습니다."
                isShowPopup = true
                
                SKPaymentQueue.default().finishTransaction(transaction)
                SKPaymentQueue.default().remove(self)
                
                fatalError()
            }
        }
    }
    
    private func complete(transaction: SKPaymentTransaction) {
        if let onSuccessPayment = onSuccessPayment {
            if let appStoreReceiptURL = Bundle.main.appStoreReceiptURL,
                FileManager.default.fileExists(atPath: appStoreReceiptURL.path) {

                do {
                    let receiptData = try Data(contentsOf: appStoreReceiptURL, options: .alwaysMapped)
                    let receiptString = receiptData.base64EncodedString(options: [])
                    onSuccessPayment(receiptString, chargeId)
                    
                    SKPaymentQueue.default().finishTransaction(transaction)
                    SKPaymentQueue.default().remove(self)
                }
                catch {
                    DEBUG_LOG("영수증 데이터 읽기 실패: " + error.localizedDescription)
                    fail(transaction: transaction)
                }
            } else {
                DEBUG_LOG("영수증 데이터 읽기 실패")
                fail(transaction: transaction)
            }
        } else {
            fail(transaction: transaction)
        }
    }
    
    private func fail(transaction: SKPaymentTransaction) {
        if let transactionError = transaction.error as NSError?,
            let localizedDescription = transaction.error?.localizedDescription,
            transactionError.code != SKError.paymentCancelled.rawValue {
            DEBUG_LOG("Transaction Error: \(localizedDescription)")
        }
        
        DispatchQueue.main.async { [unowned self] in
            errorMessage = "결제를 진행하지 못했습니다.\n다시 시도해 주세요."
            isShowPopup = true
        }
        
        SKPaymentQueue.default().finishTransaction(transaction)
        SKPaymentQueue.default().remove(self)
    }
}
