import Foundation

// MARK: - PersonalityEngine

/// Reine Berechnungslogik – keine UI-Abhängigkeiten, vollständig testbar.
/// Mappt Quiz-Antworten auf ein PersonalityProfile und leitet daraus
/// App-Verhaltens-Parameter ab.
enum PersonalityEngine {

    // MARK: - Profil berechnen

    /// Berechnet ein PersonalityProfile aus den gegebenen Antworten.
    ///
    /// - Parameter answers: Array von Tupeln (questionID, choseA).
    ///   `choseA = true` bedeutet Option A wurde gewählt, `false` = Option B.
    ///   Übersprungene Fragen können fehlen; fehlende Dimensionen erhalten 0 Punkte.
    /// - Returns: Fertiges PersonalityProfile mit Zeitstempel.
    static func computeProfile(from answers: [(questionID: String, choseA: Bool)]) -> PersonalityProfile {
        var scores: [OceanDimension: Int] = [:]
        // Alle Dimensionen mit 0 initialisieren
        for dim in OceanDimension.allCases { scores[dim] = 0 }

        // Antworten auswerten
        let answerMap = Dictionary(uniqueKeysWithValues: answers.map { ($0.questionID, $0.choseA) })
        for question in QuizQuestion.all {
            guard let choseA = answerMap[question.id] else { continue }
            let points = choseA ? question.optionAScore : (1 - question.optionAScore)
            scores[question.dimension, default: 0] += points
        }

        return PersonalityProfile(scores: scores, completedAt: Date())
    }

    // MARK: - Zusammenfassungstext

    /// Regelbasierter Zusammenfassungstext (kein API-Aufruf). Delegiert an PersonalityProfile.
    static func summaryText(for profile: PersonalityProfile) -> String {
        profile.summaryText
    }

    // MARK: - Nudge-Intervall

    /// Empfohlenes Kontakt-Nudge-Intervall in Tagen basierend auf dem Profil.
    /// - High Extraversion → kürzeres Intervall (häufigere Vorschläge)
    /// - Low Extraversion / High Neuroticism → längeres Intervall
    static func suggestedNudgeInterval(for profile: PersonalityProfile) -> Int {
        let e = profile.level(for: .extraversion)
        let n = profile.level(for: .neuroticism)

        switch (e, n) {
        case (.high, _):    return 3   // Gesellig → alle 3 Tage
        case (.medium, _):  return 7   // Ausgeglichen → alle 7 Tage
        case (.low, .high): return 14  // Introvertiert + sensibel → alle 14 Tage
        default:            return 10  // Introvertiert → alle 10 Tage
        }
    }

    // MARK: - Push-Benachrichtigungs-Text

    /// Persönlichkeitsgerechter Benachrichtigungstext für Kontakt-Erinnerungen.
    /// - High Neuroticism → wärmer, ermutigend
    /// - Low/Medium Neuroticism → direkt, casual
    static func notificationCopy(contactName: String, profile: PersonalityProfile?) -> String {
        guard let profile else {
            return "\(contactName) – wann hast du zuletzt etwas von ihm/ihr gehört?"
        }
        switch profile.level(for: .neuroticism) {
        case .high:
            return "Hey – \(contactName) freut sich sicher, von dir zu hören. 🙂"
        case .medium:
            return "\(contactName) – Zeit für ein kurzes Hallo?"
        case .low:
            return "\(contactName) – wann hast du zuletzt was von ihm/ihr gehört?"
        }
    }

    // MARK: - Notification-Texte

    /// Body-Text für Gesprächsfenster-Notification (allgemeine Kontakt-Erinnerung, kein spezifischer Name).
    /// Zentralisiert die bisher in CallWindowManager inline definierte Persönlichkeitslogik.
    /// - High Extraversion → direkt, motivierend
    /// - High Neuroticism (nicht high E) → weich, ermutigend
    /// - Default → freundlich-neutral
    static func callWindowCopy(profile: PersonalityProfile?) -> String {
        guard let profile else {
            return String(localized: "Wer freut sich heute von dir zu hören?")
        }
        switch (profile.level(for: .extraversion), profile.level(for: .neuroticism)) {
        case (.high, _):
            return String(localized: "Wer freut sich heute von dir zu hören?")
        case (_, .high):
            return String(localized: "Magst du heute jemanden kurz anschreiben? Das kann viel bedeuten. 🙂")
        default:
            return String(localized: "Zeit, dich bei jemandem zu melden?")
        }
    }

