import SwiftUI
import SwiftData
import CoreData
import UserNotifications
import OSLog
import UIKit

private let todoNotificationLogger = Logger(subsystem: "nahbar", category: "TodoNotification")

// Wiederverwendet in AIAnalysisSheet (scoped auf diese Datei)
private enum AnalysisState {
    case idle
    case loading
    case result(AIAnalysisResult, Date)
    case error(String)
}

struct PersonDetailView: View {
    @Environment(\.nahbarTheme) var theme
    @Environment(\.modelContext) var modelContext
    @Environment(\.dismiss) var dismiss
    @Environment(\.openURL) var openURL
    @Bindable var person: Person

    @State private var showingAddMoment = false
    @State private var showingAddTodo = false
    @State private var showingEditPerson = false

    // Meeting-Rating-Flow (V5)
    @State private var momentForRating: Moment? = nil
    @State private var momentForAftermath: Moment? = nil
    @State private var momentForEdit: Moment? = nil
    @State private var momentForSummary: Moment? = nil

    // Moment-Bearbeiten
    @State private var momentForTextEdit: Moment? = nil

    // Todo-Bearbeiten
    @State private var todoForEdit: Todo? = nil
    @State private var fadingOutTodos: [Todo] = []

    // Neu hinzugefügte Logbuch-Momente – 5 s in Momente sichtbar, dann in Verlauf
    @State private var fadingOutMoments: [Moment] = []
    @State private var seenMomentIDs: Set<UUID> = []
    // Treffen-Momente warten auf Rating-Survey-Abschluss bevor der 5-s-Timer startet
    @State private var pendingFadeAfterSurvey: [Moment] = []

    // Kalender-Lösch-Bestätigung
    @State private var momentPendingDelete: Moment? = nil
    @State private var showCalendarDeleteDialog = false

    // Kontakt-Aktionsblatt (Telefon)
    @State private var showingPhoneActionSheet = false

    // Fallback wenn keine Mail-App installiert
    @State private var showingEmailFallback = false

    @StateObject private var storeManager = StoreManager.shared

    // KI-Analyse
    @State private var showingAIAnalysis = false
    @State private var showingAIPaywall = false

    private var canUseAI: Bool {
        storeManager.isMax || AIAnalysisService.shared.hasFreeQueriesLeft
    }

    var body: some View {
        ScrollView {
            VStack(alignment: .leading, spacing: 28) {
                personHeader
                if person.phoneNumber != nil || person.emailAddress != nil {
                    kontaktSection
                }
                momentsSection
                todosSection
                if !mergedLogPreview.isEmpty { logbuchSection }
                if hasInfoContent { infoSection }
            }
            .padding(.horizontal, 20)
            .padding(.top, 16)
            .padding(.bottom, 48)
        }
        .background(theme.backgroundPrimary.ignoresSafeArea())
        .navigationBarTitleDisplayMode(.inline)
        .themedNavBar()
        .toolbar {
            ToolbarItem(placement: .topBarTrailing) {
                Button("Bearbeiten") { showingEditPerson = true }
                    .font(.system(size: 15))
                    .foregroundStyle(theme.accent)
            }

        }
        .sheet(isPresented: $showingAddTodo) {
            AddTodoView(person: person)
        }
        .sheet(isPresented: $showingAddMoment) {
            AddMomentView(person: person) { meetingMoment in
                // Rating-Flow nur für vergangene Treffen – zukünftige Termine überspringen
                guard meetingMoment.createdAt <= Date() else { return }
                DispatchQueue.main.asyncAfter(deadline: .now() + 0.45) {
                    momentForRating = meetingMoment
                }
            }
        }
        .onChange(of: showingAddMoment) { _, isShowing in
            if isShowing {
                seenMomentIDs = Set(person.sortedMoments.map(\.id))
            } else {
                // Neu gespeicherte Logbuch-Momente (keine Vorhaben, kein Zukunftstreffen) kurz anzeigen
                let newLogbuchMoments = person.sortedMoments.filter { moment in
                    guard !seenMomentIDs.contains(moment.id) else { return false }
                    let isActive = moment.isOpen || (moment.isMeeting && moment.createdAt > Date())
                    return !isActive
                }
                // Sofort visuell in Momente einblenden
                for moment in newLogbuchMoments {
                    withAnimation { fadingOutMoments.append(moment) }
                }
                // Treffen-Momente: Timer erst nach Rating-Survey starten (survey läuft noch)
                let meetingMoments = newLogbuchMoments.filter { $0.isMeeting }
                let otherMoments = newLogbuchMoments.filter { !$0.isMeeting }
                scheduleFadeOut(otherMoments)
                pendingFadeAfterSurvey.append(contentsOf: meetingMoments)
            }
        }
        .onChange(of: momentForRating) { old, new in
            // Survey geschlossen (war gesetzt, ist jetzt nil) → Timer für wartende Treffen starten
            guard old != nil && new == nil, !pendingFadeAfterSurvey.isEmpty else { return }
            let toFade = pendingFadeAfterSurvey
            pendingFadeAfterSurvey = []
            scheduleFadeOut(toFade)
        }
        .sheet(isPresented: $showingEditPerson) {
            AddPersonView(existingPerson: person)
        }
        .sheet(item: $momentForRating) { moment in
            MeetingRatingFlowView(
                moment: moment,
                aftermathDelay: AftermathDelayOption.loadFromDefaults().seconds
            )
        }
        .sheet(item: $momentForAftermath) { moment in
            AftermathRatingFlowView(moment: moment)
        }
        .sheet(item: $momentForEdit) { moment in
            MeetingEditFlowView(moment: moment)
        }
        .sheet(item: $momentForSummary) { moment in
            NavigationStack {
                MeetingSummaryView(moment: moment, onDismiss: { momentForSummary = nil })
                    .navigationTitle("Treffen")
                    .navigationBarTitleDisplayMode(.inline)
                    .toolbar {
                        ToolbarItem(placement: .cancellationAction) {
                            Button("Schließen") { momentForSummary = nil }
                        }
                    }
            }
        }
        .sheet(item: $momentForTextEdit) { moment in
            EditMomentView(moment: moment)
        }
        .sheet(item: $todoForEdit) { todo in
            EditTodoView(todo: todo)
        }
        .sheet(isPresented: $showingAIAnalysis) {
            AIAnalysisSheet(person: person)
        }
        .sheet(isPresented: $showingAIPaywall) {
            PaywallView(targeting: .max)
        }
        .confirmationDialog(
            "Moment löschen",
            isPresented: $showCalendarDeleteDialog,
            presenting: momentPendingDelete
        ) { moment in
            Button("Moment + Kalendereintrag löschen", role: .destructive) {
                performDelete(moment, deleteCalendarEvent: true)
                momentPendingDelete = nil
            }
            Button("Nur Moment löschen", role: .destructive) {
                performDelete(moment, deleteCalendarEvent: false)
                momentPendingDelete = nil
            }
            Button("Abbrechen", role: .cancel) {
                momentPendingDelete = nil
            }
        } message: { _ in
            Text("Dieser Moment hat einen verknüpften Kalendereintrag. Soll dieser ebenfalls gelöscht werden?")
        }
        .confirmationDialog(
            "Telefon",
            isPresented: $showingPhoneActionSheet,
            titleVisibility: .hidden
        ) {
            if let phone = person.phoneNumber {
                let sanitized = phone.components(separatedBy: .init(charactersIn: " -()")).joined()
                if let url = URL(string: "tel://\(sanitized)") {
                    Button("Anrufen") { openURL(url) }
                }
                if let url = URL(string: "sms://\(sanitized)") {
                    Button("Nachricht") { openURL(url) }
                }
                if let url = URL(string: "facetime://\(sanitized)") {
                    Button("FaceTime") { openURL(url) }
                }
                let waNumber = phone.filter { $0.isNumber }
                if !waNumber.isEmpty, let url = URL(string: "https://wa.me/\(waNumber)") {
                    Button("WhatsApp") { openURL(url) }
                }
            }
        }
        .alert("Keine Mail-App gefunden", isPresented: $showingEmailFallback) {
            Button("Kopieren") {
                UIPasteboard.general.string = person.emailAddress
            }
            Button("OK", role: .cancel) {}
        } message: {
            Text(person.emailAddress ?? "")
        }
        // Schützt vor Crash wenn der ModelContext durch Migration oder
        // CloudKit-Sync intern reset() aufruft und Person-Objekte ungültig werden.
        .onReceive(
            NotificationCenter.default.publisher(
                for: Notification.Name("NSManagedObjectContextObjectsDidChangeNotification")
            )
        ) { notification in
            guard notification.userInfo?[NSInvalidatedAllObjectsKey] != nil else { return }
            dismiss()
        }
    }

