import SwiftUI

/// Card theme configuration supporting both preset themes and custom colors.
///
/// Themes are stored as strings in the format:
/// - Preset themes: "Coral", "Midnight", etc.
/// - Custom themes: "custom:R,G,B" where R, G, B are 0.0-1.0 values
struct CardTheme: Identifiable, Hashable, Sendable {
    let name: String
    private let customRGB: (Double, Double, Double)?
    
    var id: String { name }
    
    // MARK: - Preset Themes
    
    static let coral = CardTheme(preset: .coral)
    static let midnight = CardTheme(preset: .midnight)
    static let ocean = CardTheme(preset: .ocean)
    static let lime = CardTheme(preset: .lime)
    static let violet = CardTheme(preset: .violet)
    static let forest = CardTheme(preset: .forest)
    static let rose = CardTheme(preset: .rose)
    static let slate = CardTheme(preset: .slate)
    static let amber = CardTheme(preset: .amber)
    static let plum = CardTheme(preset: .plum)
    
    /// All preset themes (excludes custom)
    static var all: [CardTheme] {
        Preset.allCases.map { CardTheme(preset: $0) }
    }
    
    // MARK: - Initialization
    
    private init(preset: Preset) {
        self.name = preset.rawValue
        self.customRGB = nil
    }
    
    /// Creates a custom theme with the specified RGB values (0.0-1.0 range)
    init(customRed: Double, customGreen: Double, customBlue: Double) {
        self.name = String(format: "custom:%.3f,%.3f,%.3f", customRed, customGreen, customBlue)
        self.customRGB = (customRed, customGreen, customBlue)
    }
    
    /// Creates a theme from a stored name string
    init(named themeName: String) {
        if themeName.hasPrefix("custom:") {
            let values = themeName.dropFirst(7).split(separator: ",")
            if values.count == 3,
               let r = Double(values[0]),
               let g = Double(values[1]),
               let b = Double(values[2]) {
                self.name = themeName
                self.customRGB = (r, g, b)
            } else {
                // Fallback to coral if parsing fails
                self.name = Preset.coral.rawValue
                self.customRGB = nil
            }
        } else if Preset(rawValue: themeName) != nil {
            self.name = themeName
            self.customRGB = nil
        } else {
            // Fallback to coral for unknown themes
            self.name = Preset.coral.rawValue
            self.customRGB = nil
        }
    }
    
    // MARK: - Properties
    
    var isCustom: Bool { customRGB != nil }
    
    var localizedName: String {
        if isCustom {
            return String.localized("Custom")
        }
        return String.localized(name)
    }
    
    private var preset: Preset? {
        Preset(rawValue: name)
    }
    
    // MARK: - Theme Brightness
    
    /// Whether this theme requires dark text for proper contrast.
    var requiresDarkText: Bool {
        if let rgb = customRGB {
            // Calculate perceived luminance for custom colors
            let luminance = 0.299 * rgb.0 + 0.587 * rgb.1 + 0.114 * rgb.2
            return luminance > 0.5
        }
        guard let preset else { return false }
        switch preset {
        case .lime, .amber, .rose:
            return true
        case .coral, .midnight, .ocean, .violet, .forest, .slate, .plum:
            return false
        }
    }
    
    // MARK: - RGB Values
    
    private var primaryRGB: (Double, Double, Double) {
        if let rgb = customRGB { return rgb }
        guard let preset else { return (0.95, 0.35, 0.33) }
        switch preset {
        case .coral: return (0.95, 0.35, 0.33)
        case .midnight: return (0.12, 0.16, 0.22)
        case .ocean: return (0.08, 0.45, 0.56)
        case .lime: return (0.73, 0.82, 0.34)
        case .violet: return (0.42, 0.36, 0.62)
        case .forest: return (0.13, 0.37, 0.31)
        case .rose: return (0.95, 0.68, 0.73)
        case .slate: return (0.38, 0.44, 0.50)
        case .amber: return (0.98, 0.75, 0.28)
        case .plum: return (0.56, 0.27, 0.52)
        }
    }
    
