import SwiftUI
import SwiftData

// MARK: - Enums

enum PersonTag: String, CaseIterable, Codable {
    case family = "Familie"
    case friends = "Freunde"
    case work = "Arbeit"
    case community = "Community"
    case other = "Andere"

    var icon: String {
        switch self {
        case .family:    return "house"
        case .friends:   return "person.2"
        case .work:      return "briefcase"
        case .community: return "person.3"
        case .other:     return "tag"
        }
    }
}

enum NudgeFrequency: String, CaseIterable, Codable {
    case never      = "Nie"
    case weekly     = "Wöchentlich"
    case biweekly   = "2 Wochen"
    case monthly    = "Monatlich"
    case quarterly  = "Quartalsweise"

    var days: Int? {
        switch self {
        case .never:     return nil
        case .weekly:    return 7
        case .biweekly:  return 14
        case .monthly:   return 30
        case .quarterly: return 90
        }
    }
}

enum MomentType: String, CaseIterable, Codable {
    case conversation = "Gespräch"
    case meeting      = "Treffen"
    case thought      = "Gedanke"
    case intention    = "Vorhaben"

    var icon: String {
        switch self {
        case .conversation: return "bubble.left"
        case .meeting:      return "person.2"
        case .thought:      return "lightbulb"
        case .intention:    return "arrow.right.circle"
        }
    }
}

enum MomentSource: String, CaseIterable, Codable {
    case whatsapp = "WhatsApp"
    case imessage = "iMessage"
    case telegram = "Telegram"
    case signal   = "Signal"
    case other    = "Chat"

    var icon: String {
        switch self {
        case .whatsapp: return "message.fill"
        case .imessage: return "message.fill"
        case .telegram: return "paperplane.fill"
        case .signal:   return "lock.circle.fill"
        case .other:    return "bubble.left.fill"
        }
    }
}

// MARK: - Person

@Model
class Person {
    var id: UUID = UUID()
    var name: String = ""
    var tagRaw: String = PersonTag.other.rawValue
    var birthday: Date?
    var occupation: String?
    var location: String?
    var interests: String?
    var generalNotes: String?
    var nudgeFrequencyRaw: String = NudgeFrequency.monthly.rawValue
    var photoData: Data?
    var nextStep: String?
    var nextStepCompleted: Bool = false
    var nextStepReminderDate: Date?
    var lastSuggestedForCall: Date?
    var createdAt: Date = Date()
    @Relationship(deleteRule: .cascade) var moments: [Moment]? = []
    @Relationship(deleteRule: .cascade) var logEntries: [LogEntry]? = []

    init(
        name: String,
        tag: PersonTag = .other,
        birthday: Date? = nil,
        occupation: String? = nil,
        location: String? = nil,
        interests: String? = nil,
        generalNotes: String? = nil,
        nudgeFrequency: NudgeFrequency = .monthly
    ) {
        self.id = UUID()
        self.name = name
        self.tagRaw = tag.rawValue
        self.birthday = birthday
        self.occupation = occupation
        self.location = location
        self.interests = interests
        self.generalNotes = generalNotes
        self.nudgeFrequencyRaw = nudgeFrequency.rawValue
        self.photoData = nil
        self.nextStep = nil
        self.nextStepCompleted = false
        self.nextStepReminderDate = nil
        self.lastSuggestedForCall = nil
        self.createdAt = Date()
        self.moments = []
        self.logEntries = []
    }

    var tag: PersonTag {
        get { PersonTag(rawValue: tagRaw) ?? .other }
        set { tagRaw = newValue.rawValue }
    }

    var nudgeFrequency: NudgeFrequency {
        get { NudgeFrequency(rawValue: nudgeFrequencyRaw) ?? .monthly }
        set { nudgeFrequencyRaw = newValue.rawValue }
    }

    var lastMomentDate: Date? {
        (moments ?? []).sorted { $0.createdAt > $1.createdAt }.first?.createdAt
    }

    var needsAttention: Bool {
        guard let days = nudgeFrequency.days else { return false }
        if let last = lastMomentDate {
            return Date().timeIntervalSince(last) > Double(days * 86400)
        }
        return Date().timeIntervalSince(createdAt) > Double(days * 86400)
    }

    func hasBirthdayWithin(days: Int) -> Bool {
        guard let birthday else { return false }
        let cal = Calendar.current
        let bdc = cal.dateComponents([.month, .day], from: birthday)
        guard let bMonth = bdc.month, let bDay = bdc.day else { return false }
        for offset in 0..<days {
            if let date = cal.date(byAdding: .day, value: offset, to: Date()) {
                let dc = cal.dateComponents([.month, .day], from: date)
                if dc.month == bMonth && dc.day == bDay { return true }
            }
        }
        return false
    }

    var initials: String {
        let parts = name.split(separator: " ")
        if parts.count >= 2 {
            return (parts[0].prefix(1) + parts[1].prefix(1)).uppercased()
        }
        return String(name.prefix(2)).uppercased()
    }

    var firstName: String {
        String(name.split(separator: " ").first ?? Substring(name))
    }

    var sortedMoments: [Moment] {
        (moments ?? []).sorted { $0.createdAt > $1.createdAt }
    }

    var sortedLogEntries: [LogEntry] {
        (logEntries ?? []).sorted { $0.loggedAt > $1.loggedAt }
    }
}

// MARK: - LogEntryType

enum LogEntryType: String, Codable {
    case nextStep      = "Schritt abgeschlossen"
    case calendarEvent = "Termin geplant"
    case call          = "Anruf"

    var icon: String {
        switch self {
        case .nextStep:      return "checkmark.circle.fill"
        case .calendarEvent: return "calendar.badge.checkmark"
        case .call:          return "phone.circle.fill"
        }
    }

    var color: String { // used for tinting in the view
        switch self {
        case .nextStep:      return "green"
        case .calendarEvent: return "blue"
        case .call:          return "accent"
        }
    }
}

// MARK: - LogEntry

@Model
class LogEntry {
    var id: UUID = UUID()
    var typeRaw: String = LogEntryType.nextStep.rawValue
    var title: String = ""
    var loggedAt: Date = Date()
    var person: Person?

    init(type: LogEntryType, title: String, person: Person? = nil) {
        self.id = UUID()
        self.typeRaw = type.rawValue
        self.title = title
        self.loggedAt = Date()
        self.person = person
    }

    var type: LogEntryType {
        get { LogEntryType(rawValue: typeRaw) ?? .nextStep }
        set { typeRaw = newValue.rawValue }
    }
}

// MARK: - Moment

@Model
class Moment {
    var id: UUID = UUID()
    var text: String = ""
    var typeRaw: String = MomentType.conversation.rawValue
    var sourceRaw: String? = nil
    var createdAt: Date = Date()
    var person: Person?

    init(text: String, type: MomentType = .conversation, source: MomentSource? = nil, person: Person? = nil) {
        self.id = UUID()
        self.text = text
        self.typeRaw = type.rawValue
        self.sourceRaw = source?.rawValue
        self.createdAt = Date()
        self.person = person
    }

    var type: MomentType {
        get { MomentType(rawValue: typeRaw) ?? .conversation }
        set { typeRaw = newValue.rawValue }
    }

    var source: MomentSource? {
        get { sourceRaw.flatMap { MomentSource(rawValue: $0) } }
        set { sourceRaw = newValue?.rawValue }
    }
}
