//
//  TransactionAmountTextFieldStore.swift
//  secant-testnet
//
//  Created by Adam Stener on 4/5/22.
//

import ComposableArchitecture
import ZcashLightClientKit
import Foundation
import Utils
import NumberFormatter

public typealias TransactionAmountTextFieldStore = Store<TransactionAmountTextFieldReducer.State, TransactionAmountTextFieldReducer.Action>

public struct TransactionAmountTextFieldReducer: Reducer {
    public struct State: Equatable {
        public var amount = RedactableInt64(0)
        public var currencySelectionState: CurrencySelectionReducer.State
        public var maxValue = RedactableInt64(0)
        public var textFieldState: TCATextFieldReducer.State
        // TODO: [#311] - Get the ZEC price from the SDK, https://github.com/Electric-Coin-Company/zashi-ios/issues/311
        public var zecPrice = Decimal(140.0)
        
        public var isValidInput: Bool {
            if !_XCTIsTesting {
                @Dependency(\.numberFormatter) var numberFormatter
                
                return numberFormatter.number(textFieldState.text.data) != nil
            } else {
                return true
            }
        }

        public var isMax: Bool {
            return amount == maxValue
        }
        
        public init(
            amount: RedactableInt64 = RedactableInt64(0),
            currencySelectionState: CurrencySelectionReducer.State,
            maxValue: RedactableInt64 = RedactableInt64(0),
            textFieldState: TCATextFieldReducer.State,
            zecPrice: Decimal = Decimal(140.0)
        ) {
            self.amount = amount
            self.currencySelectionState = currencySelectionState
            self.maxValue = maxValue
            self.textFieldState = textFieldState
            self.zecPrice = zecPrice
        }
    }

    public enum Action: Equatable {
        case clearValue
        case currencySelection(CurrencySelectionReducer.Action)
        case setMax
        case textField(TCATextFieldReducer.Action)
        case updateAmount
    }
    
    @Dependency(\.numberFormatter) var numberFormatter
    
    public init() {}
    
    public var body: some Reducer<State, Action> {
        Scope(state: \.currencySelectionState, action: /Action.currencySelection) {
            CurrencySelectionReducer()
        }

        Scope(state: \.textFieldState, action: /Action.textField) {
            TCATextFieldReducer()
        }

        Reduce { state, action in
            switch action {
            case .setMax:
                let maxValueAsZec = Decimal(state.maxValue.data) / Decimal(Zatoshi.Constants.oneZecInZatoshi)
                let currencyType = state.currencySelectionState.currencyType
                let maxCurrencyConvertedValue: NSDecimalNumber = currencyType == .zec ?
                NSDecimalNumber(decimal: maxValueAsZec).roundedZec :
                NSDecimalNumber(decimal: maxValueAsZec * state.zecPrice).roundedZec
                
                let decimalString = numberFormatter.string(maxCurrencyConvertedValue) ?? ""
                
                state.textFieldState.text = "\(decimalString)".redacted
                return Effect.send(.updateAmount)

            case .clearValue:
                state.textFieldState.text = "".redacted
                return .none

            case .textField(.set):
                return Effect.send(.updateAmount)
                
            case .updateAmount:
                guard let number = numberFormatter.number(state.textFieldState.text.data) else {
                    state.amount = Int64(0).redacted
                    return .none
                }
                switch state.currencySelectionState.currencyType {
                case .zec:
                    state.amount = NSDecimalNumber(
                        decimal: number.decimalValue * Decimal(Zatoshi.Constants.oneZecInZatoshi)
                    ).roundedZec.int64Value.redacted
                case .usd:
                    let decimal = (number.decimalValue / state.zecPrice) * Decimal(Zatoshi.Constants.oneZecInZatoshi)
                    state.amount = NSDecimalNumber(decimal: decimal).roundedZec.int64Value.redacted
                }
                return .none
                
            case .currencySelection:
                guard let number = numberFormatter.number(state.textFieldState.text.data) else {
                    state.amount = Int64(0).redacted
                    return .none
                }
                
                let currencyType = state.currencySelectionState.currencyType
                
                let newValue = currencyType == .zec ?
                number.decimalValue / state.zecPrice :
                number.decimalValue * state.zecPrice
                
                let decimalString = numberFormatter.string(NSDecimalNumber(decimal: newValue)) ?? ""
                state.textFieldState.text = "\(decimalString)".redacted
                return Effect.send(.updateAmount)
            }
        }
    }
}

// MARK: - Placeholders

extension TransactionAmountTextFieldReducer.State {
    public static let initial = TransactionAmountTextFieldReducer.State(
        currencySelectionState: CurrencySelectionReducer.State(),
        textFieldState: .initial
    )

    public static let amount = TransactionAmountTextFieldReducer.State(
        currencySelectionState: CurrencySelectionReducer.State(),
        textFieldState: .amount
    )
}

extension TransactionAmountTextFieldStore {
    public static let placeholder = TransactionAmountTextFieldStore(
        initialState: .initial
    ) {
        TransactionAmountTextFieldReducer()
    }
}