    // MARK: - Header

    private var personHeader: some View {
        HStack(alignment: .top, spacing: 16) {
            PersonAvatar(person: person, size: 64)

            VStack(alignment: .leading, spacing: 5) {
                Text(person.name)
                    .font(.system(size: 24, weight: .light, design: theme.displayDesign))
                    .foregroundStyle(theme.contentPrimary)

                TagBadge(text: person.tag.rawValue)

                if let occ = person.occupation, !occ.isEmpty {
                    Text(occ)
                        .font(.system(size: 14))
                        .foregroundStyle(theme.contentSecondary)
                }

                if person.nudgeStatus != .never {
                    nudgeChip
                }
            }

            Spacer()

            Button {
                if canUseAI {
                    showingAIAnalysis = true
                } else {
                    showingAIPaywall = true
                }
            } label: {
                HStack(spacing: 3) {
                    Image(systemName: "sparkles")
                        .font(.system(size: 18))
                        .foregroundStyle(theme.accent)
                    MaxBadge()
                }
            }
            .padding(.top, 4)
        }
    }

    private var nudgeChip: some View {
        let status = person.nudgeStatus
        let dotColor: Color = switch status {
            case .overdue: .red
            case .soon:    .orange
            default:       .green
        }
        let reference = person.lastMomentDate ?? person.createdAt
        let formatter = RelativeDateTimeFormatter()
        formatter.unitsStyle = .full
        let relativeTime = formatter.localizedString(for: reference, relativeTo: Date())

        return Menu {
            ForEach(NudgeFrequency.allCases, id: \.self) { freq in
                Button {
                    person.nudgeFrequency = freq
                    person.touch()
                    try? modelContext.save()
                } label: {
                    if freq == person.nudgeFrequency {
                        Label(freq.displayLabel, systemImage: "checkmark")
                    } else {
                        Text(freq.displayLabel)
                    }
                }
            }
        } label: {
            HStack(spacing: 5) {
                Circle()
                    .fill(dotColor)
                    .frame(width: 7, height: 7)
                Text(person.nudgeFrequency.displayLabel)
                    .font(.system(size: 13))
                    .foregroundStyle(theme.contentSecondary)
                Text("·")
                    .font(.system(size: 13))
                    .foregroundStyle(theme.contentTertiary)
                Text(relativeTime)
                    .font(.system(size: 13))
                    .foregroundStyle(theme.contentTertiary)
            }
        }
        .padding(.top, 2)
    }

    // MARK: - Kontakt

    private var kontaktSection: some View {
        VStack(alignment: .leading, spacing: 10) {
            SectionHeader(title: "Kontakt", icon: "phone")

            VStack(spacing: 0) {
                if let phone = person.phoneNumber {
                    Button { showingPhoneActionSheet = true } label: {
                        kontaktRow(label: "Telefon", value: phone, icon: "phone.fill")
                    }
                    .buttonStyle(.plain)
                    if person.emailAddress != nil { RowDivider() }
                }
                if let email = person.emailAddress {
                    Button {
                        if let url = URL(string: "mailto:\(email)") {
                            openURL(url) { accepted in
                                if !accepted { showingEmailFallback = true }
                            }
                        }
                    } label: {
                        kontaktRow(label: "E-Mail", value: email, icon: "envelope.fill")
                    }
                    .buttonStyle(.plain)
                }
            }
            .background(theme.surfaceCard)
            .clipShape(RoundedRectangle(cornerRadius: theme.radiusCard))
        }
    }

    private func kontaktRow(label: String, value: String, icon: String) -> some View {
        HStack(alignment: .top, spacing: 12) {
            Text(label)
                .font(.system(size: 13))
                .foregroundStyle(theme.contentTertiary)
                .frame(width: 88, alignment: .leading)
            Text(value)
                .font(.system(size: 15))
                .foregroundStyle(theme.contentPrimary)
                .fixedSize(horizontal: false, vertical: true)
            Spacer()
            Image(systemName: icon)
                .font(.system(size: 13, weight: .medium))
                .foregroundStyle(theme.accent)
        }
        .padding(.horizontal, 16)
        .padding(.vertical, 12)
    }

    // MARK: - Momente

    /// Aktive Momente: offene Vorhaben + noch ausstehende Treffen in der Zukunft.
    private var activeMoments: [Moment] {
        person.sortedMoments.filter { $0.isOpen || ($0.isMeeting && $0.createdAt > Date()) }
    }

    /// Was in der Momente-Sektion angezeigt wird: aktive + kurzzeitig sichtbare neue Logbuch-Momente.
    private var visibleMoments: [Moment] {
        let fadingIDs = Set(fadingOutMoments.map(\.id))
        let active = activeMoments.filter { !fadingIDs.contains($0.id) }
        return active + fadingOutMoments
    }

