//
//  TitleLockupModel.swift
//  MVMCoreUI
//
//  Created by Nadigadda, Sumanth on 04/05/22.
//  Copyright © 2022 Verizon Wireless. All rights reserved.
//

import VDSTokens
import VDS

public class TitleLockupModel: MoleculeModelProtocol, ParentMoleculeModelProtocol {
    
    //--------------------------------------------------
    // MARK: - Properties
    //--------------------------------------------------
    
    public static var identifier: String = "titleLockup"
    public var moleculeName: String = TitleLockupModel.identifier
    public var id: String = UUID().uuidString
    
    public var textAlignment: TitleLockup.TextAlignment = .left
    public var eyebrow: LabelModel?
    public var title: LabelModel
    public var subTitle: LabelModel?
    public var subTitleColor: Use = .primary
    
    public var alignment: VDS.TitleLockup.TextAlignment = .left
    public var inverted: Bool = false
    
    public var backgroundColor: Color?
    
    public var children: [MoleculeModelProtocol] {
        [eyebrow, title, subTitle].compactMap { (molecule: MoleculeModelProtocol?) in molecule }
    }
    
    public func replaceChildMolecule(with molecule: MoleculeModelProtocol) throws -> Bool  {
        return try replaceChildMolecule(at: &eyebrow, with: molecule)
        || replaceChildMolecule(at: &title, with: molecule)
        || replaceChildMolecule(at: &subTitle, with: molecule)
    }
    
    //--------------------------------------------------
    // MARK: - Initializer
    //--------------------------------------------------
    
    public init(eyebrow: LabelModel? = nil, title: LabelModel, subTitle: LabelModel? = nil) {
        self.eyebrow = eyebrow
        self.title = title
        self.subTitle = subTitle
    }
    
    //--------------------------------------------------
    // MARK: - Keys
    //--------------------------------------------------
    
    private enum CodingKeys: String, CodingKey {
        case id
        case moleculeName
        case textAlignment
        case eyebrow
        case title
        case subTitle
        case subTitleColor
        case inverted
        case alignment
    }
    
    //--------------------------------------------------
    // MARK: - Codec
    //--------------------------------------------------
    
    required public init(from decoder: Decoder) throws {
        let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
        id = try typeContainer.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString
        textAlignment = try typeContainer.decodeIfPresent(TitleLockup.TextAlignment.self, forKey: .textAlignment) ?? .left
        title = try typeContainer.decodeMolecule(codingKey: .title)
        eyebrow = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .eyebrow)
        subTitle = try typeContainer.decodeMoleculeIfPresent(codingKey: .subTitle)

        /// look for color hex code
        if let color = try? typeContainer.decodeIfPresent(Color.self, forKey: .subTitleColor) {
            self.subTitleColor = color.uiColor.isDark() ? .primary : .secondary
        
        } else if let subTitleColor = try? typeContainer.decodeIfPresent(Use.self, forKey: .subTitleColor) {
            self.subTitleColor = subTitleColor
            
        } else {
            subTitleColor = .primary
        }

        if let newAlignment = try typeContainer.decodeIfPresent(VDS.TitleLockup.TextAlignment.self, forKey: .alignment) {
            alignment = newAlignment
        }
        
        if let inverted = try typeContainer.decodeIfPresent(Bool.self, forKey: .inverted) {
            self.inverted = inverted
        } else {
            try setInverted(deprecatedFrom: decoder)
        }

    }
        
    public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(id, forKey: .id)
        try container.encode(moleculeName, forKey: .moleculeName)
        try container.encode(textAlignment, forKey: .textAlignment)
        try container.encodeIfPresent(eyebrow, forKey: .eyebrow)
        try container.encodeModel(title, forKey: .title)
        try container.encodeIfPresent(subTitle, forKey: .subTitle)
        try container.encode(subTitleColor, forKey: .subTitleColor)
        try container.encode(alignment, forKey: .alignment)
        try container.encode(inverted, forKey: .inverted)
    }
    
    public func eyebrowModel(delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> VDS.TitleLockup.EyebrowModel? {
        guard let eyebrow else { return nil }
        let attrs = eyebrow.attributes?.toVDSLabelAttributeModel(delegateObject: delegateObject, additionalData: additionalData)
        do {
            if let style = eyebrow.fontStyle {
                return .init(text: eyebrow.text,
                             isBold: style.isBold(),
                             standardStyle: try style.vdsSubsetStyle(),
                             textAttributes: attrs,
                             numberOfLines: eyebrow.numberOfLines ?? 0)
            }
        } catch MVMCoreError.errorObject(let object) {
            MVMCoreLoggingHandler.shared()?.addError(toLog: object)
        } catch { }
        
        return .init(text: eyebrow.text, textAttributes: attrs, numberOfLines: eyebrow.numberOfLines ?? 0)
    }
    
    public func titleModel(delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> VDS.TitleLockup.TitleModel {
        let attrs = title.attributes?.toVDSLabelAttributeModel(delegateObject: delegateObject, additionalData: additionalData)
        do {
            if let style = title.fontStyle {
                return .init(text: title.text,
                             textAttributes: attrs,
                             isBold: style.isBold(),
                             standardStyle: try style.vdsSubsetStyle(),
                             numberOfLines: title.numberOfLines ?? 0)
            }

        } catch MVMCoreError.errorObject(let object) {
            MVMCoreLoggingHandler.shared()?.addError(toLog: object)
        } catch { }
        
        return .init(text: title.text, textAttributes: attrs, numberOfLines: title.numberOfLines ?? 0)
    }

    public func subTitleModel(delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> VDS.TitleLockup.SubTitleModel? {
        guard let subTitle else { return nil }
        let attrs = subTitle.attributes?.toVDSLabelAttributeModel(delegateObject: delegateObject, additionalData: additionalData)
        
        do {
            if let style = subTitle.fontStyle {
                return .init(text: subTitle.text,
                             otherStandardStyle: try style.vdsSubsetStyle(),
                             textColor: subTitleColor,
                             textAttributes: attrs,
                             numberOfLines: subTitle.numberOfLines ?? 0)
            }
        } catch MVMCoreError.errorObject(let object) {
            MVMCoreLoggingHandler.shared()?.addError(toLog: object)
        } catch { }
        
        return .init(text: subTitle.text, textColor: subTitleColor, textAttributes: attrs, numberOfLines: subTitle.numberOfLines ?? 0)
        
    }
    
    private enum DeprecatedCodingKeys: String, CodingKey {
        case titleColor
        case backgroundColor
    }
    
    private func setInverted(deprecatedFrom decoder: Decoder) throws {
        let typeContainer = try decoder.container(keyedBy: DeprecatedCodingKeys.self)
        
        if let titleColor = try typeContainer.decodeIfPresent(Color.self, forKey: .titleColor) {
            inverted = !titleColor.uiColor.isDark()
        }
    
        if let backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) {
            inverted = !backgroundColor.uiColor.isDark()
        }
    }

}

extension TitleLockupModel {
    public var surface: Surface { inverted ? .dark : .light }
}
