import SwiftUI

struct CalendarMonthGrid: View {
    let monthAnchor: Date
    let data: CalendarData
    let selectedDate: Date?
    let onTapDay: (Date) -> Void

    init(monthAnchor: Date,
         data: CalendarData,
         selectedDate: Date? = nil,
         onTapDay: @escaping (Date) -> Void) {
        self.monthAnchor = monthAnchor
        self.data = data
        self.selectedDate = selectedDate
        self.onTapDay = onTapDay
    }

    private let calendar: Calendar = {
        var c = Calendar(identifier: .gregorian)
        c.firstWeekday = 2 // 周一开始
        c.locale = Locale.current
        return c
    }()

    private let weekdayLabels = [
        String(appLoc: "一"), String(appLoc: "二"), String(appLoc: "三"),
        String(appLoc: "四"), String(appLoc: "五"), String(appLoc: "六"),
        String(appLoc: "日")
    ]
    private let columns = Array(repeating: GridItem(.flexible(), spacing: 4), count: 7)

    private var days: [DayCell] {
        guard let monthInterval = calendar.dateInterval(of: .month, for: monthAnchor) else {
            return []
        }
        let firstOfMonth = monthInterval.start
        let weekdayIndex = (calendar.component(.weekday, from: firstOfMonth) - calendar.firstWeekday + 7) % 7
        let daysInMonth = calendar.range(of: .day, in: .month, for: firstOfMonth)?.count ?? 30

        var cells: [DayCell] = []
        // leading padding (上月尾)
        for offset in (0..<weekdayIndex).reversed() {
            if let d = calendar.date(byAdding: .day, value: -(offset + 1), to: firstOfMonth) {
                cells.append(DayCell(date: d, inCurrentMonth: false))
            }
        }
        // current month days
        for i in 0..<daysInMonth {
            if let d = calendar.date(byAdding: .day, value: i, to: firstOfMonth) {
                cells.append(DayCell(date: d, inCurrentMonth: true))
            }
        }
        // trailing padding (下月头) — 填到 6 周整 = 42
        while cells.count < 42 {
            if let last = cells.last,
               let next = calendar.date(byAdding: .day, value: 1, to: last.date) {
                cells.append(DayCell(date: next, inCurrentMonth: false))
            } else { break }
        }
        return cells
    }

    var body: some View {
        VStack(spacing: 8) {
            HStack(spacing: 4) {
                ForEach(weekdayLabels, id: \.self) { w in
                    Text(w)
                        .font(.tjScaled( 11, weight: .medium))
                        .foregroundStyle(Tj.Palette.text3)
                        .frame(maxWidth: .infinity)
                }
            }

            LazyVGrid(columns: columns, spacing: 4) {
                ForEach(days) { cell in
                    DayCellView(
                        cell: cell,
                        ranges: data.ranges(touching: cell.date, calendar: calendar),
                        marks: data.marks(for: cell.date, calendar: calendar),
                        isToday: calendar.isDateInToday(cell.date),
                        isSelected: selectedDate.map {
                            calendar.isDate(cell.date, inSameDayAs: $0)
                        } ?? false,
                        calendar: calendar
                    )
                    .onTapGesture { onTapDay(cell.date) }
                }
            }
        }
    }
}

struct DayCell: Identifiable, Hashable {
    let date: Date
    let inCurrentMonth: Bool
    var id: String { "\(date.timeIntervalSince1970)" }
}

private struct DayCellView: View {
    let cell: DayCell
    let ranges: [SymptomRange]
    let marks: DayMarks
    let isToday: Bool
    let isSelected: Bool
    let calendar: Calendar

    private var dayNumber: Int {
        calendar.component(.day, from: cell.date)
    }

    var body: some View {
        ZStack(alignment: .top) {
            // 背景层:selected > today
            RoundedRectangle(cornerRadius: 6, style: .continuous)
                .fill(backgroundFill)

            // 选中描边
            if isSelected {
                RoundedRectangle(cornerRadius: 6, style: .continuous)
                    .strokeBorder(Tj.Palette.brick, lineWidth: 1.5)
            }

            VStack(spacing: 2) {
                Text("\(dayNumber)")
                    .font(.tjScaled( 13,
                                  weight: (isToday || isSelected) ? .bold : .regular,
                                  design: .default))
                    .foregroundStyle(textColor)
                    .padding(.top, 4)

                // 症状连续条
                if !ranges.isEmpty {
                    VStack(spacing: 1) {
                        ForEach(Array(ranges.prefix(2).enumerated()), id: \.element.id) { _, range in
                            symptomBar(range)
                        }
                        if ranges.count > 2 {
                            Text("+\(ranges.count - 2)")
                                .font(.tjScaled( 7, design: .monospaced))
                                .foregroundStyle(Tj.Palette.text3)
                        }
                    }
                }

                // 异常 / 普通点
                if marks.hasAnyEvent {
                    HStack(spacing: 2) {
                        if marks.abnormalCount > 0 {
                            Circle().fill(Tj.Palette.brick).frame(width: 4, height: 4)
                        }
                        if marks.reportCount > 0 {
                            Circle().fill(Tj.Palette.ink2).frame(width: 4, height: 4)
                        }
                        if marks.normalCount > 0 && marks.abnormalCount == 0 {
                            Circle().fill(Tj.Palette.leaf).frame(width: 4, height: 4)
                        }
                        if marks.diaryCount > 0 {
                            Circle().fill(Tj.Palette.text3.opacity(0.7)).frame(width: 4, height: 4)
                        }
                    }
                }

                Spacer(minLength: 0)
            }
        }
        .frame(height: 56)
        .contentShape(Rectangle())
    }

    private var textColor: Color {
        if !cell.inCurrentMonth { return Tj.Palette.text3.opacity(0.5) }
        if isSelected { return Tj.Palette.brick }
        if isToday { return Tj.Palette.ink }
        return Tj.Palette.text
    }

    private var backgroundFill: Color {
        if isSelected { return Tj.Palette.brickSoft.opacity(0.5) }
        if isToday { return Tj.Palette.sand2 }
        return .clear
    }

    private func symptomBar(_ range: SymptomRange) -> some View {
        let pos = range.position(cell.date, calendar: calendar)
        let leadingRadius: CGFloat = (pos == .start || pos == .single) ? 3 : 0
        let trailingRadius: CGFloat = (pos == .end || pos == .single) ? 3 : 0
        return GeometryReader { geo in
            UnevenRoundedRectangle(
                topLeadingRadius: leadingRadius,
                bottomLeadingRadius: leadingRadius,
                bottomTrailingRadius: trailingRadius,
                topTrailingRadius: trailingRadius,
                style: .continuous
            )
            .fill(range.color)
            .frame(
                width: barWidth(for: pos, in: geo.size.width),
                height: 4
            )
            .frame(maxWidth: .infinity,
                   alignment: barAlignment(for: pos))
        }
        .frame(height: 4)
    }

    private func barWidth(for pos: SymptomRange.Position, in cellWidth: CGFloat) -> CGFloat {
        switch pos {
        case .single: return cellWidth - 8
        case .start, .end: return cellWidth - 2
        case .middle: return cellWidth + 4 // 越界让相邻天视觉连接
        }
    }

    private func barAlignment(for pos: SymptomRange.Position) -> Alignment {
        switch pos {
        case .start:  return .leading
        case .end:    return .trailing
        case .single: return .center
        case .middle: return .center
        }
    }
}
