import Foundation

public struct WizardOption: Sendable {
    public let value: AnyCodable?
    public let label: String
    public let hint: String?

    public init(value: AnyCodable?, label: String, hint: String?) {
        self.value = value
        self.label = label
        self.hint = hint
    }
}

public struct WizardDeviceCodePresentation: Sendable {
    public let code: String
    public let expiresInMinutes: Int?
    public let message: String?
}

public func parseWizardDeviceCode(
    _ raw: [String: AnyCodable]?) -> WizardDeviceCodePresentation?
{
    guard let code = raw?["code"]?.value as? String, !code.isEmpty else { return nil }
    let allowedMinutes = 1...1440
    let expiresInMinutes: Int? = switch raw?["expiresInMinutes"]?.value {
    case let value as Int where allowedMinutes.contains(value): value
    case let value as Double:
        if let exact = Int(exactly: value), allowedMinutes.contains(exact) {
            exact
        } else {
            nil
        }
    default: nil
    }
    return WizardDeviceCodePresentation(
        code: code,
        expiresInMinutes: expiresInMinutes,
        message: raw?["message"]?.value as? String)
}

public func parseWizardOptions(_ raw: [[String: AnyCodable]]?) -> [WizardOption] {
    guard let raw else { return [] }
    return raw.map { entry in
        let value = entry["value"]
        let label = (entry["label"]?.value as? String) ?? ""
        let hint = entry["hint"]?.value as? String
        return WizardOption(value: value, label: label, hint: hint)
    }
}

public func wizardStatusString(_ value: AnyCodable?) -> String? {
    (value?.value as? String)?.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()
}

public func wizardStepType(_ step: WizardStep) -> String {
    (step.type.value as? String) ?? ""
}

public func anyCodableString(_ value: AnyCodable?) -> String {
    switch value?.value {
    case let string as String:
        string
    case let int as Int:
        String(int)
    case let double as Double:
        String(double)
    case let bool as Bool:
        bool ? "true" : "false"
    default:
        ""
    }
}

public func anyCodableBool(_ value: AnyCodable?) -> Bool {
    switch value?.value {
    case let bool as Bool:
        return bool
    case let int as Int:
        return int != 0
    case let double as Double:
        return double != 0
    case let string as String:
        let trimmed = string.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()
        return trimmed == "true" || trimmed == "1" || trimmed == "yes"
    default:
        return false
    }
}

public func anyCodableArray(_ value: AnyCodable?) -> [AnyCodable] {
    switch value?.value {
    case let arr as [AnyCodable]:
        arr
    case let arr as [Any]:
        arr.map { AnyCodable($0) }
    default:
        []
    }
}

public func anyCodableEqual(_ lhs: AnyCodable?, _ rhs: AnyCodable?) -> Bool {
    switch (lhs?.value, rhs?.value) {
    case let (l as String, r as String):
        l == r
    case let (l as Int, r as Int):
        l == r
    case let (l as Double, r as Double):
        l == r
    case let (l as Bool, r as Bool):
        l == r
    case let (l as String, r as Int):
        l == String(r)
    case let (l as Int, r as String):
        String(l) == r
    case let (l as String, r as Double):
        l == String(r)
    case let (l as Double, r as String):
        String(l) == r
    default:
        false
    }
}
