import Foundation
import Combine
import UserNotifications
import OSLog

private let logger = Logger(subsystem: "nahbar", category: "CallWindowNotification")

class CallWindowManager: ObservableObject {
    static let shared = CallWindowManager()

    @Published var isEnabled: Bool          { didSet { ud.set(isEnabled, forKey: K.enabled) } }
    @Published var startHour: Int           { didSet { ud.set(startHour, forKey: K.startHour) } }
    @Published var startMinute: Int         { didSet { ud.set(startMinute, forKey: K.startMinute) } }
    @Published var endHour: Int             { didSet { ud.set(endHour, forKey: K.endHour) } }
    @Published var endMinute: Int           { didSet { ud.set(endMinute, forKey: K.endMinute) } }
    @Published var selectedWeekdays: Set<Int> {
        didSet {
            let data = (try? JSONEncoder().encode(Array(selectedWeekdays))) ?? Data()
            ud.set(data, forKey: K.weekdays)
        }
    }

    private let ud = UserDefaults.standard

    private enum K {
        static let enabled      = "cwEnabled"
        static let startHour    = "cwStartHour"
        static let startMinute  = "cwStartMinute"
        static let endHour      = "cwEndHour"
        static let endMinute    = "cwEndMinute"
        static let weekdays     = "cwWeekdays"
    }

    // Calendar weekdays in German display order (Calendar: 1=So, 2=Mo, ..., 7=Sa)
    static let weekdayOrder: [(Int, String)] = [
        (2, "Mo"), (3, "Di"), (4, "Mi"), (5, "Do"), (6, "Fr"), (7, "Sa"), (1, "So")
    ]

    private init() {
        isEnabled    = ud.bool(forKey: K.enabled)
        startHour    = ud.object(forKey: K.startHour)   as? Int ?? 17
        startMinute  = ud.object(forKey: K.startMinute) as? Int ?? 0
        endHour      = ud.object(forKey: K.endHour)     as? Int ?? 18
        endMinute    = ud.object(forKey: K.endMinute)   as? Int ?? 0

        if let data = ud.data(forKey: K.weekdays),
           let days = try? JSONDecoder().decode([Int].self, from: data) {
            selectedWeekdays = Set(days)
        } else {
            selectedWeekdays = [2, 3, 4, 5, 6] // Mo–Fr
        }
    }

    // MARK: - Window check

    var isCurrentlyInWindow: Bool {
        guard isEnabled else { return false }
        let cal = Calendar.current
        let now = Date()
        let weekday = cal.component(.weekday, from: now)
        guard selectedWeekdays.contains(weekday) else { return false }
        let nowMin   = cal.component(.hour, from: now) * 60 + cal.component(.minute, from: now)
        let startMin = startHour * 60 + startMinute
        let endMin   = endHour   * 60 + endMinute
        return nowMin >= startMin && nowMin < endMin
    }

    // MARK: - Person selection

    func selectPerson(from persons: [Person]) -> Person? {
        guard !persons.isEmpty else { return nil }
        let cal = Calendar.current

        let candidates = persons.filter { p in
            // Nicht heute schon vorgeschlagen
            if let last = p.lastSuggestedForCall, cal.isDateInToday(last) { return false }
            // Mindestens 7 Tage Pause
            if let last = p.lastSuggestedForCall {
                let days = cal.dateComponents([.day], from: last, to: Date()).day ?? 0
                if days < 7 { return false }
            }
            // Nicht heute schon kontaktiert
            if let lastMoment = p.lastMomentDate, cal.isDateInToday(lastMoment) { return false }
            return true
        }

        let pool = candidates.isEmpty ? persons : candidates

        // Überfällige Kontakte bevorzugen
        let prioritized = pool.filter { $0.needsAttention }
        let ranked = (prioritized.isEmpty ? pool : prioritized).sorted {
            ($0.lastMomentDate ?? $0.createdAt) < ($1.lastMomentDate ?? $1.createdAt)
        }

        // Zufällig aus den Top 3
        return Array(ranked.prefix(3)).randomElement()
    }

    // MARK: - Notifications

    func scheduleNotifications() {
        cancelNotifications()
        guard isEnabled else { return }

        UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound]) { granted, error in
            if let error {
                logger.error("Berechtigung-Fehler: \(error.localizedDescription)")
            }
            guard granted else {
                logger.warning("Notification-Berechtigung abgelehnt – keine Gesprächsfenster-Erinnerung.")
                return
            }
            // Persönlichkeitsgerechter Body-Text via PersonalityEngine
            let body = PersonalityEngine.callWindowCopy(profile: PersonalityStore.shared.profile)
            for weekday in self.selectedWeekdays {
                let content = UNMutableNotificationContent()
                content.title = String(localized: "Gesprächszeit")
                content.body = body
                content.sound = .default
                content.categoryIdentifier = "CALL_WINDOW"

                var dc = DateComponents()
                dc.weekday = weekday
                dc.hour    = self.startHour
                dc.minute  = self.startMinute

                let request = UNNotificationRequest(
                    identifier: "callwindow-\(weekday)",
                    content: content,
                    trigger: UNCalendarNotificationTrigger(dateMatching: dc, repeats: true)
                )
                UNUserNotificationCenter.current().add(request) { error in
                    if let error {
                        logger.error("Gesprächsfenster-Notification konnte nicht geplant werden (Wochentag \(weekday)): \(error.localizedDescription)")
                    }
                }
            }
        }
    }

    func cancelNotifications() {
        UNUserNotificationCenter.current().removePendingNotificationRequests(
            withIdentifiers: (1...7).map { "callwindow-\($0)" }
        )
    }

    // MARK: - Display

    var windowDescription: String {
        String(format: "%02d:%02d – %02d:%02d Uhr", startHour, startMinute, endHour, endMinute)
    }
}