    /// Startet den 5-s-Ausblend-Timer für die angegebenen Momente.
    private func scheduleFadeOut(_ moments: [Moment]) {
        for moment in moments {
            DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
                withAnimation(.easeOut(duration: 0.35)) {
                    fadingOutMoments.removeAll { $0.id == moment.id }
                }
            }
        }
    }

    private var momentsSection: some View {
        VStack(alignment: .leading, spacing: 10) {
            HStack {
                SectionHeader(title: "Momente", icon: "clock")
                Spacer()
                Button {
                    showingAddMoment = true
                } label: {
                    HStack(spacing: 4) {
                        Image(systemName: "plus")
                            .font(.system(size: 11, weight: .medium))
                        Text("Moment")
                            .font(.system(size: 13, weight: .medium))
                    }
                    .foregroundStyle(theme.accent)
                    .padding(.horizontal, 10)
                    .padding(.vertical, 5)
                    .background(theme.accent.opacity(0.10))
                    .clipShape(Capsule())
                }
                .tourTarget(.addMomentButton)
            }

            if person.sortedMoments.isEmpty {
                Text("Noch nichts festgehalten. Dein nächstes Gespräch kann hier beginnen.")
                    .font(.system(size: 14))
                    .foregroundStyle(theme.contentTertiary)
                    .padding(.vertical, 4)
            } else if !visibleMoments.isEmpty {
                VStack(spacing: 0) {
                    ForEach(Array(visibleMoments.enumerated()), id: \.element.id) { index, moment in
                        VStack(spacing: 0) {
                            MomentRowView(
                                moment: moment,
                                onRateMeeting: { momentForRating = moment },
                                onAftermathMeeting: { momentForAftermath = moment },
                                onViewSummary: { momentForSummary = moment },
                                onEditMeeting: { momentForEdit = moment },
                                onToggleIntention: { toggleIntention(moment) },
                                onEdit: { momentForTextEdit = moment },
                                onToggleImportant: { toggleImportant(moment) }
                            )
                            .opacity(fadingOutMoments.contains(where: { $0.id == moment.id }) ? 0.45 : 1.0)
                            if index < visibleMoments.count - 1 { RowDivider() }
                        }
                    }
                }
                .background(theme.surfaceCard)
                .clipShape(RoundedRectangle(cornerRadius: theme.radiusCard))
            }
        }
    }

    // MARK: - Logbuch Vorschau

    private let logbuchPreviewLimit = 5

    // Lokaler Hilfstyp für die gemischte Vorschau
    private struct LogPreviewItem: Identifiable {
        let id: String
        let icon: String
        let title: String
        let typeLabel: String
        let date: Date
    }

    private var mergedLogPreview: [LogPreviewItem] {
        // Nur Momente die weder aktiv (offene Vorhaben / Zukunftstreffen) noch gerade sichtbar ausklingend sind
        let activeIDs = Set(activeMoments.map(\.id))
        let fadingIDs = Set(fadingOutMoments.map(\.id))
        let logbuchMoments = person.sortedMoments.filter {
            !activeIDs.contains($0.id) && !fadingIDs.contains($0.id)
        }
        let momentItems = logbuchMoments.map {
            LogPreviewItem(id: "m-\($0.id)", icon: $0.type.icon, title: $0.text,
                           typeLabel: $0.type.displayName, date: $0.createdAt)
        }
        let entryItems = person.sortedLogEntries.map {
            LogPreviewItem(id: "e-\($0.id)", icon: $0.type.icon, title: $0.title,
                           typeLabel: $0.type.rawValue, date: $0.loggedAt)
        }
        return (momentItems + entryItems).sorted { $0.date > $1.date }
    }

    private var logbuchSection: some View {
        let allItems = mergedLogPreview
        let preview = Array(allItems.prefix(logbuchPreviewLimit))
        let hasMore = allItems.count > logbuchPreviewLimit

        return VStack(alignment: .leading, spacing: 10) {
            HStack {
                SectionHeader(title: "Verlauf", icon: "clock.arrow.circlepath")
                Spacer()
                NavigationLink(destination: LogbuchView(person: person)) {
                    Text("Alle")
                        .font(.system(size: 13))
                        .foregroundStyle(theme.accent)
                }
            }

            VStack(spacing: 0) {
                ForEach(Array(preview.enumerated()), id: \.element.id) { index, item in
                    logPreviewRow(item)
                    if index < preview.count - 1 || hasMore { RowDivider() }
                }
                if hasMore {
                    NavigationLink(destination: LogbuchView(person: person)) {
                        HStack {
                            Text("Alle \(allItems.count) Einträge anzeigen")
                                .font(.system(size: 14))
                                .foregroundStyle(theme.accent)
                            Spacer()
                            Image(systemName: "chevron.right")
                                .font(.system(size: 12, weight: .medium))
                                .foregroundStyle(theme.contentTertiary)
                        }
                        .padding(.horizontal, 16)
                        .padding(.vertical, 12)
                    }
                }
            }
            .background(theme.surfaceCard)
            .clipShape(RoundedRectangle(cornerRadius: theme.radiusCard))
        }
    }

    private func logPreviewRow(_ item: LogPreviewItem) -> some View {
        HStack(spacing: 12) {
            Image(systemName: item.icon)
                .font(.system(size: 14, weight: .light))
                .foregroundStyle(theme.accent)
                .frame(width: 20)

            VStack(alignment: .leading, spacing: 3) {
                Text(item.title)
                    .font(.system(size: 15, design: theme.displayDesign))
                    .foregroundStyle(theme.contentPrimary)
                    .lineLimit(2)
                    .fixedSize(horizontal: false, vertical: true)

                HStack(spacing: 6) {
                    Text(LocalizedStringKey(item.typeLabel))
                        .font(.system(size: 12))
                        .foregroundStyle(theme.contentTertiary)
                    Text("·")
                        .font(.system(size: 12))
                        .foregroundStyle(theme.contentTertiary)
                    Text(item.date.formatted(.dateTime.day().month(.abbreviated).year()))
                        .font(.system(size: 12))
                        .foregroundStyle(theme.contentTertiary)
                }
            }

            Spacer()
        }
        .padding(.horizontal, 16)
        .padding(.vertical, 12)
    }

    // MARK: - Info

    private var hasInfoContent: Bool {
        person.birthday != nil
        || !(person.location ?? "").isEmpty
        || !(person.interests ?? "").isEmpty
        || !(person.culturalBackground ?? "").isEmpty
        || !(person.generalNotes ?? "").isEmpty
    }

    private var infoSection: some View {
        VStack(alignment: .leading, spacing: 10) {
            SectionHeader(title: "Über \(person.firstName)", icon: "person")

            VStack(spacing: 0) {
                if let birthday = person.birthday {
                    InfoRowView(
                        label: "Geburtstag",
                        value: birthday.formatted(.dateTime.day().month(.wide).year().locale(Locale(identifier: "de_DE")))
                    )
                    RowDivider()
                }
                if let loc = person.location, !loc.isEmpty {
                    InfoRowView(label: "Wohnort", value: loc)
                    RowDivider()
                }
                if let interests = person.interests, !interests.isEmpty {
                    InterestChipRow(label: "Interessen", text: interests, color: .green)
                    RowDivider()
                }
                if let bg = person.culturalBackground, !bg.isEmpty {
                    InfoRowView(label: "Herkunft", value: bg)
                    RowDivider()
                }
                if let notes = person.generalNotes, !notes.isEmpty {
                    InfoRowView(label: "Notizen", value: notes)
                }
            }
            .background(theme.surfaceCard)
            .clipShape(RoundedRectangle(cornerRadius: theme.radiusCard))
        }
    }

    // MARK: - Aktionen

    private func deleteMoment(_ moment: Moment) {
        // Prüfen ob ein Kalendereintrag verknüpft ist → ggf. Bestätigung anfordern
        if CalendarEventStore.identifier(for: moment.id) != nil {
            momentPendingDelete = moment
            showCalendarDeleteDialog = true
        } else {
            performDelete(moment, deleteCalendarEvent: false)
        }
    }

    private func performDelete(_ moment: Moment, deleteCalendarEvent: Bool) {
        let momentID = moment.id
        if deleteCalendarEvent, let eventID = CalendarEventStore.identifier(for: momentID) {
            Task {
                _ = await CalendarManager.shared.deleteEvent(identifier: eventID)
                CalendarEventStore.remove(momentID: momentID)
            }
        } else {
            CalendarEventStore.remove(momentID: momentID)
        }
        modelContext.delete(moment)
        person.touch()
    }

    private func toggleImportant(_ moment: Moment) {
        moment.isImportant.toggle()
        moment.updatedAt = Date()
    }

    // MARK: - Todos

    /// Offene Todos + gerade abgehakte (noch ausblendend).
    private var visibleTodos: [Todo] {
        let fadingIDs = Set(fadingOutTodos.map(\.id))
        return person.openTodos.filter { !fadingIDs.contains($0.id) } + fadingOutTodos
    }

    private var todosSection: some View {
        VStack(alignment: .leading, spacing: 10) {
            HStack {
                SectionHeader(title: "Todos", icon: "checkmark.circle")
                Spacer()
                Button {
                    showingAddTodo = true
                } label: {
                    HStack(spacing: 4) {
                        Image(systemName: "plus")
                            .font(.system(size: 11, weight: .medium))
                        Text("Todo")
                            .font(.system(size: 13, weight: .medium))
                    }
                    .foregroundStyle(theme.accent)
                    .padding(.horizontal, 10)
                    .padding(.vertical, 5)
                    .background(theme.accent.opacity(0.10))
                    .clipShape(Capsule())
                }
                .tourTarget(.addTodoButton)
            }

            if visibleTodos.isEmpty {
                Text("Noch keine Todos.")
                    .font(.system(size: 14))
                    .foregroundStyle(theme.contentTertiary)
                    .padding(.vertical, 4)
            } else {
                VStack(spacing: 0) {
                    ForEach(Array(visibleTodos.enumerated()), id: \.element.id) { index, todo in
                        TodoRowView(
                            todo: todo,
                            isLast: index == visibleTodos.count - 1,
                            onToggle: { toggleTodo(todo) },
                            onDelete: { deleteTodo(todo) },
                            onEdit: { todoForEdit = todo }
                        )
                    }
                }
                .background(theme.surfaceCard)
                .clipShape(RoundedRectangle(cornerRadius: theme.radiusCard))
            }
        }
    }

    private func toggleTodo(_ todo: Todo) {
        if !todo.isCompleted {
            // Sofort in Fade-out-Liste aufnehmen, damit der Eintrag sichtbar bleibt
            fadingOutTodos.append(todo)

            withAnimation(.spring(response: 0.3, dampingFraction: 0.75)) {
                todo.isCompleted = true
                todo.completedAt = Date()
            }
            UNUserNotificationCenter.current()
                .removePendingNotificationRequests(withIdentifiers: ["todo-\(todo.id)"])

            // Logbuch-Eintrag erstellen
            let entry = LogEntry(type: .todoCompleted, title: todo.title, person: person)
            modelContext.insert(entry)
            person.logEntries?.append(entry)

            // Nach 5 Sek. sanft ausblenden
            DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
                withAnimation(.easeOut(duration: 0.35)) {
                    fadingOutTodos.removeAll { $0.id == todo.id }
                }
            }
        } else {
            withAnimation(.spring(response: 0.3, dampingFraction: 0.75)) {
                todo.isCompleted = false
                todo.completedAt = nil
            }
        }
        person.touch()
        do {
            try modelContext.save()
        } catch {
            AppEventLog.shared.record(
                "Fehler beim Abhaken des Todos: \(error.localizedDescription)",
                level: .error, category: "Todo"
            )
        }
    }

    private func deleteTodo(_ todo: Todo) {
        UNUserNotificationCenter.current()
            .removePendingNotificationRequests(withIdentifiers: ["todo-\(todo.id)"])
        modelContext.delete(todo)
        person.touch()
    }

    private func toggleIntention(_ moment: Moment) {
        guard moment.isIntention else { return }
        withAnimation(.spring(response: 0.3, dampingFraction: 0.75)) {
            if !moment.isCompleted {
                // Vorhaben abhaken: LogEntry erstellen
                moment.isCompleted = true
                moment.updatedAt = Date()
                let entry = LogEntry(type: .nextStep, title: moment.text, person: person)
                modelContext.insert(entry)
                person.logEntries?.append(entry)
                // Erinnerung abbrechen falls vorhanden
                if moment.reminderDate != nil {
                    UNUserNotificationCenter.current()
                        .removePendingNotificationRequests(withIdentifiers: ["intention-\(moment.id)"])
                }
            } else {
                moment.isCompleted = false
                moment.updatedAt = Date()
            }
        }
        do {
            try modelContext.save()
        } catch {
            AppEventLog.shared.record(
                "Fehler beim Abhaken des Vorhabens: \(error.localizedDescription)",
                level: .error, category: "Intention"
            )
        }
    }
}

