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

import VDSColorTokens

public class TitleLockupModel: MoleculeModelProtocol, ParentMoleculeModelProtocol {
    
    //--------------------------------------------------
    // MARK: - Properties
    //--------------------------------------------------
    
    public static var identifier: String = "titleLockup"
    public var moleculeName: String = TitleLockupModel.identifier
    
    public var eyebrow: LabelModel?
    public var title: LabelModel
    public var subTitle: LabelModel?
    
    public var alignment: Alignment = .left {
        didSet {
            ///Updating the text alignment for all labels
            if let textAlignment = NSTextAlignment(rawValue: alignment.rawValue) {
                eyebrow?.textAlignment = textAlignment
                title.textAlignment = textAlignment
                subTitle?.textAlignment = textAlignment
            }
        }
    }
    
    public var inverted: Bool = false {
        didSet {
            ///Updating the text color
            eyebrow?.textColor = titleColor
            title.textColor = titleColor
            subTitle?.textColor = subTitleColor
        }
    }
    
    private var _backgroundColor: Color?
    public var backgroundColor: Color? {
        get {
            return inverted ? Color(uiColor: VDSColor.backgroundPrimaryDark) : Color(uiColor: VDSColor.backgroundPrimaryLight)
        }
        set {
            _backgroundColor = newValue
        }
    }
    
    public var titleColor: Color? {
        return inverted ? Color(uiColor: VDSColor.elementsPrimaryOndark) : Color(uiColor: VDSColor.elementsPrimaryOnlight)
    }
    
    public var subTitleColor: Color? {
        return inverted ? Color(uiColor: VDSColor.elementsSecondaryOndark) : Color(uiColor: VDSColor.elementsSecondaryOnlight)
    }
    
    public var children: [MoleculeModelProtocol] {
        [eyebrow, title, subTitle].compactMap { (molecule: MoleculeModelProtocol?) in molecule }
    }
    
    //--------------------------------------------------
    // MARK: - Initializer
    //--------------------------------------------------
    
    public init(eyebrow: LabelModel? = nil, title: LabelModel, subTitle: LabelModel? = nil) throws {
        self.eyebrow = eyebrow
        self.title = title
        self.subTitle = subTitle
        updateLabelAttributes()
    }
    
    //--------------------------------------------------
    // MARK: - Enum
    //--------------------------------------------------
    
    public enum Alignment: String, Codable {
        case left
        case center
    }
    
    //--------------------------------------------------
    // MARK: - Styling
    //--------------------------------------------------
    
    /// Returns the default fontStyle for the subtitle, based on the title fontStyle.
    func defaultSubtitleFontStyle() -> Styler.Font {
        switch title.fontStyle {
        case .RegularTitleXLarge, .RegularTitle2XLarge, .RegularFeatureXSmall:
            return .RegularBodyLarge
        case .RegularFeatureSmall, .RegularFeatureMedium:
            return .RegularTitleLarge
        default:
            return .RegularBodySmall
        }
    }
    
    /// Returns the default spacing between the eyebrow and title, based on the title fontStyle.
    func defaultEyebrowTitleSpacing() -> CGFloat {
        switch title.fontStyle {
        case .RegularTitleXLarge, .RegularTitle2XLarge, .RegularFeatureXSmall, .RegularFeatureSmall:
            return Padding.Three
        case .RegularFeatureMedium:
            return subTitle?.fontStyle == .RegularBodyLarge ? Padding.Three : Padding.Four
        default:
            return Padding.Two
        }
    }
    
    /// Returns the default spacing between the title and subTitle, based on the title fontStyle.
    func defaultTitleSubTitleSpacing() -> CGFloat {
        switch title.fontStyle {
        case .RegularTitleXLarge:
            return Padding.Three
        case .RegularTitle2XLarge, .RegularFeatureXSmall, .RegularFeatureSmall:
            return Padding.Four
        case .RegularFeatureMedium:
            return Padding.Five
        default:
            return Padding.Two
        }
    }
    
    //--------------------------------------------------
    // MARK: - Keys
    //--------------------------------------------------
    
    private enum CodingKeys: String, CodingKey {
        case moleculeName
        case backgroundColor
        case eyebrow
        case title
        case subTitle
        case inverted
        case alignment
    }
    
    //--------------------------------------------------
    // MARK: - Codec
    //--------------------------------------------------
    
    required public init(from decoder: Decoder) throws {
        let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
        title = try typeContainer.decodeMolecule(codingKey: .title)
        eyebrow = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .eyebrow)
        subTitle = try typeContainer.decodeMoleculeIfPresent(codingKey: .subTitle)
        
        if let newAlignment = try typeContainer.decodeIfPresent(Alignment.self, forKey: .alignment) {
            alignment = newAlignment
        }
        
        if let invertedStatus = try typeContainer.decodeIfPresent(Bool.self, forKey: .inverted) {
            inverted = invertedStatus
        }
        
        backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
        
        updateLabelAttributes()
    }
    
    public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(moleculeName, forKey: .moleculeName)
        try container.encodeIfPresent(eyebrow, forKey: .eyebrow)
        try container.encodeModel(title, forKey: .title)
        try container.encodeIfPresent(subTitle, forKey: .subTitle)
        try container.encode(alignment, forKey: .alignment)
        try container.encode(inverted, forKey: .inverted)
        try container.encodeIfPresent(_backgroundColor, forKey: .backgroundColor)
    }
    
    //--------------------------------------------------
    // MARK: - Model updates
    //--------------------------------------------------

    private func updateLabelAttributes() {
        // If subtitle style is not available, will set font style based on the component
        if subTitle?.fontStyle == nil {
            subTitle?.fontStyle = defaultSubtitleFontStyle()
        }
        
        // If eyebrow style is not available, will set font style based on the component. Eyebrow and subtitle share the same font size
        if eyebrow?.fontStyle == nil {
            eyebrow?.fontStyle = subTitle?.fontStyle
        }
        
        // Updating the text color
        if eyebrow?.textColor == nil {
            eyebrow?.textColor = subTitleColor
        }
        if title.textColor == nil {
            title.textColor = titleColor
        }
        if subTitle?.textColor == nil {
            subTitle?.textColor = subTitleColor
        }
            
        // Updating the text alignment for all labels
        if let textAlignment = NSTextAlignment(rawValue: alignment.rawValue) {
            if eyebrow?.textAlignment == nil {
                eyebrow?.textAlignment = textAlignment
            }
            if title.textAlignment == nil {
                title.textAlignment = textAlignment
            }
            if subTitle?.textAlignment == nil {
                subTitle?.textAlignment = textAlignment
            }
        }
    }
}
