//
//  TimerViewModel.swift
//  EzTimer
//
//  Created by Jared Evans on 12/16/25.
//

import SwiftUI
import Combine
import UserNotifications
import AudioToolbox
import AVFoundation

class TimerViewModel: ObservableObject {
    @Published var timeRemaining: TimeInterval = 0
    @Published var isActive = false
    @Published var notificationMessage = ""
    @Published var customLabels: [String] = []

    @Published var isTimerFinished = false
    @Published var isFlashEnabled = false
    
    private var timerSubscription: AnyCancellable?
    private var cancellables = Set<AnyCancellable>()
    private var endTime: Date?
    private var initialDuration: TimeInterval = 0 // Track the initial set time
    private var adjustmentDebounceTimer: Timer?
    
    init() {
        // Load custom labels or default to 4 empty strings
        if let saved = UserDefaults.standard.stringArray(forKey: "customLabels") {
            if saved.count >= 4 {
                customLabels = Array(saved.prefix(4))
            } else {
                // Fallback reset if weird count (less than 4)
                 customLabels = ["", "", "", ""]
            }
        } else {
            customLabels = ["", "", "", ""]
        }
        
        loadSettings()
        
        // Observe changes to notificationMessage and update notification if timer is active
        $notificationMessage
            .dropFirst() // Skip initial value
            .sink { [weak self] newMessage in
                guard let self = self else { return }
                if self.isActive && self.timeRemaining > 0, let endTime = self.endTime {
                    // Cancel existing notifications and reschedule with new message
                    self.cancelNotification()
                    self.scheduleNotification(message: newMessage)
                    
                    // Update Live Activity with new message
                    LiveActivityManager.shared.update(endTime: endTime, duration: self.timeRemaining, message: newMessage)
                }
            }
            .store(in: &cancellables)
    }
    
    // Update a custom label and save to persistence
    func updateCustomLabel(at index: Int, with text: String) {
        guard index >= 0 && index < customLabels.count else { return }
        customLabels[index] = text
        UserDefaults.standard.set(customLabels, forKey: "customLabels")
    }
    
    // MARK: - Color Selection
    enum TimerColor: String, CaseIterable, Codable {
        case red, yellow, white, cyan, orange
        
        var color: Color {
            switch self {
            case .red: return .red
            case .yellow: return .yellow
            case .white: return .white
            case .cyan: return .cyan
            case .orange: return .orange
            }
        }
        
        var name: String {
            rawValue.capitalized
        }
    }
    
    @Published var selectedColor: TimerColor = .red {
        didSet {
            UserDefaults.standard.set(selectedColor.rawValue, forKey: "selectedTimerColor")
        }
    }
    
    // MARK: - Flash Mode Selection
    enum FlashMode: String, CaseIterable, Codable {
        case soft   // Soft fading flash
        case rapid  // Rapid strobe-like flash
        
        var iconName: String {
            switch self {
            case .soft: return "sparkle"
            case .rapid: return "sun.max"
            }
        }
    }
    
    @Published var selectedFlashMode: FlashMode = .soft {
        didSet {
            UserDefaults.standard.set(selectedFlashMode.rawValue, forKey: "selectedFlashMode")
        }
    }
    
    private func loadSettings() {
        if let colorString = UserDefaults.standard.string(forKey: "selectedTimerColor"),
           let color = TimerColor(rawValue: colorString) {
            selectedColor = color
        }
        if let flashModeString = UserDefaults.standard.string(forKey: "selectedFlashMode"),
           let flashMode = FlashMode(rawValue: flashModeString) {
            selectedFlashMode = flashMode
        }
    }
    
