//
//  Styler.swift
//  MVMCoreUI
//
//  Created by Kevin Christiano on 4/1/20.
//  Copyright © 2020 Verizon Wireless. All rights reserved.
//

import Foundation
import UIKit


open class Styler {
    
    // MARK:- Font Enum
    public enum Font: String, Codable {
        case RegularFeatureXLarge
        case BoldFeatureXLarge
        case RegularFeatureLarge
        case BoldFeatureLarge
        case RegularFeatureMedium
        case BoldFeatureMedium
        case RegularFeatureSmall
        case BoldFeatureSmall
        case RegularFeatureXSmall
        case BoldFeatureXSmall
        
        case RegularTitle2XLarge
        case BoldTitle2XLarge
        case RegularTitleXLarge
        case BoldTitleXLarge
        case RegularTitleLarge
        case BoldTitleLarge
        case RegularTitleMedium
        case BoldTitleMedium
        case RegularTitleSmall
        case BoldTitleSmall
        
        case RegularBodyLarge
        case BoldBodyLarge
        case RegularBodyMedium
        case BoldBodyMedium
        case RegularBodySmall
        case BoldBodySmall
        case RegularMicro
        case BoldMicro
        
        // Legacy Fonts
        case Title2XLarge // Maps to RegularTitle2XLarge
        case TitleXLarge // Maps to RegularTitleXLarge
        case H1 // Maps to RegularTitle2XLarge
        case H32 // Maps to RegularTitleXLarge
        case H2 // Maps to RegularTitleLarge
        case B20 // Maps to RegularBodyLarge
        case H3 // Maps to BoldTitleMedium
        case B1 // Maps to BoldBodySmall
        case B2 // Maps to RegularBodySmall
        case B3 // Maps to RegularMicro
        
        /// Returns the font size of the current enum case.
        public func pointSize() -> CGFloat {
            switch self {
            case .RegularFeatureXLarge,
                 .BoldFeatureXLarge:
                return 96
            case .RegularFeatureLarge,
                 .BoldFeatureLarge:
                return 80
            case .RegularFeatureMedium,
                 .BoldFeatureMedium:
                return 64
            case .RegularFeatureSmall,
                 .BoldFeatureSmall:
                return 48
            case .RegularFeatureXSmall,
                 .BoldFeatureXSmall,
                 .RegularTitle2XLarge,
                 .BoldTitle2XLarge,
                 .Title2XLarge,
                 .H1:
                return 40
            case .RegularTitleXLarge,
                 .BoldTitleXLarge,
                 .TitleXLarge,
                 .H32:
                return 32
            case .BoldTitleLarge,
                 .RegularTitleLarge,
                 .H2:
                return 24
            case .BoldTitleMedium,
                 .RegularTitleMedium,
                 .H3:
                return 20
            case .RegularTitleSmall,
                 .BoldTitleSmall,
                 .BoldBodyLarge,
                 .RegularBodyLarge,
                 .B20:
                return 16
            case .RegularBodyMedium,
                 .BoldBodyMedium:
                return 14
            case .BoldBodySmall, .B1,
                 .RegularBodySmall, .B2:
                return 12
            case .BoldMicro,
                 .RegularMicro, .B3:
                return 11
            }
        }
        
        public func color() -> UIColor {
            switch self {
            case .B3:
                return .mvmCoolGray6
                
            default:
                return .mvmBlack
            }
        }
        
        /// Determines if the selected font case is bold or regular.
        public func isBold() -> Bool {
            
            switch self {
            case .BoldFeatureXLarge,
                 .BoldFeatureLarge,
                 .BoldFeatureMedium,
                 .BoldFeatureSmall,
                 .BoldFeatureXSmall,
                 .BoldTitle2XLarge,
                 .BoldTitleXLarge,
                 .BoldTitleLarge,
                 .BoldTitleMedium,
                 .BoldTitleSmall,
                 .BoldBodyLarge,
                 .BoldBodyMedium,
                 .BoldBodySmall,
                 .H3,
                 .B1,
                 .BoldMicro:
                return true
            default:
                return false
            }
        }
       
        /// Returns the font based on the declared enum case.
        public func getFont(_ genericScaling: Bool = true) -> UIFont {
            let size = genericScaling ? sizeFontGeneric(forCurrentDevice: pointSize()) : pointSize()
            return MFStyler.getFontFor(size: size, isBold: isBold())
        }
        
        /// Styles the provided label to the declared enum Font case.
        public func styleLabel(_ label: UILabel, genericScaling: Bool = true) {
            label.font = getFont(genericScaling)
            label.textColor = color()
        }
    }
    
    public enum Button {
        
        public enum Style: String, Codable {
            case primary
            case secondary
        }
        ///MVA 3.0 - Button sizes are standard(default size), small, Tiny. Tiny button has been depricated as of Rebranding 3.0.
        public enum Size: String, Codable {
            case standard
            case small
            case tiny
            