// MARK: - Deletable Moment Row
// Links wischen  → Löschen (rot)
// MARK: - Todo Row

private struct TodoRowView: View {
    @Environment(\.nahbarTheme) var theme
    let todo: Todo
    let isLast: Bool
    let onToggle: () -> Void
    let onDelete: () -> Void
    let onEdit: () -> Void

    var body: some View {
        VStack(spacing: 0) {
            HStack(alignment: .top, spacing: 12) {
                Button { onToggle() } label: {
                    Image(systemName: todo.isCompleted ? "checkmark.circle.fill" : "circle")
                        .font(.system(size: 20))
                        .foregroundStyle(todo.isCompleted ? Color.green : theme.contentTertiary)
                        .padding(.top, 1)
                }
                .buttonStyle(.plain)

                Button { onEdit() } label: {
                    VStack(alignment: .leading, spacing: 4) {
                        Text(todo.title)
                            .font(.system(size: 15, design: theme.displayDesign))
                            .foregroundStyle(todo.isCompleted ? theme.contentTertiary : theme.contentPrimary)
                            .strikethrough(todo.isCompleted, color: theme.contentTertiary)
                            .fixedSize(horizontal: false, vertical: true)

                        HStack(spacing: 6) {
                            Label(
                                todo.dueDate.formatted(.dateTime.day().month(.abbreviated).year().locale(Locale.current)),
                                systemImage: "calendar"
                            )
                            .font(.system(size: 12))
                            .foregroundStyle(isOverdue ? .red : theme.contentTertiary)

                            // Erinnerungs-Indikator
                            if let reminder = todo.reminderDate, !todo.isCompleted {
                                Label(
                                    reminder.formatted(.dateTime.day().month(.abbreviated).hour().minute().locale(Locale.current)),
                                    systemImage: "bell"
                                )
                                .font(.system(size: 12))
                                .foregroundStyle(theme.accent.opacity(0.8))
                            }
                        }
                    }
                    .frame(maxWidth: .infinity, alignment: .leading)
                }
                .buttonStyle(.plain)
            }
            .padding(.horizontal, 16)
            .padding(.vertical, 12)
            .opacity(todo.isCompleted ? 0.55 : 1.0)

            if !isLast { RowDivider() }
        }
        .swipeActions(edge: .leading) {
            Button { onEdit() } label: {
                Label("Bearbeiten", systemImage: "pencil")
            }
            .tint(theme.accent)
        }
        .swipeActions(edge: .trailing, allowsFullSwipe: true) {
            Button(role: .destructive) { onDelete() } label: {
                Label("Löschen", systemImage: "trash")
            }
        }
    }

    private var isOverdue: Bool {
        !todo.isCompleted && todo.dueDate < Calendar.current.startOfDay(for: Date())
    }
}

// MARK: - Moment Row

struct MomentRowView: View {
    @Environment(\.nahbarTheme) var theme
    let moment: Moment

    // Callbacks für typ-spezifische Aktionen (nur in PersonDetailView relevant)
    var onRateMeeting: (() -> Void)? = nil
    var onAftermathMeeting: (() -> Void)? = nil
    var onViewSummary: (() -> Void)? = nil
    var onEditMeeting: (() -> Void)? = nil
    var onToggleIntention: (() -> Void)? = nil
    var onEdit: (() -> Void)? = nil
    var onToggleImportant: (() -> Void)? = nil

