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

import Foundation
import Combine
import Observation
import AudioPlaybackKit
import SwiftUI

/// 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
    
    // 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()
    }
    
    deinit {
        stopTimers()
    }
    
    // MARK: - Public Interface
    func toggleDisplayMode() {
        withAnimation(UIConstants.AnimationCurves.bouncy) {
            isDisplayMode.toggle()
        }
        
        // Manage wake lock based on display mode and keep awake setting
        updateWakeLockState()
    }
    
    func updateStyle(_ newStyle: ClockStyle) {
        style = newStyle
        saveStyle()
        updateTimersIfNeeded()
        updateWakeLockState()
    }
    
    // MARK: - Private Methods
    private func loadStyle() {
        if let decoded = try? JSONDecoder().decode(ClockStyle.self, from: styleJSON) {
            style = decoded
        } else {
            style = ClockStyle()
            saveStyle()
        }
    }
    
    private 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()
                }
            }
        }
        
        // 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()
        }
    }
}
