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

import Foundation
import UserNotifications
import Observation

/// Service for managing alarms and notifications
@Observable
class AlarmService {
    
    // MARK: - Properties
    private(set) var alarms: [Alarm] = []
    private var alarmLookup: [UUID: Int] = [:]
    private var persistenceWorkItem: DispatchWorkItem?
    private let focusModeService = FocusModeService.shared
    
    // MARK: - Initialization
    init() {
        loadAlarms()
        Task {
            // Request permissions through FocusModeService for better compatibility
            let granted = await focusModeService.requestNotificationPermissions()
            if !granted {
                // Fallback to original method
                _ = await NotificationUtils.requestPermissions()
            }
        }
    }
    
    // MARK: - Public Interface
    func addAlarm(_ alarm: Alarm) {
        alarms.append(alarm)
        updateAlarmLookup()
        scheduleNotification(for: alarm)
        saveAlarms()
    }
    
    func updateAlarm(_ alarm: Alarm) {
        guard let index = alarmLookup[alarm.id] else { return }
        alarms[index] = alarm
        updateAlarmLookup()
        scheduleNotification(for: alarm)
        saveAlarms()
    }
    
    func deleteAlarm(id: UUID) {
        alarms.removeAll { $0.id == id }
        updateAlarmLookup()
        NotificationUtils.removeNotification(identifier: id.uuidString)
        saveAlarms()
    }
    
    func toggleAlarm(id: UUID) {
        guard let index = alarmLookup[id] else { return }
        alarms[index].isEnabled.toggle()
        scheduleNotification(for: alarms[index])
        saveAlarms()
    }
    
    func getAlarm(id: UUID) -> Alarm? {
        return alarms.first { $0.id == id }
    }
    
    // MARK: - Private Methods
    private func updateAlarmLookup() {
        alarmLookup.removeAll()
        for (index, alarm) in alarms.enumerated() {
            alarmLookup[alarm.id] = index
        }
    }
    
    private func scheduleNotification(for alarm: Alarm) {
        // Remove existing notification
        NotificationUtils.removeNotification(identifier: alarm.id.uuidString)
        
        // Schedule new notification if enabled
        if alarm.isEnabled {
            Task {
                let respectFocusModes = currentRespectFocusModes()
                // Use FocusModeService for better Focus mode compatibility
                focusModeService.scheduleAlarmNotification(
                    identifier: alarm.id.uuidString,
                    title: alarm.label,
                    body: alarm.notificationMessage,
                    date: alarm.time,
                    soundName: alarm.soundName,
                    repeats: false, // For now, set to false since Alarm model doesn't have repeatDays
                    respectFocusModes: respectFocusModes
                )
            }
        }
    }

    private func currentRespectFocusModes() -> Bool {
        guard let data = UserDefaults.standard.data(forKey: ClockStyle.appStorageKey),
              let style = try? JSONDecoder().decode(ClockStyle.self, from: data) else {
            return ClockStyle().respectFocusModes
        }
        return style.respectFocusModes
    }
    
    private func saveAlarms() {
        persistenceWorkItem?.cancel()
        
        let alarmsSnapshot = self.alarms
        let work = DispatchWorkItem {
            if let encoded = try? JSONEncoder().encode(alarmsSnapshot) {
                UserDefaults.standard.set(encoded, forKey: AppConstants.StorageKeys.savedAlarms)
            }
        }
        persistenceWorkItem = work
        
        DispatchQueue.main.asyncAfter(
            deadline: .now() + AppConstants.PersistenceDelays.alarms,
            execute: work
        )
    }
    
    private func loadAlarms() {
        if let savedAlarms = UserDefaults.standard.data(forKey: AppConstants.StorageKeys.savedAlarms),
           let decodedAlarms = try? JSONDecoder().decode([Alarm].self, from: savedAlarms) {
            alarms = decodedAlarms
            updateAlarmLookup()
            
            // Reschedule all enabled alarms
            for alarm in alarms where alarm.isEnabled {
                scheduleNotification(for: alarm)
            }
        }
    }
}
