import SwiftUI
import SwiftData
import Foundation

struct SymptomRange: Identifiable, Hashable {
    let id: String
    let name: String
    let startDay: Date
    let endDay: Date
    let severity: Int
    let isOngoing: Bool

    var color: Color {
        switch severity {
        case 1, 2: return Tj.Palette.leaf
        case 3:    return Tj.Palette.amber
        default:   return Tj.Palette.brick
        }
    }

    func contains(_ day: Date, calendar: Calendar = .current) -> Bool {
        let d = calendar.startOfDay(for: day)
        return d >= startDay && d <= endDay
    }

    func position(_ day: Date, calendar: Calendar = .current) -> Position {
        let d = calendar.startOfDay(for: day)
        let isStart = d == startDay
        let isEnd = d == endDay
        if isStart && isEnd { return .single }
        if isStart { return .start }
        if isEnd { return .end }
        return .middle
    }

    enum Position { case single, start, middle, end }
}

struct DayMarks: Hashable {
    var abnormalCount: Int = 0
    var normalCount: Int = 0
    var reportCount: Int = 0
    var diaryCount: Int = 0

    var hasAnyEvent: Bool {
        abnormalCount + normalCount + reportCount + diaryCount > 0
    }
}

struct CalendarData {
    let dayMarks: [Date: DayMarks]
    let symptomRanges: [SymptomRange]

    func marks(for day: Date, calendar: Calendar = .current) -> DayMarks {
        dayMarks[calendar.startOfDay(for: day)] ?? DayMarks()
    }

    func ranges(touching day: Date, calendar: Calendar = .current) -> [SymptomRange] {
        symptomRanges.filter { $0.contains(day, calendar: calendar) }
    }

    static func build(indicators: [Indicator],
                      reports: [Report],
                      diaries: [DiaryEntry],
                      symptoms: [Symptom],
                      now: Date = .now,
                      calendar: Calendar = .current) -> CalendarData {
        var buckets: [Date: DayMarks] = [:]

        for i in indicators {
            let day = calendar.startOfDay(for: i.capturedAt)
            var m = buckets[day] ?? DayMarks()
            if i.status == .normal {
                m.normalCount += 1
            } else {
                m.abnormalCount += 1
            }
            buckets[day] = m
        }

        for r in reports {
            let day = calendar.startOfDay(for: r.reportDate)
            var m = buckets[day] ?? DayMarks()
            m.reportCount += 1
            buckets[day] = m
        }

        for d in diaries {
            let day = calendar.startOfDay(for: d.createdAt)
            var m = buckets[day] ?? DayMarks()
            m.diaryCount += 1
            buckets[day] = m
        }

        let ranges: [SymptomRange] = symptoms.map { s in
            SymptomRange(
                id: "\(s.persistentModelID)",
                name: s.name,
                startDay: calendar.startOfDay(for: s.startedAt),
                endDay: calendar.startOfDay(for: s.endedAt ?? now),
                severity: s.severity,
                isOngoing: s.isOngoing
            )
        }

        return CalendarData(dayMarks: buckets, symptomRanges: ranges)
    }
}
