//
//  NavigationItemModelProtocol.swift
//  MVMCoreUI
//
//  Created by Scott Pfeil on 3/12/20.
//  Copyright © 2020 Verizon Wireless. All rights reserved.
//

import VDSColorTokens

public enum NavigationItemStyle: String, Codable {
    case light
    case dark
}

open class NavigationItemModel: NavigationItemModelProtocol, MoleculeModelProtocol {
    //--------------------------------------------------
    // MARK: - Properties
    //--------------------------------------------------
    
    open class var identifier: String { "navigationBar" }
    
    private let defaultHidesSystemBackButton = true
    
    open var title: String?
    open var hidden = false
    open var line: LineModel? = LineModel(type: .secondary)
    open var hidesSystemBackButton = true
    open var style: NavigationItemStyle?

    private var _backgroundColor: Color?
    open var backgroundColor: Color? {
        get {
            if let backgroundColor = _backgroundColor { return backgroundColor }
            if let style = style,
               style == .dark { return Color(uiColor: VDSColor.backgroundPrimaryDark) }
            return Color(uiColor: VDSColor.backgroundPrimaryLight)
        }
        set {
            _backgroundColor = newValue
        }
    }

    private var _tintColor: Color?
    open var tintColor: Color {
        get {
            if let tintColor = _tintColor { return tintColor }
            if let style = style,
                style == .dark { return Color(uiColor: VDSColor.elementsPrimaryOndark) }
            return Color(uiColor: VDSColor.elementsPrimaryOnlight)
        }
        set {
            _tintColor = newValue
        }
    }
    
    /// If true, we add the button in the backButton property. If false we do not add the button. If nil, we add the button if the controller is not the bottom of the stack
    open var alwaysShowBackButton: Bool?
    open var backButton: (NavigationButtonModelProtocol & MoleculeModelProtocol)?
    
    open var additionalLeftButtons: [(NavigationButtonModelProtocol & MoleculeModelProtocol)]?
    open var additionalRightButtons: [(NavigationButtonModelProtocol & MoleculeModelProtocol)]?
    open var titleView: MoleculeModelProtocol?
    open var titleOffset: UIOffset? = UIOffset(horizontal: -CGFloat.greatestFiniteMagnitude, vertical: 0)
    
    //--------------------------------------------------
    // MARK: - Initializer
    //--------------------------------------------------
    
    public init() {}
    
    //--------------------------------------------------
    // MARK: - Keys
    //--------------------------------------------------
    
    private enum CodingKeys: String, CodingKey {
        case moleculeName
        case title
        case hidden
        case backgroundColor
        case tintColor
        case line
        case hidesSystemBackButton
        case alwaysShowBackButton
        case backButton
        case additionalLeftButtons
        case additionalRightButtons
        case titleView
        case style
        case titleOffset
    }
    
    //--------------------------------------------------
    // MARK: - Codec
    //--------------------------------------------------
    
    required public init(from decoder: Decoder) throws {
        let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
        title = try typeContainer.decodeIfPresent(String.self, forKey: .title)
        if let hidden = try typeContainer.decodeIfPresent(Bool.self, forKey: .hidden) {
            self.hidden = hidden
        }
        backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
        _tintColor = try typeContainer.decodeIfPresent(Color.self, forKey: .tintColor)
        if let line = try typeContainer.decodeIfPresent(LineModel.self, forKey: .line) {
            self.line = line
        }
        if let hidesSystemBackButton = try typeContainer.decodeIfPresent(Bool.self, forKey: .hidesSystemBackButton) {
            self.hidesSystemBackButton = hidesSystemBackButton
        }
        alwaysShowBackButton = try typeContainer.decodeIfPresent(Bool.self, forKey: .alwaysShowBackButton)
        backButton = try typeContainer.decodeModelIfPresent(codingKey: .backButton)
        additionalLeftButtons = try typeContainer.decodeModelsIfPresent(codingKey: .additionalLeftButtons)
        additionalRightButtons = try typeContainer.decodeModelsIfPresent(codingKey: .additionalRightButtons)
        titleView = try typeContainer.decodeModelIfPresent(codingKey: .titleView)
        style = try typeContainer.decodeIfPresent(NavigationItemStyle.self, forKey: .style)
        if let titleOffset = try typeContainer.decodeIfPresent(UIOffset.self, forKey: .titleOffset) {
            self.titleOffset = titleOffset
        }
        line?.inverted = style == .dark
    }
              
    open func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(moleculeName, forKey: .moleculeName)
        try container.encodeIfPresent(title, forKey: .title)
        try container.encode(hidden, forKey: .hidden)
        try container.encodeIfPresent(_backgroundColor, forKey: .backgroundColor)
        try container.encodeIfPresent(_tintColor, forKey: .tintColor)
        try container.encodeIfPresent(line, forKey: .line)
        try container.encode(hidesSystemBackButton, forKey: .hidesSystemBackButton)
        try container.encodeIfPresent(alwaysShowBackButton, forKey: .alwaysShowBackButton)
        try container.encodeModelIfPresent(backButton, forKey: .backButton)
        try container.encodeModelsIfPresent(additionalLeftButtons, forKey: .additionalLeftButtons)
        try container.encodeModelsIfPresent(additionalRightButtons, forKey: .additionalRightButtons)
        try container.encodeModelIfPresent(titleView, forKey: .titleView)
        try container.encodeIfPresent(style, forKey: .style)
        try container.encodeIfPresent(titleOffset, forKey: .titleOffset)
    }
}

extension NavigationItemModel: ParentMoleculeModelProtocol {
    public var children: [MoleculeModelProtocol] {
        var children: [MoleculeModelProtocol] = [line, titleView, backButton].compactMap { $0 }
        if let leftButtons = additionalLeftButtons {
            children.append(contentsOf: leftButtons)
        }
        if let rightButtons = additionalRightButtons {
            children.append(contentsOf: rightButtons)
        }
        return children
    }
}
