//
//  LNExchangePanel.swift
//  Lanu
//
//  Created by OneeChan on 2026/1/8.
//

import Foundation
import UIKit
import SnapKit


enum LNExchangeType {
    case coinToDiamond
    case diamondToCoin
    case beanToCoin
    case beanToDiamond
    
    var exchangeType: (from: LNCurrencyType, to: LNCurrencyType) {
        switch self {
        case .coinToDiamond: (.coin, .diamond)
        case .diamondToCoin: (.diamond, .coin)
        case .beanToCoin: (.bean, .coin)
        case .beanToDiamond: (.bean, .diamond)
        }
    }
    
    static func map(from: LNCurrencyType, to: LNCurrencyType) -> Self? {
        if from == .coin, to == .diamond {
            .coinToDiamond
        } else if from == .diamond, to == .coin {
            .diamondToCoin
        } else if from == .bean, to == .coin {
            .beanToCoin
        } else if from == .bean, to == .diamond {
            .beanToDiamond
        } else {
            nil
        }
    }
    
    var rate: Double? {
        let config = LNConfigManager.shared.commonConfig.commonCoinExchangeConsts
        
        switch self {
        case .coinToDiamond:
            guard let coin = config.first(where: { $0.IDR != nil && $0.goldCoin != nil }),
                  let diamond = config.first(where: { $0.IDR != nil && $0.diamond != nil })
            else {
                return nil
            }
            return coin.IDR! / coin.goldCoin! / (diamond.IDR! / diamond.diamond!)
        case .diamondToCoin:
            guard let coin = config.first(where: { $0.IDR != nil && $0.goldCoin != nil }),
                  let diamond = config.first(where: { $0.IDR != nil && $0.diamond != nil })
            else {
                return nil
            }
            return diamond.IDR! / diamond.diamond! / (coin.IDR! / coin.goldCoin!)
        case .beanToCoin:
            guard let bean = config.first(where: { $0.IDR != nil && $0.bean != nil }),
                  let coin = config.first(where: { $0.IDR != nil && $0.goldCoin != nil })
            else {
                return nil
            }
            return bean.IDR! / bean.bean! / (coin.IDR! / coin.goldCoin!)
        case .beanToDiamond:
            guard let bean = config.first(where: { $0.IDR != nil && $0.bean != nil }),
                  let diamond = config.first(where: { $0.IDR != nil && $0.diamond != nil })
            else {
                return nil
            }
            return bean.IDR! / bean.bean! / (diamond.IDR! / diamond.diamond!)
        }
    }
}


class LNExchangePanel: LNPopupView {
    private let exchangeType: LNExchangeType
    
    private let exchangeView = UIView()
    private let remainLabel = UILabel()
    private let exchangeInput = UITextField()
    private let expectLabel = UILabel()
    
    private let exchangeButton = UIButton()
    private var delayTaskId: String?
    
    init(exchangeType: LNExchangeType) {
        self.exchangeType = exchangeType
        super.init(frame: .zero)
        
        setupViews()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

extension LNExchangePanel: UITextFieldDelegate {
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        let currentText = textField.text ?? ""
                
        guard let range = Range(range, in: currentText) else { return false }
        let newText = currentText.replacingCharacters(in: range, with: string)
        if newText.isEmpty {
            return true
        }
        if newText.starts(with: "00") {
            return false
        }
        
        if newText.filter({ $0 == "." }).count > 2 {
            return false
        }
        
        guard Double(newText) != nil else {
            return false
        }
        
        return true
    }
    
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        textField.resignFirstResponder()
        return true
    }
}

extension LNExchangePanel {
    private func checkExchangeButton() {
        let text = exchangeInput.text ?? ""
        if text.isEmpty {
            exchangeInput.attributedPlaceholder = .init(string: .init(key: "A00261"),
                                                    attributes: [.font: UIFont.heading_h3,
                                                                 .foregroundColor: UIColor.text_2])
        } else {
            exchangeInput.attributedPlaceholder = nil
        }
        
        fetchExchangeResult()
    }
    
    private func fetchExchangeResult() {
        LNDelayTask.cancel(key: delayTaskId)
        
        exchangeButton.isEnabled = false
        exchangeButton.setBackgroundImage(nil, for: .normal)
        delayTaskId = LNDelayTask.perform(delay: 1.0) { [weak self] in
            guard let self else { return }
            let text = exchangeInput.text ?? ""
            let value = Double(text) ?? 0
            if value == 0 {
                expectLabel.text = "0"
                return
            }
            LNPurchaseManager.shared.expectResult(exchangeType: exchangeType, count: value)
            { [weak self] result in
                guard let self else { return }
                guard exchangeInput.text == text else { return }
                
                if let result {
                    expectLabel.text = "\(result)"
                    exchangeButton.isEnabled = true
                    exchangeButton.setBackgroundImage(.primary_8, for: .normal)
                } else {
                    expectLabel.text = ""
                }
            }
        }
    }
    