    /// Wird lokal gecacht, damit die Ansicht auf CalendarEventStore-Änderungen reagieren kann.
    @State private var hasCalendarEvent = false

    var body: some View {
        Group {
            switch moment.type {
            case .meeting:   meetingRow
            case .intention: intentionRow
            default:         standardRow
            }
        }
        .onAppear {
            hasCalendarEvent = CalendarEventStore.identifier(for: moment.id) != nil
        }
        .onReceive(NotificationCenter.default.publisher(for: CalendarEventStore.didChangeNotification)) { n in
            guard (n.object as? UUID) == moment.id else { return }
            hasCalendarEvent = CalendarEventStore.identifier(for: moment.id) != nil
        }
    }

    // MARK: Standard-Zeile (Gespräch, Gedanke)

    private var standardRow: some View {
        HStack(alignment: .top, spacing: 12) {
            typeIcon
            Button { onEdit?() } label: {
                momentContent
                    .frame(maxWidth: .infinity, alignment: .leading)
            }
            .buttonStyle(.plain)
            starButton
        }
        .padding(.horizontal, 16)
        .padding(.vertical, 12)
    }

    // MARK: Treffen-Zeile

    private var meetingRow: some View {
        VStack(alignment: .leading, spacing: 8) {
            HStack(alignment: .top, spacing: 12) {
                typeIcon
                Button { onEdit?() } label: {
                    momentContent
                        .frame(maxWidth: .infinity, alignment: .leading)
                }
                .buttonStyle(.plain)
                starButton
                // Score-Badge oder Bearbeiten-Button
                if let avg = moment.immediateAverage {
                    Button { onViewSummary?() } label: {
                        scoreBadge(avg)
                    }
                    .buttonStyle(.plain)
                }
            }

            // Aktions-Zeile
            HStack(spacing: 8) {
                Spacer().frame(width: 30)  // Einrückung für Typ-Icon

                if moment.meetingStatus == nil || (moment.ratings ?? []).isEmpty {
                    // Noch nicht bewertet
                    Button { onRateMeeting?() } label: {
                        Label("Bewerten", systemImage: "star")
                            .font(.system(size: 12, weight: .medium))
                            .foregroundStyle(theme.accent)
                            .padding(.horizontal, 10)
                            .padding(.vertical, 5)
                            .background(theme.accent.opacity(0.1))
                            .clipShape(Capsule())
                    }
                } else if moment.meetingStatus == .awaitingAftermath {
                    // Nachwirkung ausstehend
                    Button { onAftermathMeeting?() } label: {
                        Label("Nachwirkung", systemImage: "moon.stars")
                            .font(.system(size: 12, weight: .medium))
                            .foregroundStyle(.purple)
                            .padding(.horizontal, 10)
                            .padding(.vertical, 5)
                            .background(Color.purple.opacity(0.1))
                            .clipShape(Capsule())
                    }
                    // Bewertung bearbeiten
                    Button { onEditMeeting?() } label: {
                        Image(systemName: "pencil")
                            .font(.system(size: 12))
                            .foregroundStyle(theme.contentTertiary)
                    }
                } else if moment.isMeetingComplete {
                    // Abgeschlossen – nur bearbeiten
                    Button { onEditMeeting?() } label: {
                        Label("Bearbeiten", systemImage: "pencil")
                            .font(.system(size: 12, weight: .medium))
                            .foregroundStyle(theme.contentTertiary)
                            .padding(.horizontal, 10)
                            .padding(.vertical, 5)
                            .background(theme.contentTertiary.opacity(0.08))
                            .clipShape(Capsule())
                    }
                }

                Spacer()
            }
            .padding(.bottom, 4)
        }
        .padding(.horizontal, 16)
        .padding(.top, 12)
        .padding(.bottom, 8)
    }

    // MARK: Vorhaben-Zeile

    private var intentionRow: some View {
        HStack(alignment: .top, spacing: 12) {
            // Checkbox
            Button { onToggleIntention?() } label: {
                Image(systemName: moment.isCompleted ? "checkmark.circle.fill" : "circle")
                    .font(.system(size: 20))
                    .foregroundStyle(moment.isCompleted ? Color.green : theme.contentTertiary)
                    .padding(.top, 1)
            }
            .buttonStyle(.plain)

            Button { onEdit?() } label: {
                VStack(alignment: .leading, spacing: 4) {
                    Text(moment.text)
                        .font(.system(size: 15, design: theme.displayDesign))
                        .foregroundStyle(moment.isCompleted ? theme.contentTertiary : theme.contentPrimary)
                        .strikethrough(moment.isCompleted, color: theme.contentTertiary)
                        .fixedSize(horizontal: false, vertical: true)

                    HStack(spacing: 6) {
                        if let reminder = moment.reminderDate, !moment.isCompleted {
                            Label(
                                reminder.formatted(.dateTime.day().month(.abbreviated).hour().minute().locale(Locale.current)),
                                systemImage: "bell"
                            )
                            .font(.system(size: 12))
                            .foregroundStyle(theme.accent.opacity(0.8))
                        } else {
                            Text(moment.createdAt, format: .dateTime.day().month(.abbreviated).year().locale(Locale(identifier: "de_DE")))
                                .font(.system(size: 12))
                                .foregroundStyle(theme.contentTertiary)
                        }
                    }
                }
                .frame(maxWidth: .infinity, alignment: .leading)
            }
            .buttonStyle(.plain)

            starButton
        }
        .padding(.horizontal, 16)
        .padding(.vertical, 12)
        .opacity(moment.isCompleted ? 0.55 : 1.0)
    }

    // MARK: - Gemeinsame Elemente

    private var typeIcon: some View {
        ZStack(alignment: .bottomTrailing) {
            Image(systemName: moment.type.icon)
                .font(.system(size: 13, weight: .light))
                .foregroundStyle(theme.contentTertiary)
                .frame(width: 18)
                .padding(.top, 2)

            if let source = moment.source {
                Image(systemName: source.icon)
                    .font(.system(size: 8, weight: .semibold))
                    .foregroundStyle(.white)
                    .padding(2)
                    .background(sourceColor(source))
                    .clipShape(Circle())
                    .offset(x: 5, y: 4)
            }
        }
        .frame(width: 18)
        .padding(.top, 2)
    }

    private var starButton: some View {
        Button { onToggleImportant?() } label: {
            Image(systemName: moment.isImportant ? "star.fill" : "star")
                .font(.system(size: 15))
                .foregroundStyle(moment.isImportant ? Color.orange : theme.contentTertiary.opacity(0.4))
        }
        .buttonStyle(.plain)
        .padding(.top, 1)
    }

    private var momentContent: some View {
        VStack(alignment: .leading, spacing: 4) {
            Text(moment.text)
                .font(.system(size: 15, design: theme.displayDesign))
                .foregroundStyle(theme.contentPrimary)
                .fixedSize(horizontal: false, vertical: true)

            HStack(spacing: 6) {
                if hasCalendarEvent {
                    Image(systemName: "calendar")
                        .font(.system(size: 10))
                        .foregroundStyle(theme.contentTertiary)
                }
                Text(moment.createdAt, format: .dateTime.day().month(.abbreviated).year().locale(Locale(identifier: "de_DE")))
                    .font(.system(size: 12))
                    .foregroundStyle(theme.contentTertiary)

                if let source = moment.source {
                    Text("·")
                        .font(.system(size: 12))
                        .foregroundStyle(theme.contentTertiary)
                    Text(source.rawValue)
                        .font(.system(size: 12))
                        .foregroundStyle(sourceColor(source).opacity(0.8))
                }
            }
        }
    }

