//
//  ClockStyle.swift
//  TheNoiseClock
//
//  Created by Matt Bruce on 9/7/25.
//

import SwiftUI
import Observation

/// Clock customization settings and data model
@Observable
class ClockStyle: Codable, Equatable {
    
    // MARK: - Time Format Settings
    var use24Hour: Bool = true
    var showSeconds: Bool = false
    
    // MARK: - Visual Settings
    var digitColorHex: String = AppConstants.Defaults.digitColorHex
    var randomizeColor: Bool = false
    var glowIntensity: Double = AppConstants.Defaults.glowIntensity
    var digitScale: Double = AppConstants.Defaults.digitScale
    var stretched: Bool = true
    var backgroundHex: String = AppConstants.Defaults.backgroundColorHex
    
    // MARK: - Font Settings
    var fontFamily: String = "System" // System, San Francisco, etc.
    var fontWeight: String = "Bold" // Ultra Light, Thin, Light, Regular, Medium, Semibold, Bold, Heavy, Black
    var fontDesign: String = "Rounded" // Default, Serif, Rounded, Monospaced
    
    // MARK: - Overlay Settings
    var showBattery: Bool = true
    var showDate: Bool = true
    var dateFormat: String = "d MMMM EEE" // Default: "7 September Mon"
    var clockOpacity: Double = AppConstants.Defaults.clockOpacity
    var overlayOpacity: Double = AppConstants.Defaults.overlayOpacity
    
    // MARK: - Display Settings
    var keepAwake: Bool = false // Keep screen awake in display mode
    var respectFocusModes: Bool = true // Respect Focus mode settings for audio
    
    // MARK: - Cached Colors
    private var _cachedDigitColor: Color?
    private var _cachedBackgroundColor: Color?
    
    // MARK: - Codable Keys
    private enum CodingKeys: String, CodingKey {
        case use24Hour
        case showSeconds
        case digitColorHex
        case randomizeColor
        case glowIntensity
        case digitScale
        case stretched
        case backgroundHex
        case fontFamily
        case fontWeight
        case fontDesign
        case showBattery
        case showDate
        case dateFormat
        case clockOpacity
        case overlayOpacity
        case keepAwake
        case respectFocusModes
    }
    
    // MARK: - Initialization
    init() {
        // Defaults already set in property declarations
    }
    
    // MARK: - Codable Implementation
    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        
        self.use24Hour = try container.decodeIfPresent(Bool.self, forKey: .use24Hour) ?? self.use24Hour
        self.showSeconds = try container.decodeIfPresent(Bool.self, forKey: .showSeconds) ?? self.showSeconds
        self.digitColorHex = try container.decodeIfPresent(String.self, forKey: .digitColorHex) ?? self.digitColorHex
        self.randomizeColor = try container.decodeIfPresent(Bool.self, forKey: .randomizeColor) ?? self.randomizeColor
        self.glowIntensity = try container.decodeIfPresent(Double.self, forKey: .glowIntensity) ?? self.glowIntensity
        self.digitScale = try container.decodeIfPresent(Double.self, forKey: .digitScale) ?? self.digitScale
        self.stretched = try container.decodeIfPresent(Bool.self, forKey: .stretched) ?? self.stretched
        self.backgroundHex = try container.decodeIfPresent(String.self, forKey: .backgroundHex) ?? self.backgroundHex
        self.fontFamily = try container.decodeIfPresent(String.self, forKey: .fontFamily) ?? self.fontFamily
        self.fontWeight = try container.decodeIfPresent(String.self, forKey: .fontWeight) ?? self.fontWeight
        self.fontDesign = try container.decodeIfPresent(String.self, forKey: .fontDesign) ?? self.fontDesign
        self.showBattery = try container.decodeIfPresent(Bool.self, forKey: .showBattery) ?? self.showBattery
        self.showDate = try container.decodeIfPresent(Bool.self, forKey: .showDate) ?? self.showDate
        self.dateFormat = try container.decodeIfPresent(String.self, forKey: .dateFormat) ?? self.dateFormat
        self.clockOpacity = try container.decodeIfPresent(Double.self, forKey: .clockOpacity) ?? self.clockOpacity
        self.overlayOpacity = try container.decodeIfPresent(Double.self, forKey: .overlayOpacity) ?? self.overlayOpacity
        self.keepAwake = try container.decodeIfPresent(Bool.self, forKey: .keepAwake) ?? self.keepAwake
        self.respectFocusModes = try container.decodeIfPresent(Bool.self, forKey: .respectFocusModes) ?? self.respectFocusModes
        
        clearColorCache()
    }
    
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(use24Hour, forKey: .use24Hour)
        try container.encode(showSeconds, forKey: .showSeconds)
        try container.encode(digitColorHex, forKey: .digitColorHex)
        try container.encode(randomizeColor, forKey: .randomizeColor)
        try container.encode(glowIntensity, forKey: .glowIntensity)
        try container.encode(digitScale, forKey: .digitScale)
        try container.encode(stretched, forKey: .stretched)
        try container.encode(backgroundHex, forKey: .backgroundHex)
        try container.encode(fontFamily, forKey: .fontFamily)
        try container.encode(fontWeight, forKey: .fontWeight)
        try container.encode(fontDesign, forKey: .fontDesign)
        try container.encode(showBattery, forKey: .showBattery)
        try container.encode(showDate, forKey: .showDate)
        try container.encode(dateFormat, forKey: .dateFormat)
        try container.encode(clockOpacity, forKey: .clockOpacity)
        try container.encode(overlayOpacity, forKey: .overlayOpacity)
        try container.encode(keepAwake, forKey: .keepAwake)
        try container.encode(respectFocusModes, forKey: .respectFocusModes)
    }
    
    // MARK: - Computed Properties
    var digitColor: Color {
        if let cached = _cachedDigitColor {
            return cached
        }
        let color = Color(hex: digitColorHex) ?? .white
        _cachedDigitColor = color
        return color
    }
    
    var backgroundColor: Color {
        if let cached = _cachedBackgroundColor {
            return cached
        }
        let color = Color(hex: backgroundHex) ?? .black
        _cachedBackgroundColor = color
        return color
    }
    
    // MARK: - Helper Methods
    func clearColorCache() {
        _cachedDigitColor = nil
        _cachedBackgroundColor = nil
    }
    
    // MARK: - Equatable
    static func == (lhs: ClockStyle, rhs: ClockStyle) -> Bool {
        lhs.use24Hour == rhs.use24Hour &&
        lhs.showSeconds == rhs.showSeconds &&
        lhs.digitColorHex == rhs.digitColorHex &&
        lhs.randomizeColor == rhs.randomizeColor &&
        lhs.glowIntensity == rhs.glowIntensity &&
        lhs.digitScale == rhs.digitScale &&
        lhs.stretched == rhs.stretched &&
        lhs.backgroundHex == rhs.backgroundHex &&
        lhs.fontFamily == rhs.fontFamily &&
        lhs.fontWeight == rhs.fontWeight &&
        lhs.fontDesign == rhs.fontDesign &&
        lhs.showBattery == rhs.showBattery &&
        lhs.showDate == rhs.showDate &&
        lhs.dateFormat == rhs.dateFormat &&
        lhs.clockOpacity == rhs.clockOpacity &&
        lhs.overlayOpacity == rhs.overlayOpacity &&
        lhs.keepAwake == rhs.keepAwake &&
        lhs.respectFocusModes == rhs.respectFocusModes
    }
}

// MARK: - Storage Key
extension ClockStyle {
    static let appStorageKey = AppConstants.StorageKeys.clockStyle
}
