//
//  TestToggle.swift
//  JSONCreator
//
//  Created by Matt Bruce on 10/21/22.
//  Copyright © 2022 Verizon Wireless. All rights reserved.
//

import Foundation
import MVMCore
import MVMCoreUI
import UIKit
import VDS

/**
 A custom implementation of Apple's UISwitch.
 
 By default this class begins in the off state.
 
 Container: The background of the toggle control.
 Knob: The circular indicator that slides on the container.
 */
open class TestToggle: VDS.Toggle, VDSMoleculeViewProtocol {
    //--------------------------------------------------
    // MARK: - Properties
    //--------------------------------------------------
    public var viewModel: TestToggleModel!
    public var delegateObject: MVMCoreUIDelegateObject?
    public var additionalData: [AnyHashable: Any]?

    //--------------------------------------------------
    // MARK: - Initializers
    //--------------------------------------------------
    public override func initialSetup() {
        super.initialSetup()
        publisher(for: .valueChanged)
            .sink {[weak self] toggle in
                guard let self = self else { return }
                self.valueChanged(isOn: toggle.isOn)
            }.store(in: &subscribers)
    }
    
    // MARK:- MVMCoreViewProtocol
    open func updateView(_ size: CGFloat) {}
    
    override open func updateView() {
        super.updateView()
        
        //accessibility
        accessibilityLabel = MVMCoreUIUtility.hardcodedString(withKey: "Toggle_buttonlabel")
        accessibilityHint = isEnabled ? MVMCoreUIUtility.hardcodedString(withKey: "AccToggleHint") : MVMCoreUIUtility.hardcodedString(withKey: "AccDisabled")
        accessibilityValue = isOn ? MVMCoreUIUtility.hardcodedString(withKey: "AccOn") : MVMCoreUIUtility.hardcodedString(withKey: "AccOff")
    }
    
    open func viewModelDidUpdate() {
        guard let viewModel else { return }
        
        additionalData = additionalData.dictionaryAdding(key: KeySourceModel, value: viewModel)
    }
    
    private func valueChanged(isOn: Bool){
        guard let viewModel else { return }
        //sync the value on the viewModel
        viewModel.selected = isOn
        
        //tell the form you changed
        _ = FormValidator.validate(delegate: self.delegateObject?.formHolderDelegate)

        if viewModel.action != nil || viewModel.alternateAction != nil {
            var action: ActionModelProtocol?
            if isOn {
                action = viewModel.action
            } else {
                action = viewModel.alternateAction ?? viewModel.action
            }
            if let action {
                MVMCoreUIActionHandler.performActionUnstructured(with: action,
                                                                 sourceModel: viewModel,
                                                                 additionalData: additionalData,
                                                                 delegateObject: delegateObject)
            }
        }
        
        print("toggle value changed to: \(isOn)")
        print("viewModel server value: \(viewModel.formFieldServerValue()!)")
    }
    
    public static func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
        return 44
    }
    
    private typealias ActionDefinition = (model: ActionModelProtocol,
                                          sourceModel: MoleculeModelProtocol?)
    
    private func performActionUnstructured(definition: ActionDefinition) {
        MVMCoreUIActionHandler.performActionUnstructured(with: definition.model,
                                                         sourceModel: definition.sourceModel,
                                                         additionalData: additionalData,
                                                         delegateObject: delegateObject)
    }
}
// MARK: - MVMCoreUIViewConstrainingProtocol
extension TestToggle {
    
    public func needsToBeConstrained() -> Bool { true }
    
    public func horizontalAlignment() -> UIStackView.Alignment { .trailing }
}

public class TestToggleModel: MoleculeModelProtocol, FormFieldProtocol {
    //--------------------------------------------------
    // MARK: - Properties
    //--------------------------------------------------
    
    public static var identifier: String = "testToggle"
    public var backgroundColor: Color? //not used
    
    public var selected: Bool = false
    public var enabled: Bool = true
    public var readOnly: Bool = false
    public var action: ActionModelProtocol?
    public var alternateAction: ActionModelProtocol?
    public var accessibilityText: String?
    public var fieldKey: String?
    public var groupName: String = FormValidator.defaultGroupName
    public var baseValue: AnyHashable?

    //--------------------------------------------------
    // MARK: - Keys
    //--------------------------------------------------
    
    private enum CodingKeys: String, CodingKey {
        case moleculeName
        case state
        case enabled
        case readOnly
        case action
        case accessibilityIdentifier
        case alternateAction
        case accessibilityText
        case fieldKey
        case groupName
    }
    
    //--------------------------------------------------
    // MARK: - Form Valdiation
    //--------------------------------------------------
    
    public func formFieldValue() -> AnyHashable? {
        guard enabled else { return nil }
        return selected
    }
    
    //--------------------------------------------------
    // MARK: - Server Value
    //--------------------------------------------------
    open func formFieldServerValue() -> AnyHashable? {
        return formFieldValue()
    }
    
    //--------------------------------------------------
    // MARK: - Initializer
    //--------------------------------------------------
    
    public init(_ state: Bool) {
        selected = state
        baseValue = state
    }
    
    //--------------------------------------------------
    // MARK: - Codec
    //--------------------------------------------------
    
    required public init(from decoder: Decoder) throws {
        let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
        
        if let state = try typeContainer.decodeIfPresent(Bool.self, forKey: .state) {
            selected = state
        }
        action = try typeContainer.decodeModelIfPresent(codingKey: .action)
        alternateAction = try typeContainer.decodeModelIfPresent(codingKey: .alternateAction)
        accessibilityText = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityText)
        baseValue = selected
        fieldKey = try typeContainer.decodeIfPresent(String.self, forKey: .fieldKey)
        if let gName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName) {
            groupName = gName
        }
        enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) ?? true
        readOnly = try typeContainer.decodeIfPresent(Bool.self, forKey: .readOnly) ?? false
        
        
    }
    
    public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
        try container.encodeModelIfPresent(action, forKey: .action)
        try container.encodeModelIfPresent(alternateAction, forKey: .alternateAction)
        try container.encode(moleculeName, forKey: .moleculeName)
        try container.encode(selected, forKey: .state)
        try container.encode(enabled, forKey: .enabled)
        try container.encodeIfPresent(fieldKey, forKey: .fieldKey)
        try container.encodeIfPresent(groupName, forKey: .groupName)
        try container.encode(readOnly, forKey: .readOnly)
    }
}