    private func scoreBadge(_ value: Double) -> some View {
        ZStack {
            Circle()
                .fill(scoreColor(value).opacity(0.15))
                .frame(width: 34, height: 34)
            Text(String(format: "%.1f", value))
                .font(.system(size: 10, weight: .bold))
                .foregroundStyle(scoreColor(value))
        }
    }

    private func scoreColor(_ value: Double) -> Color {
        switch value {
        case ..<(-0.5): return .red
        case (-0.5)..<(0.5): return Color(.systemGray3)
        case (0.5)...: return .green
        default: return .gray
        }
    }

    private func sourceColor(_ source: MomentSource) -> Color {
        switch source {
        case .whatsapp: return Color(red: 0.15, green: 0.80, blue: 0.33)
        case .imessage: return Color(red: 0.0,  green: 0.48, blue: 1.0)
        case .telegram: return Color(red: 0.17, green: 0.67, blue: 0.94)
        case .signal:   return Color(red: 0.23, green: 0.47, blue: 0.95)
        case .other:    return Color.gray
        }
    }
}

// MARK: - Edit Moment View

struct EditMomentView: View {
    @Environment(\.nahbarTheme) var theme
    @Environment(\.modelContext) var modelContext
    @Environment(\.dismiss) var dismiss

    let moment: Moment

    @State private var text: String
    @State private var createdAt: Date
    @State private var showDeleteConfirm = false
    @State private var showCalendarDeleteConfirm = false
    @FocusState private var isFocused: Bool

    init(moment: Moment) {
        self.moment = moment
        self._text      = State(initialValue: moment.text)
        self._createdAt = State(initialValue: moment.createdAt)
    }

    private var isValid: Bool { !text.trimmingCharacters(in: .whitespaces).isEmpty }

    var body: some View {
        NavigationStack {
            VStack(alignment: .leading, spacing: 16) {

                // Zeitpunkt
                VStack(spacing: 0) {
                    DatePicker(
                        "Zeitpunkt",
                        selection: $createdAt,
                        displayedComponents: [.date, .hourAndMinute]
                    )
                    .font(.system(size: 15))
                    .foregroundStyle(theme.contentPrimary)
                    .tint(theme.accent)
                    .environment(\.locale, Locale.current)
                    .padding(.horizontal, 16)
                    .padding(.vertical, 10)
                }
                .background(theme.surfaceCard)
                .clipShape(RoundedRectangle(cornerRadius: theme.radiusCard))
                .padding(.horizontal, 20)

                // Text
                ZStack(alignment: .topLeading) {
                    if text.isEmpty {
                        Text("Moment…")
                            .font(.system(size: 16))
                            .foregroundStyle(theme.contentTertiary)
                            .padding(.horizontal, 16)
                            .padding(.vertical, 14)
                            .allowsHitTesting(false)
                    }
                    TextEditor(text: $text)
                        .font(.system(size: 16, design: theme.displayDesign))
                        .foregroundStyle(theme.contentPrimary)
                        .tint(theme.accent)
                        .scrollContentBackground(.hidden)
                        .padding(.horizontal, 12)
                        .padding(.vertical, 10)
                        .focused($isFocused)
                }
                .frame(minHeight: 180)
                .background(theme.surfaceCard)
                .clipShape(RoundedRectangle(cornerRadius: theme.radiusCard))
                .padding(.horizontal, 20)

                // Löschen-Button
                Button {
                    if CalendarEventStore.identifier(for: moment.id) != nil {
                        showCalendarDeleteConfirm = true
                    } else {
                        showDeleteConfirm = true
                    }
                } label: {
                    Label("Moment löschen", systemImage: "trash")
                        .font(.system(size: 15))
                        .foregroundStyle(.red)
                        .frame(maxWidth: .infinity)
                        .padding(.vertical, 14)
                        .background(Color.red.opacity(0.08))
                        .clipShape(RoundedRectangle(cornerRadius: theme.radiusCard))
                }
                .padding(.horizontal, 20)

                Spacer()
            }
            .padding(.top, 16)
            .background(theme.backgroundPrimary.ignoresSafeArea())
            .navigationTitle("Moment bearbeiten")
            .navigationBarTitleDisplayMode(.inline)
            .themedNavBar()
            .toolbar {
                ToolbarItem(placement: .topBarLeading) {
                    Button("Abbrechen") { dismiss() }
                        .foregroundStyle(theme.contentSecondary)
                }
                ToolbarItem(placement: .topBarTrailing) {
                    Button("Fertig") { save() }
                        .font(.system(size: 15, weight: .semibold))
                        .foregroundStyle(isValid ? theme.accent : theme.contentTertiary)
                        .disabled(!isValid)
                }
            }
        }
        .onAppear { isFocused = true }
        .confirmationDialog("Moment löschen?", isPresented: $showDeleteConfirm, titleVisibility: .visible) {
            Button("Löschen", role: .destructive) { delete(deleteCalendarEvent: false) }
            Button("Abbrechen", role: .cancel) {}
        } message: {
            Text("Dieser Moment wird unwiderruflich gelöscht.")
        }
        .confirmationDialog("Moment mit Kalendereintrag löschen?", isPresented: $showCalendarDeleteConfirm, titleVisibility: .visible) {
            Button("Moment + Kalendereintrag löschen", role: .destructive) { delete(deleteCalendarEvent: true) }
            Button("Nur Moment löschen", role: .destructive) { delete(deleteCalendarEvent: false) }
            Button("Abbrechen", role: .cancel) {}
        }
    }

    private func delete(deleteCalendarEvent: Bool) {
        let momentID = moment.id
        if deleteCalendarEvent, let eventID = CalendarEventStore.identifier(for: momentID) {
            Task {
                _ = await CalendarManager.shared.deleteEvent(identifier: eventID)
                CalendarEventStore.remove(momentID: momentID)
            }
        } else {
            CalendarEventStore.remove(momentID: momentID)
        }
        moment.person?.touch()
        modelContext.delete(moment)
        do { try modelContext.save() } catch {
            AppEventLog.shared.record(
                "Fehler beim Löschen des Moments: \(error.localizedDescription)",
                level: .error, category: "Moment"
            )
        }
        dismiss()
    }

    private func save() {
        let trimmed = text.trimmingCharacters(in: .whitespaces)
        guard !trimmed.isEmpty else { return }
        moment.text      = trimmed
        moment.createdAt = createdAt
        moment.updatedAt = Date()
        moment.person?.touch()
        do {
            try modelContext.save()
        } catch {
            AppEventLog.shared.record(
                "Fehler beim Bearbeiten des Moments: \(error.localizedDescription)",
                level: .error, category: "Moment"
            )
        }
        // Verknüpften Kalendereintrag aktualisieren, falls vorhanden
        if let eventID = CalendarEventStore.identifier(for: moment.id) {
            let firstName = moment.person?.firstName ?? ""
            let title = String.localizedStringWithFormat(String(localized: "Treffen mit %@"), firstName)
            let savedDate = createdAt
            Task {
                await CalendarManager.shared.updateEvent(
                    identifier: eventID,
                    title: title,
                    notes: trimmed,
                    newStartDate: savedDate
                )
            }
        }
        dismiss()
    }
}

// MARK: - Edit Todo View

struct EditTodoView: View {
    @Environment(\.nahbarTheme) var theme
    @Environment(\.modelContext) var modelContext
    @Environment(\.dismiss) var dismiss

