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

import Foundation
import Combine
import Observation
import AudioPlaybackKit
import SwiftUI
import Bedrock

/// ViewModel for clock display and management
@Observable
class ClockViewModel {
    
    // MARK: - Properties
    private(set) var currentTime = Date()
    private(set) var style = ClockStyle()
    private(set) var isDisplayMode = false
    
    // Wake lock service
    private let wakeLockService = WakeLockService.shared
    
    // Ambient light service
    private let ambientLightService = AmbientLightService.shared
    
    // Timer management
    private var secondTimer: Timer.TimerPublisher?
    private var minuteTimer: Timer.TimerPublisher?
    private var secondCancellable: AnyCancellable?
    private var minuteCancellable: AnyCancellable?
    
    // Persistence
    private var persistenceWorkItem: DispatchWorkItem?
    private var styleJSON: Data {
        get {
            UserDefaults.standard.data(forKey: ClockStyle.appStorageKey) ?? {
                let def = ClockStyle()
                return (try? JSONEncoder().encode(def)) ?? Data()
            }()
        }
        set {
            UserDefaults.standard.set(newValue, forKey: ClockStyle.appStorageKey)
        }
    }    
    
    // MARK: - Initialization
    init() {
        loadStyle()
        setupTimers()
        startAmbientLightMonitoring()
    }
    
    deinit {
        stopTimers()
        stopAmbientLightMonitoring()
    }
    
    // MARK: - Public Interface
    func toggleDisplayMode() {
        withAnimation(Design.Animation.spring(bounce: Design.Animation.springBounce)) {
            isDisplayMode.toggle()
        }
        
        // Manage wake lock based on display mode and keep awake setting
        updateWakeLockState()
    }
    
    func updateStyle(_ newStyle: ClockStyle) {
        
        // Update properties of the existing style object instead of replacing it
        // This preserves the @Observable chain
        style.use24Hour = newStyle.use24Hour
        style.showSeconds = newStyle.showSeconds
        style.showAmPm = newStyle.showAmPm
        style.forceHorizontalMode = newStyle.forceHorizontalMode
        style.digitColorHex = newStyle.digitColorHex
        style.glowIntensity = newStyle.glowIntensity
        style.digitScale = newStyle.digitScale
        style.stretched = newStyle.stretched
        style.clockOpacity = newStyle.clockOpacity
        style.fontFamily = newStyle.fontFamily
        style.fontWeight = newStyle.fontWeight
        style.fontDesign = newStyle.fontDesign
        style.showBattery = newStyle.showBattery
        style.showDate = newStyle.showDate
        style.overlayOpacity = newStyle.overlayOpacity
        style.backgroundHex = newStyle.backgroundHex
        style.keepAwake = newStyle.keepAwake
        style.randomizeColor = newStyle.randomizeColor
        style.selectedColorTheme = newStyle.selectedColorTheme
        style.nightModeEnabled = newStyle.nightModeEnabled
        style.autoNightMode = newStyle.autoNightMode
        style.scheduledNightMode = newStyle.scheduledNightMode
        style.nightModeStartTime = newStyle.nightModeStartTime
        style.nightModeEndTime = newStyle.nightModeEndTime
        style.ambientLightThreshold = newStyle.ambientLightThreshold
        style.autoBrightness = newStyle.autoBrightness
        style.dateFormat = newStyle.dateFormat
        style.respectFocusModes = newStyle.respectFocusModes
        
        
        saveStyle()
        updateTimersIfNeeded()
        updateWakeLockState()
        updateBrightness() // Update brightness when style changes
    }
    
    // MARK: - Private Methods
    private func loadStyle() {
        if let decoded = try? JSONDecoder().decode(ClockStyle.self, from: styleJSON) {
            style = decoded
        } else {
            style = ClockStyle()
            saveStyle()
        }
    }
    
    func saveStyle() {
        persistenceWorkItem?.cancel()
        
        let work = DispatchWorkItem {
            if let data = try? JSONEncoder().encode(self.style) {
                self.styleJSON = data
            }
        }
        persistenceWorkItem = work
        
        DispatchQueue.main.asyncAfter(
            deadline: .now() + AppConstants.PersistenceDelays.clockStyle,
            execute: work
        )
    }
    