            func getHeight() -> CGFloat {
                switch self {
                case .standard:
                    return 44
                case .small:
                    return 32
                case .tiny:
                    return 20
                }
            }
            
            func minimumWidth() -> CGFloat {
                switch self {
                case .standard:
                    return 76
                case .small:
                    return 0
                case .tiny:
                    return 49
                }
            }
        }
    }
    
    //--------------------------------------------------
    // MARK: - Functions
    //--------------------------------------------------
    
    open class func sizeObjectGeneric(forCurrentDevice size: CGFloat) -> MFSizeObject? {
        
        let sizeObject = MFSizeObject(standardSize: size, standardiPadPortraitSize: size * 1.3)
        sizeObject?.addLargerThanCustomSize(size * 1.4, forThreshold: MFSizeStandardiPadLandscapeThreshold)
        sizeObject?.addLargerThanCustomSize(size * 1.5, forThreshold: MFSizeiPadProLandscapeThreshold)
        
        return sizeObject
    }
    
    open class func sizeFontGeneric(forCurrentDevice size: CGFloat) -> CGFloat {
        sizeObjectGeneric(forCurrentDevice: size)?.getValueBasedOnApplicationWidth() ?? size
    }
    
    /// Provide additional size information to help calculate its intrinsic height.
    /// - Returns: The available spacing that can be used for intrinsic content width.
    open class func maxAvailableLayoutWidth(size: CGFloat) -> CGFloat {
        // The 2 is the product of both sides of padding.
        size - (Padding.Component.horizontalPaddingForSize(size) * 2)
    }
    
    //--------------------------------------------------
    // MARK: - Spacing
    //--------------------------------------------------
    
    open class func setDefaultMarginsFor(_ view: UIView?, size: CGFloat?, horizontal: Bool = true, vertical: Bool = false) {
        
        var horizontalPadding: CGFloat = Padding.Component.HorizontalMarginSpacing
        let verticalPadding: CGFloat = vertical ? Padding.Component.VerticalMarginSpacing : 0
        
        if let size = size {
            horizontalPadding = horizontal ? Padding.Component.horizontalPaddingForSize(size) : 0
        }
        
        DispatchQueue.main.async {
            MVMCoreUIUtility.setMarginsFor(view,
                                           leading: horizontalPadding,
                                           top: verticalPadding,
                                           trailing: horizontalPadding,
                                           bottom: verticalPadding)
        }
    }
    
    open class func setMarginsFor(_ view: UIView?, size: CGFloat, horizontal: CGFloat?, top: CGFloat, bottom: CGFloat) {
        
        let horizontalPadding: CGFloat = horizontal ?? Padding.Component.horizontalPaddingForSize(size)
        
        DispatchQueue.main.async {
            MVMCoreUIUtility.setMarginsFor(view,
                                           leading: horizontalPadding,
                                           top: top,
                                           trailing: horizontalPadding,
                                           bottom: bottom)
        }
    }
}

@objc public extension MFStyler {
    /// Creates the appropriate VZW font for a given size and weight.
    @objc static func getFontFor(size: CGFloat, isBold: Bool) -> UIFont {
        if isBold {
            return size >= 13 ? MFFonts.mfFontDSBold(size) : MFFonts.mfFontTXBold(size)
        } else {
            return size >= 13 ? MFFonts.mfFontDSRegular(size) : MFFonts.mfFontTXRegular(size)
        }
    }
    
    /// Creates the appropriate VZW font for a VDS style.
    @objc static func getFontFor(styleString: String, genericScaling: Bool = true) -> UIFont? {
        return Styler.Font(rawValue: styleString)?.getFont(genericScaling)
    }
    
    /// Creates the appropriate VZW font for a VDS style, scaling based on the scaleValue threshold passed in.
    @objc static func getFontFor(styleString: String, scaleValue: CGFloat) -> UIFont? {
        guard let font = Styler.Font(rawValue: styleString),
              let size = Styler.Font(rawValue: styleString)?.pointSize(),
              let newSize = Styler.sizeObjectGeneric(forCurrentDevice: size)?.getValueBased(onSize: scaleValue) else { return nil }
        return getFontFor(size: newSize, isBold: font.isBold())
    }
    
    /// Styles the label accordingly to Styler.Font
    @objc static func style(label: UILabel, styleString: String, genericScaling: Bool = true) {
        Styler.Font(rawValue: styleString)?.styleLabel(label, genericScaling: genericScaling)
    }
    
    /// Returns an attributed string with the passed in VDS Style.
    @objc static func getAttributedString(for string: String, styleString: String, genericScaling: Bool = true) -> NSAttributedString {
        let font = Styler.Font(rawValue: styleString)!
        return styleGetAttributedString(string, font: font.getFont(genericScaling), color: font.color())
    }
}