    let todo: Todo

    @State private var title: String
    @State private var dueDate: Date
    @State private var addReminder: Bool
    @State private var reminderDate: Date
    @FocusState private var isFocused: Bool

    init(todo: Todo) {
        self.todo = todo
        self._title      = State(initialValue: todo.title)
        self._dueDate    = State(initialValue: todo.dueDate)
        self._addReminder = State(initialValue: todo.reminderDate != nil)
        self._reminderDate = State(initialValue: todo.reminderDate ?? AddTodoView.defaultReminderDate(for: todo.dueDate))
    }

    private var isValid: Bool { !title.trimmingCharacters(in: .whitespaces).isEmpty }

    var body: some View {
        NavigationStack {
            ScrollView {
                VStack(alignment: .leading, spacing: 16) {

                    // Titel-Eingabe
                    ZStack(alignment: .topLeading) {
                        if title.isEmpty {
                            Text("Was möchtest du erledigen?")
                                .font(.system(size: 16))
                                .foregroundStyle(theme.contentTertiary)
                                .padding(.horizontal, 16)
                                .padding(.vertical, 14)
                                .allowsHitTesting(false)
                        }
                        TextEditor(text: $title)
                            .font(.system(size: 16, design: theme.displayDesign))
                            .foregroundStyle(theme.contentPrimary)
                            .tint(theme.accent)
                            .scrollContentBackground(.hidden)
                            .padding(.horizontal, 12)
                            .padding(.vertical, 10)
                            .focused($isFocused)
                    }
                    .frame(minHeight: 100)
                    .background(theme.surfaceCard)
                    .clipShape(RoundedRectangle(cornerRadius: theme.radiusCard))
                    .padding(.horizontal, 20)

                    // Fälligkeitsdatum + Erinnerung
                    VStack(spacing: 0) {
                        DatePicker(
                            "Fällig am",
                            selection: $dueDate,
                            displayedComponents: .date
                        )
                        .font(.system(size: 15))
                        .foregroundStyle(theme.contentPrimary)
                        .tint(theme.accent)
                        .environment(\.locale, Locale.current)
                        .padding(.horizontal, 16)
                        .padding(.vertical, 10)

                        RowDivider()

                        HStack {
                            Image(systemName: "bell")
                                .font(.system(size: 14))
                                .foregroundStyle(addReminder ? theme.accent : theme.contentTertiary)
                            Text("Erinnerung setzen")
                                .font(.system(size: 15))
                                .foregroundStyle(theme.contentPrimary)
                            Spacer()
                            Toggle("", isOn: $addReminder)
                                .tint(theme.accent)
                        }
                        .padding(.horizontal, 16)
                        .padding(.vertical, 12)

                        if addReminder {
                            RowDivider()
                            DatePicker(
                                "Wann?",
                                selection: $reminderDate,
                                in: Date()...,
                                displayedComponents: [.date, .hourAndMinute]
                            )
                            .font(.system(size: 15))
                            .foregroundStyle(theme.contentPrimary)
                            .tint(theme.accent)
                            .environment(\.locale, Locale.current)
                            .padding(.horizontal, 16)
                            .padding(.vertical, 10)
                        }
                    }
                    .background(theme.surfaceCard)
                    .clipShape(RoundedRectangle(cornerRadius: theme.radiusCard))
                    .padding(.horizontal, 20)
                    .animation(.easeInOut(duration: 0.2), value: addReminder)

                    Spacer(minLength: 40)
                }
                .padding(.top, 16)
            }
            .background(theme.backgroundPrimary.ignoresSafeArea())
            .navigationTitle("Todo bearbeiten")
            .navigationBarTitleDisplayMode(.inline)
            .themedNavBar()
            .toolbar {
                ToolbarItem(placement: .topBarLeading) {
                    Button("Abbrechen") { dismiss() }
                        .foregroundStyle(theme.contentSecondary)
                }
                ToolbarItem(placement: .topBarTrailing) {
                    Button("Fertig") { save() }
                        .font(.system(size: 15, weight: .semibold))
                        .foregroundStyle(isValid ? theme.accent : theme.contentTertiary)
                        .disabled(!isValid)
                }
            }
        }
        .onChange(of: dueDate) { _, newDue in
            reminderDate = AddTodoView.defaultReminderDate(for: newDue)
        }
        .onAppear { isFocused = true }
    }

    private func save() {
        let trimmed = title.trimmingCharacters(in: .whitespaces)
        guard !trimmed.isEmpty else { return }

        // Alte Erinnerung immer zuerst entfernen
        UNUserNotificationCenter.current()
            .removePendingNotificationRequests(withIdentifiers: ["todo-\(todo.id)"])

        todo.title   = trimmed
        todo.dueDate = dueDate
        todo.reminderDate = addReminder ? reminderDate : nil
        todo.person?.touch()

        if addReminder {
            scheduleReminder()
        }

        do {
            try modelContext.save()
        } catch {
            AppEventLog.shared.record(
                "Fehler beim Bearbeiten des Todos: \(error.localizedDescription)",
                level: .error, category: "Todo"
            )
        }
        dismiss()
    }

    private func scheduleReminder() {
        let center = UNUserNotificationCenter.current()
        center.requestAuthorization(options: [.alert, .sound]) { granted, error in
            if let error {
                todoNotificationLogger.error("Berechtigung-Fehler: \(error.localizedDescription)")
            }
            guard granted else {
                todoNotificationLogger.warning("Notification-Berechtigung abgelehnt – keine Todo-Erinnerung.")
                return
            }
            let content = UNMutableNotificationContent()
            content.title = todo.person?.firstName ?? ""
            content.subtitle = String(localized: "Dein Todo")
            content.body  = todo.title
            content.sound = .default
            content.userInfo = ["todoID": todo.id.uuidString]
            let components = Calendar.current.dateComponents(
                [.year, .month, .day, .hour, .minute], from: reminderDate
            )
            let trigger = UNCalendarNotificationTrigger(dateMatching: components, repeats: false)
            let request = UNNotificationRequest(
                identifier: "todo-\(todo.id)",
                content: content,
                trigger: trigger
            )
            center.add(request) { error in
                if let error {
                    todoNotificationLogger.error("Todo-Erinnerung konnte nicht geplant werden: \(error.localizedDescription)")
                } else {
                    todoNotificationLogger.info("Todo-Erinnerung geplant: \(todo.id.uuidString)")
                }
            }
        }
    }
}

// MARK: - AI Analysis Sheet

private struct AIAnalysisSheet: View {
    @Environment(\.nahbarTheme) var theme
    @Environment(\.dismiss) var dismiss
    @StateObject private var store = StoreManager.shared
    let person: Person

    @State private var analysisState: AnalysisState = .idle
    @State private var showAIConsent = false
    @State private var showPaywall = false
    @State private var remainingRequests: Int = AIAnalysisService.shared.remainingRequests
    @AppStorage("aiConsentGiven") private var aiConsentGiven = false

    private var canUseAI: Bool {
        store.isMax || AIAnalysisService.shared.hasFreeQueriesLeft
    }