    // Request notification permissions
    func requestPermissions() {
        UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in
            if granted {
                print("Notification permission granted")
            } else if let error = error {
                print("Notification permission error: \(error.localizedDescription)")
            }
        }
    }
    
    // Set timer with a specific duration in minutes but do not start
    func setTime(minutes: Int) {
        stopTimer() // Invalidate any existing timer
        isTimerFinished = false
        
        // Just set the initial time
        let seconds = TimeInterval(minutes * 60)
        timeRemaining = seconds
        initialDuration = seconds
        isActive = false
    }
    
    // Add time to current duration
    func addTime(minutes: Int) {
        if !isActive {
            // If timer is not active, just add to the current setup
            timeRemaining += Double(minutes * 60)
            initialDuration += Double(minutes * 60) 
        } else {
            // If running, extend the current timer
            timeRemaining += Double(minutes * 60)
            
            // If we extended it while running, we might need to update the endTime locally so the tick logic (which relies on endTime) works correctly?
            // Wait, tick() uses: let remaining = endTime.timeIntervalSinceNow
            // So if we increase timeRemaining, we MUST increase endTime.
            if let currentEnd = endTime {
                endTime = currentEnd.addingTimeInterval(Double(minutes * 60))
                
                // Also update Live Activity if needed
                LiveActivityManager.shared.start(endTime: endTime!, duration: timeRemaining, message: notificationMessage)
            }
        }
    }

    // Start the countdown from the current timeRemaining
    func startCountdown() {
        stopTimer() // Invalidate any existing timer
        isTimerFinished = false
        
        guard timeRemaining > 0 else { return }
        
        // Calculate new end time based on current remaining time
        endTime = Date().addingTimeInterval(timeRemaining)
        isActive = true
        
        scheduleNotification()
        
        // Start Live Activity
        if let targetTime = endTime {
            LiveActivityManager.shared.start(endTime: targetTime, duration: timeRemaining, message: notificationMessage)
        }
        
        
        timerSubscription = Timer.publish(every: 0.1, on: .main, in: .common)
            .autoconnect()
            .sink { [weak self] _ in
                self?.tick()
            }
    }
    
    // Reset the timer to 0 and stop
    func resetTimer() {
        stopTimer()
        isTimerFinished = false
        timeRemaining = 0
        initialDuration = 0
    }
    
    // Adjust time manually
    func adjustTime(bySeconds seconds: Int) {
        let newTime = timeRemaining + TimeInterval(seconds)
        timeRemaining = max(newTime, 0)
        
        if isActive {
            // Update endTime to reflect the new remaining time
            endTime = Date().addingTimeInterval(timeRemaining)
            
            // Cancel current notifications and live activity immediately
            cancelNotification()
            LiveActivityManager.shared.end()
            
            // Cancel any existing debounce timer
            adjustmentDebounceTimer?.invalidate()
            
            // If time was reduced to 0, stop the timer
            if timeRemaining <= 0 {
                stopTimer()
                return
            }
            
            // Start a new debounce timer (2 seconds)
            adjustmentDebounceTimer = Timer.scheduledTimer(withTimeInterval: 2.0, repeats: false) { [weak self] _ in
                guard let self = self, self.isActive, self.timeRemaining > 0, let endTime = self.endTime else { return }
                
                // Restart notifications and live activity
                self.scheduleNotification()
                LiveActivityManager.shared.start(endTime: endTime, duration: self.timeRemaining, message: self.notificationMessage)
            }
        } else {
            // Not running, just update initial duration for setup mode
            initialDuration = timeRemaining
        }
    }
    
    // Stop the timer
    private func stopTimer(cancelsNotification: Bool = true, endActivity: Bool = true) {
        // Cancel any pending debounce timer
        adjustmentDebounceTimer?.invalidate()
        adjustmentDebounceTimer = nil
        
        isActive = false
        timerSubscription?.cancel()
        timerSubscription = nil
        if cancelsNotification {
            cancelNotification()
            isTimerFinished = false // Only clear if manually stopped/reset
        }
        
        // End Live Activity only if requested
        if endActivity {
            LiveActivityManager.shared.end()
        }
    }
    
    // Schedule a local notification
    private func scheduleNotification(message: String? = nil) {
        // Only schedule if we have time remaining
        guard timeRemaining > 0 else { return }
        
        let targetMessage = message ?? notificationMessage
        
        // Burst Mode: Schedule 3 notifications spaced 1 second apart
        for i in 0..<3 {
            let offset = TimeInterval(i * 1)
            let triggerTime = timeRemaining + offset
            
            let content = UNMutableNotificationContent()
            content.title = "VizTimer"
            content.body = targetMessage.isEmpty ? "Timer Finished!" : targetMessage
            content.sound = .default
            content.interruptionLevel = .timeSensitive
            
            let trigger = UNTimeIntervalNotificationTrigger(timeInterval: triggerTime, repeats: false)
            let request = UNNotificationRequest(identifier: "VizTimerNotification_\(i)", content: content, trigger: trigger)
            
            UNUserNotificationCenter.current().add(request)
        }
    }
    
    // Cancel any pending notifications
    private func cancelNotification() {
        let identifiers = (0..<3).map { "VizTimerNotification_\($0)" }
        UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: identifiers)
    }
    
    // Trigger vibration 3 times
    private func triggerVibration() {
        for i in 0..<3 {
            DispatchQueue.main.asyncAfter(deadline: .now() + Double(i)) {
                AudioServicesPlaySystemSound(kSystemSoundID_Vibrate)
            }
        }
    }
    
    // Trigger Camera Flash 3 times
    private func triggerFlash() {
        guard let device = AVCaptureDevice.default(for: .video) else {
            print("No video device found")
            return
        }
        
        guard device.hasTorch else {
            print("Device does not have a torch")
            return
        }
        
        for i in 0..<3 {
            // Flash ON
            DispatchQueue.main.asyncAfter(deadline: .now() + Double(i)) {
                do {
                    try device.lockForConfiguration()
                    // Use max brightness for visibility
                    try device.setTorchModeOn(level: AVCaptureDevice.maxAvailableTorchLevel) 
                    device.unlockForConfiguration()
                } catch {
                    print("Torch could not be used: \(error)")
                }
            }
            
            // Flash OFF (short pulse - 100ms)
            DispatchQueue.main.asyncAfter(deadline: .now() + Double(i) + 0.1) {
                 do {
                    try device.lockForConfiguration()
                    device.torchMode = .off
                    device.unlockForConfiguration()
                } catch {
                    print("Torch could not be used: \(error)")
                }
            }
        }
    }
    
    // Update logic for each tick
    private func tick() {
        guard let endTime = endTime else { return }
        let remaining = endTime.timeIntervalSinceNow
        
        if remaining <= 0 {
            withAnimation {
                timeRemaining = initialDuration // Reset to initial duration
            }
            
            // Finish Live Activity nicely
            LiveActivityManager.shared.finish(message: notificationMessage.isEmpty ? "Timer Finished!" : notificationMessage)
            
            triggerVibration()
            if isFlashEnabled {
                triggerFlash()
            }
            stopTimer(cancelsNotification: false, endActivity: false) // Do NOT cancel notification so it fires, and don't kill activity
            isTimerFinished = true
        } else {
            withAnimation {
                timeRemaining = remaining
            }
        }
    }
    
    // Format time for display
    func timeString() -> String {
        let totalSeconds = Int(ceil(timeRemaining))
        let minutes = totalSeconds / 60
        let seconds = totalSeconds % 60
        return String(format: "%02d:%02d", minutes, seconds)
    }
}