    private func setupViews() {
        let titleView = buildTitleView()
        container.addSubview(titleView)
        titleView.snp.makeConstraints { make in
            make.horizontalEdges.equalToSuperview()
            make.top.equalToSuperview()
        }
        
        let remainView = buildRemain()
        container.addSubview(remainView)
        remainView.snp.makeConstraints { make in
            make.horizontalEdges.equalToSuperview()
            make.top.equalTo(titleView.snp.bottom).offset(4)
        }
        
        exchangeView.backgroundColor = .fill_1
        exchangeView.layer.cornerRadius = 12
        container.addSubview(exchangeView)
        exchangeView.snp.makeConstraints { make in
            make.horizontalEdges.equalToSuperview().inset(16)
            make.top.equalTo(remainView.snp.bottom).offset(4)
        }
        
        let diamondExchange = buildExchangeView()
        exchangeView.addSubview(diamondExchange)
        diamondExchange.snp.makeConstraints { make in
            make.horizontalEdges.equalToSuperview()
            make.top.equalToSuperview()
        }
        
        let line = UIView()
        line.backgroundColor = .fill_3
        exchangeView.addSubview(line)
        line.snp.makeConstraints { make in
            make.horizontalEdges.equalToSuperview().inset(10)
            make.top.equalTo(diamondExchange.snp.bottom).offset(4)
            make.height.equalTo(1)
        }
        
        let coinView = buildExpectView()
        exchangeView.addSubview(coinView)
        coinView.snp.makeConstraints { make in
            make.horizontalEdges.equalToSuperview()
            make.bottom.equalToSuperview()
            make.top.equalTo(line.snp.bottom).offset(4)
        }
        
        exchangeButton.setTitle(.init(key: "A00262"), for: .normal)
        exchangeButton.setTitleColor(.text_1, for: .normal)
        exchangeButton.titleLabel?.font = .heading_h3
        exchangeButton.backgroundColor = .text_2
        exchangeButton.layer.cornerRadius = 23.5
        exchangeButton.clipsToBounds = true
        exchangeButton.isEnabled = false
        exchangeButton.setBackgroundImage(nil, for: .normal)
        exchangeButton.addAction(UIAction(handler: { [weak self] _ in
            guard let self else { return }
            guard let amout = Double(exchangeInput.text ?? "") else { return }
            guard amout > 0 else { return }
            LNPurchaseManager.shared.exchangeCurrency(exchangeType: exchangeType, amount: amout) { [weak self] success in
                guard let self else { return }
                guard success else { return }
                dismiss()
                showToast(.init(key: "A00263"))
            }
        }), for: .touchUpInside)
        container.addSubview(exchangeButton)
        exchangeButton.snp.makeConstraints { make in
            make.horizontalEdges.equalToSuperview().inset(16)
            make.height.equalTo(47)
            make.top.equalTo(exchangeView.snp.bottom).offset(24)
            make.bottom.equalToSuperview().offset(commonBottomInset)
        }
    }
    
    private func buildTitleView() -> UIView {
        let titleView = UIView()
        titleView.isUserInteractionEnabled = false
        titleView.snp.makeConstraints { make in
            make.height.equalTo(50)
        }
        
        let titleLabel = UILabel()
        titleLabel.text = switch exchangeType {
        case .coinToDiamond, .beanToDiamond: .init(key: "A00264")
        case .diamondToCoin, .beanToCoin: .init(key: "A00273")
        }
        titleLabel.font = .heading_h3
        titleLabel.textColor = .text_5
        titleView.addSubview(titleLabel)
        titleLabel.snp.makeConstraints { make in
            make.leading.equalToSuperview().offset(16)
            make.centerY.equalToSuperview()
        }
        
        return titleView
    }
    