    /// Body-Text für Nachwirkungs-Notification nach einem Treffen.
    /// Zentralisiert die bisher in AftermathNotificationManager inline verwendete Persönlichkeitslogik.
    /// - High Neuroticism → weich, optional einladend
    /// - Default → direkt, warm
    static func aftermathCopy(profile: PersonalityProfile?) -> String {
        guard let profile else {
            return String(localized: "Wie wirkt euer Treffen jetzt auf dich? 3 kurze Fragen – dauert 1 Minute.")
        }
        switch profile.level(for: .neuroticism) {
        case .high:
            return String(localized: "Wenn du magst, kannst du das Treffen kurz reflektieren.")
        default:
            return String(localized: "Wie wirkt euer Treffen jetzt auf dich? 3 kurze Fragen – dauert 1 Minute.")
        }
    }

    // MARK: - Besuchsbewertungs-Timing

    /// Gibt an, ob der Besuchsfragebogen verzögert angezeigt werden soll.
    /// - High Conscientiousness → sofort
    /// - High Neuroticism → 2h Verzögerung mit weicherem Text
    static func ratingPromptTiming(for profile: PersonalityProfile?) -> RatingPromptTiming {
        guard let profile else { return .immediate(copy: nil) }

        let c = profile.level(for: .conscientiousness)
        let n = profile.level(for: .neuroticism)

        if c == .high {
            return .immediate(copy: nil)
        } else if n == .high {
            return .delayed(
                seconds: 7200, // 2 Stunden
                copy: "Wenn du magst, kannst du das Treffen kurz reflektieren."
            )
        }
        return .immediate(copy: nil)
    }

    // MARK: - Kontakt-Reihenfolge

    /// Gibt eine sortierte Liste von Kontakten zurück, wobei persönlichkeitsgesteuerte
    /// Empfehlungen zuerst erscheinen und eine Begründung erhalten.
    ///
    /// - High Agreeableness → Kontakte priorisieren, die lange nicht besucht wurden
    /// - Low Extraversion → Gesamtanzahl der Vorschläge reduzieren
    static func sortedSuggestions(
        contacts: [NahbarContact],
        profile: PersonalityProfile?,
        lastMeetingDates: [UUID: Date]
    ) -> [ContactSuggestion] {
        guard let profile else {
            return contacts.map { ContactSuggestion(contact: $0, isRecommended: false, reason: nil) }
        }

        let a = profile.level(for: .agreeableness)
        let e = profile.level(for: .extraversion)

        // Maximale Anzahl an Vorschlägen nach Extraversion
        let maxCount: Int
        switch e {
        case .high:   maxCount = contacts.count
        case .medium: maxCount = min(contacts.count, 5)
        case .low:    maxCount = min(contacts.count, 3)
        }

        // Sortierstrategie nach Agreeableness
        var sorted = contacts
        if a == .high {
            sorted = contacts.sorted { lhs, rhs in
                let lDate = lastMeetingDates[lhs.id] ?? .distantPast
                let rDate = lastMeetingDates[rhs.id] ?? .distantPast
                return lDate < rDate // ältestes Treffen zuerst
            }
        }

        return sorted.prefix(maxCount).map { contact in
            let longAgo: Bool
            if let lastMeeting = lastMeetingDates[contact.id] {
                let daysSince = Calendar.current.dateComponents([.day], from: lastMeeting, to: Date()).day ?? 0
                longAgo = daysSince > 14
            } else {
                longAgo = true
            }

            let isRecommended = a == .high && longAgo
            let reason: String? = isRecommended ? "Schon länger nichts von \(contact.givenName) gehört." : nil
            return ContactSuggestion(contact: contact, isRecommended: isRecommended, reason: reason)
        }
    }

    // MARK: - Intervall-Empfehlung für Einstellungen

    /// Gibt den empfohlenen Benachrichtigungs-Intervall für das Einstellungsmenü zurück.
    static func recommendedNotificationInterval(for profile: PersonalityProfile?) -> Int? {
        guard let profile else { return nil }
        return suggestedNudgeInterval(for: profile)
    }
}

// MARK: - Supporting Types

/// Ergebnis der persönlichkeitsgesteuerten Kontakt-Sortierung.
struct ContactSuggestion: Identifiable {
    var id: UUID { contact.id }
    let contact: NahbarContact
    /// Ob dieser Kontakt aufgrund des Profils empfohlen wird.
    let isRecommended: Bool
    /// Kurze Begründung für den RecommendedBadge (nil wenn nicht empfohlen).
    let reason: String?
}

/// Zeitpunkt und Kontext für den Besuchsfragebogen-Prompt.
enum RatingPromptTiming {
    case immediate(copy: String?)
    case delayed(seconds: Int, copy: String?)
}


