//
//  VDS-Enums+Codable.swift
//  MVMCoreUI
//
//  Created by Matt Bruce on 1/25/23.
//  Copyright © 2023 Verizon Wireless. All rights reserved.
//

import Foundation
import VDS
import VDSColorTokens

//--------------------------------------------------
// MARK: - Codable Extensions
//--------------------------------------------------

extension VDS.Surface: Codable {}
extension VDS.Badge.FillColor: Codable {}
extension VDS.ButtonGroup.Alignment: Codable {}
extension VDS.Icon.Name: Codable {}
extension VDS.Icon.Size: Codable {}
extension VDS.Tabs.Orientation: Codable {}
extension VDS.Tabs.IndicatorPosition: Codable {}
extension VDS.Tabs.Overflow: Codable {}
extension VDS.Tabs.Size: Codable {}
extension VDS.TextLink.Size: Codable {}
extension VDS.TextLinkCaret.IconPosition: Codable {}
extension VDS.TileContainerBase.AspectRatio: Codable {}
extension VDS.Tilelet.Padding: Codable {}
extension VDS.TitleLockup.TextAlignment: Codable {}
extension VDS.Tooltip.FillColor: Codable {}
extension VDS.Tooltip.Size: Codable {}
extension VDS.Line.Style: Codable {}
extension VDS.Line.Orientation: Codable {}
extension VDS.Use: Codable {}

extension VDS.Button.Size: RawRepresentableCodable {
    public static var mapping: [String : VDS.Button.Size] { ["standard": .large, "tiny": .small] }
    public static var defaultValue: VDS.Button.Size? { nil }
}

//--------------------------------------------------
// MARK: - Decodable Defaults
//--------------------------------------------------
extension DecodableDefault.Sources {
    public struct Surface: DecodableDefaultSource {
        public static var defaultValue: VDS.Surface { .light }
    }
    
    public struct IconSize: DecodableDefaultSource {
        public static var defaultValue: VDS.Icon.Size { .medium }
    }
    
    public struct BlackColor: DecodableDefaultSource {
        public static var defaultValue: Color { .init(uiColor: VDSColor.paletteBlack) }
    }
}

extension DecodableDefault {
    public typealias IconSize = Wrapper<Sources.IconSize>
    public typealias BlackColor = Wrapper<Sources.BlackColor>
    public typealias Surface = Wrapper<Sources.Surface>
}

extension VDS.TileContainerBase.BackgroundColor: Codable {
    public func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch self {
        case .custom(let value):
            try container.encode(value)
        default:
            try container.encode(String(reflecting: self))
        }
    }
    
    // Init from decoder to handle the decoding based on the type
    public init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        let type = try container.decode(String.self)
        switch type {
        case "primary":
            self = .primary
        case "secondary":
            self = .secondary
        case "white":
            self = .white
        case "black":
            self = .black
        default:
            self = .custom(type)
        }
    }
}

extension VDS.TileContainer.Padding: Codable {
    enum PaddingError: Error {
        case valueNotFound(type: String)
    }
    public func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch self {
        case .custom(let value):
            try container.encode(value)
        default:
            try container.encode(String(reflecting: self))
        }
    }
    
    // Init from decoder to handle the decoding based on the type
    public init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        do {
            let type = try container.decode(String.self)
            switch type {
            case "padding2X":
                self = .padding2X
            case "padding4X":
                self = .padding4X
            case "padding6X":
                self = .padding6X
            case "padding8X":
                self = .padding8X
            case "padding12X":
                self = .padding12X
            default:
                throw PaddingError.valueNotFound(type: type)
            }
        } catch PaddingError.valueNotFound(let type) {
            throw PaddingError.valueNotFound(type: type)
        } catch {
            let type = try container.decode(CGFloat.self)
            self = .custom(type)
        }
    }
}