    private func setupTimers() {
        // Always need minute timer for color randomization
        if minuteTimer == nil {
            minuteTimer = Timer.publish(every: AppConstants.TimerIntervals.minute, on: .main, in: .common)
            minuteCancellable = minuteTimer?.autoconnect().sink { _ in
                if self.style.randomizeColor {
                    self.style.digitColorHex = Color.randomBrightColorHex()
                    self.saveStyle()
                    self.updateBrightness() // Update brightness when color changes
                }
                
                // Check for night mode state changes (scheduled night mode)
                // Force a UI update by updating currentTime slightly
                self.currentTime = Date()
                
                // Update brightness if night mode is active
                self.updateBrightness()
            }
        }
        
        // Only create second timer if seconds are shown
        if style.showSeconds && secondTimer == nil {
            secondTimer = Timer.publish(every: AppConstants.TimerIntervals.second, on: .main, in: .common)
            secondCancellable = secondTimer?.autoconnect().sink { now in
                self.currentTime = now
            }
        }
    }
    
    private func stopTimers() {
        secondCancellable?.cancel()
        minuteCancellable?.cancel()
        secondCancellable = nil
        minuteCancellable = nil
        secondTimer = nil
        minuteTimer = nil
    }
    
    private func updateTimersIfNeeded() {
        if style.showSeconds && secondTimer == nil {
            secondTimer = Timer.publish(every: AppConstants.TimerIntervals.second, on: .main, in: .common)
            secondCancellable = secondTimer?.autoconnect().sink { now in
                self.currentTime = now
            }
        } else if !style.showSeconds && secondTimer != nil {
            secondCancellable?.cancel()
            secondCancellable = nil
            secondTimer = nil
        }
    }
    
    /// Update wake lock state based on current settings
    private func updateWakeLockState() {
        // Enable wake lock if in display mode and keep awake is enabled
        if isDisplayMode && style.keepAwake {
            wakeLockService.enableWakeLock()
        } else {
            wakeLockService.disableWakeLock()
        }
    }
    
    /// Start ambient light monitoring
    private func startAmbientLightMonitoring() {
        ambientLightService.startMonitoring()
        
        // Set up callback to respond to brightness changes
        ambientLightService.onBrightnessChange = { [weak self] in
            Design.debugLog("[brightness] ClockViewModel: Received brightness change notification")
            self?.updateBrightness()
        }
    }
    
    /// Stop ambient light monitoring
    private func stopAmbientLightMonitoring() {
        ambientLightService.stopMonitoring()
    }
    
    /// Update brightness based on color theme and night mode settings
    private func updateBrightness() {
        if style.autoBrightness {
            let targetBrightness = style.effectiveBrightness
            let currentScreenBrightness = UIScreen.main.brightness
            let isNightMode = style.isNightModeActive
            
            Design.debugLog("[brightness] Auto Brightness Debug:")
            Design.debugLog("[brightness]   - Auto brightness enabled: \(style.autoBrightness)")
            Design.debugLog("[brightness]   - Current screen brightness: \(String(format: "%.2f", currentScreenBrightness))")
            Design.debugLog("[brightness]   - Target brightness: \(String(format: "%.2f", targetBrightness))")
            Design.debugLog("[brightness]   - Night mode active: \(isNightMode)")
            Design.debugLog("[brightness]   - Color theme: \(style.selectedColorTheme)")
            Design.debugLog("[brightness]   - Ambient light threshold: \(String(format: "%.2f", style.ambientLightThreshold))")
            
            ambientLightService.setBrightness(targetBrightness)
            
            Design.debugLog("[brightness]   - Brightness set to: \(String(format: "%.2f", targetBrightness))")
            Design.debugLog("[brightness]   - Actual screen brightness now: \(String(format: "%.2f", UIScreen.main.brightness))")
            Design.debugLog("[brightness] ---")
        } else {
            Design.debugLog("[brightness] Auto Brightness: DISABLED")
        }
    }
}