    var body: some View {
        NavigationStack {
            ScrollView {
                VStack(alignment: .leading, spacing: 16) {
                    // Header mit MAX-Badge
                    HStack(spacing: 6) {
                        SectionHeader(title: "KI-Auswertung", icon: "sparkles")
                        MaxBadge()
                        if !store.isMax && canUseAI {
                            Text("\(AIAnalysisService.shared.freeQueriesRemaining) gratis")
                                .font(.system(size: 10, weight: .bold))
                                .foregroundStyle(theme.contentTertiary)
                                .padding(.horizontal, 7)
                                .padding(.vertical, 3)
                                .background(theme.backgroundSecondary)
                                .clipShape(Capsule())
                        }
                    }

                    // Inhalt
                    VStack(alignment: .leading, spacing: 0) {
                        switch analysisState {
                        case .idle:
                            Button {
                                if aiConsentGiven {
                                    Task { await runAnalysis() }
                                } else {
                                    showAIConsent = true
                                }
                            } label: {
                                HStack(spacing: 10) {
                                    Image(systemName: "sparkles")
                                        .foregroundStyle(theme.accent)
                                    Text("\(person.firstName) analysieren")
                                        .font(.system(size: 15, weight: .medium))
                                        .foregroundStyle(theme.contentPrimary)
                                    Spacer()
                                    Image(systemName: "chevron.right")
                                        .font(.system(size: 12))
                                        .foregroundStyle(theme.contentTertiary)
                                }
                                .padding(16)
                            }

                        case .loading:
                            HStack(spacing: 12) {
                                ProgressView().tint(theme.accent)
                                VStack(alignment: .leading, spacing: 2) {
                                    Text("Analysiere Logbuch…")
                                        .font(.system(size: 14))
                                        .foregroundStyle(theme.contentSecondary)
                                    Text("Das kann bis zu einer Minute dauern.")
                                        .font(.system(size: 12))
                                        .foregroundStyle(theme.contentTertiary)
                                }
                            }
                            .padding(16)

                        case .result(let result, let date):
                            VStack(alignment: .leading, spacing: 0) {
                                analysisSection(icon: "waveform.path", title: "Muster & Themen", text: result.patterns)
                                RowDivider()
                                analysisSection(icon: "person.2", title: "Beziehungsqualität", text: result.relationship)
                                RowDivider()
                                analysisSection(icon: "arrow.right.circle", title: "Empfehlung", text: result.recommendation)
                                RowDivider()
                                HStack(spacing: 0) {
                                    VStack(alignment: .leading, spacing: 1) {
                                        Text("Analysiert")
                                            .font(.system(size: 11))
                                            .foregroundStyle(theme.contentTertiary)
                                        Text(date.formatted(.dateTime.day().month(.abbreviated).hour().minute().locale(Locale.current)))
                                            .font(.system(size: 11))
                                            .foregroundStyle(theme.contentTertiary)
                                    }
                                    .padding(.leading, 16)
                                    .padding(.vertical, 12)

                                    Spacer()

                                    Button {
                                        Task { await runAnalysis() }
                                    } label: {
                                        HStack(spacing: 4) {
                                            Image(systemName: "arrow.clockwise")
                                                .font(.system(size: 12))
                                            Text(remainingRequests > 0
                                                 ? "Aktualisieren (\(remainingRequests))"
                                                 : "Limit erreicht")
                                                .font(.system(size: 13))
                                        }
                                        .foregroundStyle(remainingRequests > 0 ? theme.accent : theme.contentTertiary)
                                    }
                                    .disabled(remainingRequests == 0 || isAnalyzing)
                                    .padding(.trailing, 16)
                                    .padding(.vertical, 12)
                                }
                            }

                        case .error(let msg):
                            VStack(alignment: .leading, spacing: 8) {
                                Label("Analyse fehlgeschlagen", systemImage: "exclamationmark.triangle")
                                    .font(.system(size: 14, weight: .medium))
                                    .foregroundStyle(theme.contentSecondary)
                                Text(msg)
                                    .font(.system(size: 12))
                                    .foregroundStyle(theme.contentTertiary)
                                Button {
                                    Task { await runAnalysis() }
                                } label: {
                                    Text("Erneut versuchen")
                                        .font(.system(size: 13, weight: .medium))
                                        .foregroundStyle(theme.accent)
                                }
                            }
                            .padding(16)
                        }
                    }
                    .background(theme.surfaceCard)
                    .clipShape(RoundedRectangle(cornerRadius: theme.radiusCard))
                }
                .padding(20)
            }
            .background(theme.backgroundPrimary.ignoresSafeArea())
            .navigationTitle("KI Insights zu \(person.firstName)")
            .navigationBarTitleDisplayMode(.inline)
            .themedNavBar()
            .toolbar {
                ToolbarItem(placement: .cancellationAction) {
                    Button("Schließen") { dismiss() }
                        .foregroundStyle(theme.accent)
                }
            }
            .sheet(isPresented: $showAIConsent) {
                AIConsentSheet {
                    aiConsentGiven = true
                    Task { await runAnalysis() }
                }
            }
            .sheet(isPresented: $showPaywall) {
                PaywallView(targeting: .max)
            }
        }
        .onAppear {
            // Cache laden
            if let cached = AIAnalysisService.shared.loadCached(for: person) {
                analysisState = .result(cached.asResult, cached.analyzedAt)
            }
            remainingRequests = AIAnalysisService.shared.remainingRequests

            // Auto-start: kein Cache → direkt starten wenn möglich
            if case .idle = analysisState {
                if canUseAI && aiConsentGiven {
                    Task { await runAnalysis() }
                } else if canUseAI && !aiConsentGiven {
                    showAIConsent = true
                }
            }
        }
    }

    private func analysisSection(icon: String, title: String, text: String) -> some View {
        HStack(alignment: .top, spacing: 12) {
            Image(systemName: icon)
                .font(.system(size: 13))
                .foregroundStyle(theme.accent)
                .frame(width: 20)
                .padding(.top, 2)
            VStack(alignment: .leading, spacing: 6) {
                Text(title)
                    .font(.system(size: 13, weight: .semibold))
                    .foregroundStyle(theme.contentSecondary)
                Text(LocalizedStringKey(text))
                    .font(.system(size: 14, design: theme.displayDesign))
                    .foregroundStyle(theme.contentPrimary)
                    .fixedSize(horizontal: false, vertical: true)
            }
        }
        .padding(.horizontal, 16)
        .padding(.vertical, 12)
    }

    private var isAnalyzing: Bool {
        if case .loading = analysisState { return true }
        return false
    }

    private func runAnalysis() async {
        guard !AIAnalysisService.shared.isRateLimited else { return }
        analysisState = .loading
        do {
            let result = try await AIAnalysisService.shared.analyze(person: person)
            remainingRequests = AIAnalysisService.shared.remainingRequests
            if !store.isMax { AIAnalysisService.shared.consumeFreeQuery() }
            analysisState = .result(result, Date())
        } catch {
            if let cached = AIAnalysisService.shared.loadCached(for: person) {
                analysisState = .result(cached.asResult, cached.analyzedAt)
            } else {
                analysisState = .error(error.localizedDescription)
            }
        }
    }
}

// MARK: - Info Row

struct InfoRowView: View {
    @Environment(\.nahbarTheme) var theme
    let label: String
    let value: String

    var body: some View {
        HStack(alignment: .top, spacing: 12) {
            Text(label)
                .font(.system(size: 13))
                .foregroundStyle(theme.contentTertiary)
                .frame(width: 88, alignment: .leading)

            Text(value)
                .font(.system(size: 15))
                .foregroundStyle(theme.contentPrimary)
                .fixedSize(horizontal: false, vertical: true)

            Spacer()
        }
        .padding(.horizontal, 16)
        .padding(.vertical, 12)
    }
}