    private func buildRemain() -> UIView {
        let container = UIView()
        container.onTap { [weak self] in
            guard let self else { return }
            endEditing(true)
        }
        container.snp.makeConstraints { make in
            make.height.equalTo(36)
        }
        
        let exchange = UIButton()
        exchange.setTitle(.init(key: "A00265"), for: .normal)
        exchange.setTitleColor(.text_6, for: .normal)
        exchange.titleLabel?.font = .body_xs
        exchange.addAction(UIAction(handler: { [weak self] _ in
            guard let self else { return }
            exchangeInput.text = switch exchangeType {
            case .coinToDiamond: myWalletInfo.coin.toDisplay
            case .diamondToCoin: myWalletInfo.diamond.toDisplay
            case .beanToCoin, .beanToDiamond: myWalletInfo.availableBean.toDisplay
            }
            checkExchangeButton()
        }), for: .touchUpInside)
        container.addSubview(exchange)
        exchange.snp.makeConstraints { make in
            make.centerY.equalToSuperview()
            make.trailing.equalToSuperview().offset(-16)
        }
        
        let currencyIcon: UIImageView = switch exchangeType {
        case .coinToDiamond: .coinImageView()
        case .diamondToCoin: .diamondImageView()
        case .beanToCoin, .beanToDiamond: .beanImageView()
        }
        container.addSubview(currencyIcon)
        currencyIcon.snp.makeConstraints { make in
            make.leading.equalToSuperview().offset(16)
            make.centerY.equalToSuperview()
            make.width.height.equalTo(24)
        }
        
        remainLabel.text = switch exchangeType {
        case .coinToDiamond: myWalletInfo.coin.toDisplay
        case .diamondToCoin: myWalletInfo.diamond.toDisplay
        case .beanToCoin, .beanToDiamond: myWalletInfo.availableBean.toDisplay
        }
        remainLabel.font = .heading_h1
        remainLabel.textColor = .text_5
        container.addSubview(remainLabel)
        remainLabel.snp.makeConstraints { make in
            make.leading.equalTo(currencyIcon.snp.trailing).offset(2)
            make.centerY.equalToSuperview()
        }
        
        return container
    }
    
    private func buildExchangeView() -> UIView {
        let container = UIView()
        container.onTap { [weak self] in
            guard let self else { return }
            endEditing(true)
        }
        container.snp.makeConstraints { make in
            make.height.equalTo(67)
        }
        
        let titleLabel = UILabel()
        titleLabel.text = switch exchangeType {
        case .coinToDiamond: .init(key: "A00266")
        case .diamondToCoin: .init(key: "A00274")
        case .beanToCoin, .beanToDiamond: .init(key: "B00106")
        }
        titleLabel.font = .heading_h4
        titleLabel.textColor = .text_5
        container.addSubview(titleLabel)
        titleLabel.snp.makeConstraints { make in
            make.leading.equalToSuperview().offset(12)
            make.centerY.equalToSuperview()
        }
        
        exchangeInput.font = .heading_h2
        exchangeInput.textColor = .text_5
        exchangeInput.visibleView = exchangeView
        exchangeInput.delegate = self
        exchangeInput.returnKeyType = .done
        exchangeInput.attributedPlaceholder = .init(
            string: .init(key: "A00261"),
            attributes: [.font: UIFont.heading_h3,
                         .foregroundColor: UIColor.text_2])
        exchangeInput.keyboardType = .decimalPad
        exchangeInput.addAction(UIAction(handler: { [weak self] _ in
            guard let self else { return }
            checkExchangeButton()
        }), for: .editingChanged)
        container.addSubview(exchangeInput)
        exchangeInput.snp.makeConstraints { make in
            make.trailing.equalToSuperview().offset(-12)
            make.centerY.equalToSuperview()
        }
        
        let expectIcon: UIImageView = switch exchangeType {
        case .coinToDiamond: .coinImageView()
        case .diamondToCoin: .diamondImageView()
        case .beanToCoin, .beanToDiamond: .beanImageView()
        }
        container.addSubview(expectIcon)
        expectIcon.snp.makeConstraints { make in
            make.trailing.equalTo(exchangeInput.snp.leading).offset(-2)
            make.centerY.equalToSuperview()
            make.width.height.equalTo(20)
        }
        
        return container
    }
    
    private func buildExpectView() -> UIView {
        let container = UIView()
        container.snp.makeConstraints { make in
            make.height.equalTo(67)
        }
        
        let titleLabel = UILabel()
        titleLabel.text = switch exchangeType {
        case .coinToDiamond, .beanToDiamond: .init(key: "A00267")
        case .diamondToCoin, .beanToCoin: .init(key: "A00275")
        }
        titleLabel.font = .heading_h4
        titleLabel.textColor = .text_5
        container.addSubview(titleLabel)
        titleLabel.snp.makeConstraints { make in
            make.leading.equalToSuperview().offset(12)
            make.centerY.equalToSuperview()
        }
        
        expectLabel.text = "0"
        expectLabel.font = .heading_h2
        expectLabel.textColor = .text_5
        container.addSubview(expectLabel)
        expectLabel.snp.makeConstraints { make in
            make.trailing.equalToSuperview().offset(-12)
            make.centerY.equalToSuperview()
        }
        
        let expectIcon: UIImageView = switch exchangeType {
        case .coinToDiamond, .beanToDiamond: .diamondImageView()
        case .diamondToCoin, .beanToCoin: .coinImageView()
        }
        container.addSubview(expectIcon)
        expectIcon.snp.makeConstraints { make in
            make.trailing.equalTo(expectLabel.snp.leading).offset(-2)
            make.centerY.equalToSuperview()
            make.width.height.equalTo(20)
        }
        
        return container
    }
}