    private var secondaryRGB: (Double, Double, Double) {
        if let rgb = customRGB {
            // Calculate luminance to determine if we should lighten or darken
            let luminance = 0.299 * rgb.0 + 0.587 * rgb.1 + 0.114 * rgb.2
            
            if luminance < 0.3 {
                // Dark color: lighten uniformly to avoid color shifts
                let lightenAmount = 0.15
                return (
                    min(1.0, rgb.0 + lightenAmount),
                    min(1.0, rgb.1 + lightenAmount),
                    min(1.0, rgb.2 + lightenAmount)
                )
            } else {
                // Light color: darken uniformly
                let darkenAmount = 0.12
                return (
                    max(0.0, rgb.0 - darkenAmount),
                    max(0.0, rgb.1 - darkenAmount),
                    max(0.0, rgb.2 - darkenAmount)
                )
            }
        }
        guard let preset else { return (0.93, 0.83, 0.68) }
        switch preset {
        case .coral: return (0.93, 0.83, 0.68)
        case .midnight: return (0.29, 0.33, 0.4)
        case .ocean: return (0.2, 0.65, 0.55)
        case .lime: return (0.93, 0.83, 0.68)
        case .violet: return (0.29, 0.33, 0.4)
        case .forest: return (0.22, 0.52, 0.42)
        case .rose: return (0.98, 0.85, 0.88)
        case .slate: return (0.52, 0.58, 0.64)
        case .amber: return (0.99, 0.88, 0.55)
        case .plum: return (0.72, 0.45, 0.68)
        }
    }
    
    private var accentRGB: (Double, Double, Double) {
        if customRGB != nil {
            // For custom colors, use a contrasting accent (gold or dark)
            return requiresDarkText ? (0.12, 0.12, 0.14) : (0.95, 0.75, 0.25)
        }
        guard let preset else { return (0.95, 0.33, 0.28) }
        switch preset {
        case .coral: return (0.95, 0.33, 0.28)
        case .midnight: return (0.95, 0.75, 0.25)
        case .ocean: return (0.95, 0.75, 0.25)
        case .lime: return (0.12, 0.12, 0.14)
        case .violet: return (0.95, 0.75, 0.25)
        case .forest: return (0.95, 0.75, 0.25)
        case .rose: return (0.75, 0.25, 0.35)
        case .slate: return (0.95, 0.75, 0.25)
        case .amber: return (0.12, 0.12, 0.14)
        case .plum: return (0.95, 0.75, 0.25)
        }
    }
    
    private var textRGB: (Double, Double, Double) {
        requiresDarkText
            ? (0.14, 0.14, 0.17)  // Dark text for light backgrounds
            : (0.98, 0.98, 0.98)  // Light text for dark backgrounds
    }
    
    // MARK: - Colors (MainActor)
    
    @MainActor var primaryColor: Color {
        Color(red: primaryRGB.0, green: primaryRGB.1, blue: primaryRGB.2)
    }
    
    @MainActor var secondaryColor: Color {
        Color(red: secondaryRGB.0, green: secondaryRGB.1, blue: secondaryRGB.2)
    }
    
    @MainActor var accentColor: Color {
        Color(red: accentRGB.0, green: accentRGB.1, blue: accentRGB.2)
    }
    
    /// The appropriate text color for content displayed on this theme's background.
    @MainActor var textColor: Color {
        Color(red: textRGB.0, green: textRGB.1, blue: textRGB.2)
    }
    
    // MARK: - Hashable & Equatable
    
    static func == (lhs: CardTheme, rhs: CardTheme) -> Bool {
        lhs.name == rhs.name
    }
    
    func hash(into hasher: inout Hasher) {
        hasher.combine(name)
    }
}

// MARK: - Preset Theme Cases

extension CardTheme {
    /// Internal enum for preset themes
    enum Preset: String, CaseIterable {
        case coral = "Coral"
        case midnight = "Midnight"
        case ocean = "Ocean"
        case lime = "Lime"
        case violet = "Violet"
        case forest = "Forest"
        case rose = "Rose"
        case slate = "Slate"
        case amber = "Amber"
        case plum = "Plum"
    }
}

// MARK: - Convenience Initializer

extension CardTheme {
    /// Creates a theme from a stored name string (convenience for property access)
    static func theme(named name: String) -> CardTheme {
        CardTheme(named: name)
    }
}
