//
//  SummaryView.swift
//  iKeyMon
//
//  Created by tracer on 21.04.26.
//

import SwiftUI
import SwiftData
import Charts

struct SummaryView: View {
    private enum TimeRange: String, CaseIterable, Identifiable {
        case hour = "Hour"
        case day = "Day"
        case week = "Week"
        case month = "Month"

        var id: String { rawValue }

        var duration: TimeInterval {
            switch self {
            case .hour:
                return 60 * 60
            case .day:
                return 24 * 60 * 60
            case .week:
                return 7 * 24 * 60 * 60
            case .month:
                return 30 * 24 * 60 * 60
            }
        }

        var axisLabelFormat: Date.FormatStyle {
            switch self {
            case .hour:
                return .dateTime.hour().minute()
            case .day:
                return .dateTime.hour()
            case .week:
                return .dateTime.month(.abbreviated).day()
            case .month:
                return .dateTime.month(.abbreviated).day()
            }
        }
    }

    @Binding var server: Server
    var canRestart: Bool = false
    var isRestarting: Bool = false
    var onRestart: (() -> Void)? = nil
    @Query(sort: \MetricSample.timestamp, order: .forward) private var metricSamples: [MetricSample]
    @State private var selectedRange: TimeRange = .hour

    private let cardSpacing: CGFloat = 16
    private let minCardWidth: CGFloat = 260

    var body: some View {
        GeometryReader { geometry in
            let contentWidth = max(geometry.size.width - 36, 0)
            let chartColumns = summaryColumns(for: contentWidth)

            ScrollView {
                VStack(alignment: .leading, spacing: 18) {
                    summaryHeader

                    HStack {
                        Spacer()
                        Picker("Time Range", selection: $selectedRange) {
                            ForEach(TimeRange.allCases) { range in
                                Text(range.rawValue)
                                    .tag(range)
                            }
                        }
                        .pickerStyle(.segmented)
                        .frame(maxWidth: 260)
                    }
                    .frame(maxWidth: .infinity)

                    LazyVGrid(columns: chartColumns, spacing: cardSpacing) {
                        historyChartCard(
                            title: "CPU usage",
                            currentValue: server.info?.load.percent ?? 0,
                            tint: loadTint,
                            samples: filteredSamples,
                            value: \.cpuPercent,
                            yAxisDomain: cpuChartDomain,
                            yAxisValues: nil,
                            clampValuesToDomain: false,
                        footer: [
                            ("1 min", String(format: "%.2f", server.info?.load.minute1 ?? 0)),
                            ("5 min", String(format: "%.2f", server.info?.load.minute5 ?? 0)),
                            ("15 min", String(format: "%.2f", server.info?.load.minute15 ?? 0))
                        ]
                    )

                        historyChartCard(
                            title: "Memory usage",
                            currentValue: server.info?.memory.percent ?? 0,
                            tint: .blue,
                            samples: filteredSamples,
                            value: \.memoryPercent,
                            footer: [
                                ("Used", (server.info?.memory.used ?? 0).toNiceBinaryUnit()),
                                ("Free", (server.info?.memory.free ?? 0).toNiceBinaryUnit()),
                                ("Total", (server.info?.memory.total ?? 0).toNiceBinaryUnit())
                            ]
                        )

                        historyChartCard(
                            title: "Disk usage",
                            currentValue: server.info?.diskSpace.percent ?? 0,
                            tint: .green,
                            samples: filteredSamples,
                            value: \.diskPercent,
                            footer: [
                                ("Used", (server.info?.diskSpace.used ?? 0).toNiceBinaryUnit()),
                                ("Free", (server.info?.diskSpace.free ?? 0).toNiceBinaryUnit()),
                                ("Total", (server.info?.diskSpace.total ?? 0).toNiceBinaryUnit())
                            ]
                        )

                        historyChartCard(
                            title: "Swap usage",
                            currentValue: server.info?.swap.percent ?? 0,
                            tint: .orange,
                            samples: filteredSamples,
                            value: \.swapPercent,
                            footer: [
                                ("Used", (server.info?.swap.used ?? 0).toNiceBinaryUnit()),
                                ("Free", (server.info?.swap.free ?? 0).toNiceBinaryUnit()),
                                ("Total", (server.info?.swap.total ?? 0).toNiceBinaryUnit())
                            ]
                        )
                    }
                    .frame(maxWidth: .infinity, alignment: .leading)
                }
                .padding(18)
                .frame(width: contentWidth, alignment: .leading)
            }
        }
    }

    private func summaryColumns(for width: CGFloat) -> [GridItem] {
        let count = max(1, min(4, Int((width + cardSpacing) / (minCardWidth + cardSpacing))))
        return Array(
            repeating: GridItem(.flexible(minimum: minCardWidth), spacing: cardSpacing, alignment: .top),
            count: count
        )
    }

    private var selectedRangeStart: Date {
        Date().addingTimeInterval(-selectedRange.duration)
    }

    private var filteredSamples: [MetricSample] {
        return metricSamples.filter { sample in
            sample.serverID == server.id && sample.timestamp >= selectedRangeStart
        }
    }

    private var cpuChartDomain: ClosedRange<Double> {
        let values = filteredSamples.map(\.cpuPercent) + [server.info?.load.percent ?? 0]
        let maximum = max(values.max() ?? 0, 100)
        let roundedUpperBound = ceil(maximum / 25) * 25
        return 0 ... roundedUpperBound
    }

    private var summaryHeader: some View {
        dashboardCard {
            HStack(alignment: .top, spacing: 16) {
                VStack(alignment: .leading, spacing: 10) {
                    HStack(alignment: .center, spacing: 10) {
                        Circle()
                            .fill(statusTint)
                            .frame(width: 10, height: 10)
                            .help(statusTooltip)

                        Text(server.hostname)
                            .font(.system(size: 22, weight: .semibold))

                        statusBadge(statusText, tint: statusTint)
                            .help(statusTooltip)
                    }

                    HStack(spacing: 8) {
                        statusBadge(panelBadgeText, tint: .orange)
                        statusBadge(apiBadgeText, tint: .blue)
                        if let operatingSystemSummary = server.info?.operatingSystemSummary, !operatingSystemSummary.isEmpty {
                            statusBadge(operatingSystemSummary, tint: .secondary)
                        }
                    }

                    Text(summaryLine)
                        .font(.subheadline)
                        .foregroundStyle(.secondary)
                        .fixedSize(horizontal: false, vertical: true)
                }

                Spacer(minLength: 12)

                if canRestart, let onRestart {
                    Button(role: .destructive) {
                        onRestart()
                    } label: {
                        if isRestarting {
                            HStack(spacing: 8) {
                                ProgressView()
                                    .controlSize(.small)
                                Text("Rebooting…")
                            }
                        } else {
                            Label("Reboot Server", systemImage: "arrow.clockwise.circle")
                        }
                    }
                    .disabled(isRestarting)
                }
            }
        }
    }

    private func historyChartCard(
        title: String,
        currentValue: Double,
        tint: Color,
        samples: [MetricSample],
        value: KeyPath<MetricSample, Double>,
        yAxisDomain: ClosedRange<Double> = 0...100,
        yAxisValues: [Double]? = [0, 25, 50, 75, 100],
        clampValuesToDomain: Bool = true,
        footer: [(String, String)],
        caption: String? = nil
    ) -> some View {
        dashboardCard {
            VStack(alignment: .leading, spacing: 14) {
                HStack(alignment: .firstTextBaseline) {
                    Text(title)
                        .font(.headline)
                    Spacer()
                    Text(String(format: "%.2f %%", currentValue))
                        .font(.title3.weight(.semibold))
                        .foregroundStyle(tint)
                        .monospacedDigit()
                }

                if samples.isEmpty {
                    ContentUnavailableView(
                        "No chart data yet",
                        systemImage: "chart.xyaxis.line",
                        description: Text("History appears after a few refresh cycles.")
                    )
                    .frame(maxWidth: .infinity)
                    .padding(.vertical, 24)
                } else {
                    Chart(samples) { sample in
                        let rawValue = sample[keyPath: value]
                        let sampleValue = clampValuesToDomain
                            ? min(max(rawValue, yAxisDomain.lowerBound), yAxisDomain.upperBound)
                            : rawValue

                        AreaMark(
                            x: .value("Time", sample.timestamp),
                            y: .value(title, sampleValue)
                        )
                        .interpolationMethod(.catmullRom)
                        .foregroundStyle(
                            LinearGradient(
                                colors: [
                                    tint.opacity(0.55),
                                    tint.opacity(0.12)
                                ],
                                startPoint: .top,
                                endPoint: .bottom
                            )
                        )

                        LineMark(
                            x: .value("Time", sample.timestamp),
                            y: .value(title, sampleValue)
                        )
                        .interpolationMethod(.catmullRom)
                        .foregroundStyle(tint)
                        .lineStyle(StrokeStyle(lineWidth: 2))
                    }
                    .chartYScale(domain: yAxisDomain)
                    .chartXScale(domain: selectedRangeStart ... Date())
                    .chartXAxis {
                        AxisMarks(values: .automatic(desiredCount: 6)) { value in
                            AxisGridLine(stroke: StrokeStyle(lineWidth: 0.5))
                                .foregroundStyle(.secondary.opacity(0.25))
                            AxisTick()
                                .foregroundStyle(.secondary.opacity(0.7))
                            AxisValueLabel(format: selectedRange.axisLabelFormat)
                        }
                    }
                    .chartYAxis {
                        if let yAxisValues {
                            AxisMarks(position: .leading, values: yAxisValues) { value in
                                AxisGridLine(stroke: StrokeStyle(lineWidth: 0.5))
                                    .foregroundStyle(.secondary.opacity(0.2))
                                AxisTick()
                                    .foregroundStyle(.secondary.opacity(0.7))
                                AxisValueLabel {
                                    if let percent = value.as(Double.self) {
                                        Text("\(Int(percent))%")
                                    }
                                }
                            }
                        } else {
                            AxisMarks(position: .leading, values: .automatic(desiredCount: 5)) { value in
                                AxisGridLine(stroke: StrokeStyle(lineWidth: 0.5))
                                    .foregroundStyle(.secondary.opacity(0.2))
                                AxisTick()
                                    .foregroundStyle(.secondary.opacity(0.7))
                                AxisValueLabel {
                                    if let percent = value.as(Double.self) {
                                        Text("\(Int(percent))%")
                                    }
                                }
                            }
                        }
                    }
                    .frame(height: 220)
                }

                HStack(spacing: 16) {
                    ForEach(Array(footer.enumerated()), id: \.offset) { _, item in
                        metric(item.0, value: item.1)
                    }
                }

                if let caption {
                    Text(caption)
                        .font(.caption)
                        .foregroundStyle(.secondary)
                }
            }
        }
    }

    private func metric(_ title: String, value: String) -> some View {
        VStack(alignment: .leading, spacing: 4) {
            Text(title.uppercased())
                .font(.caption2.weight(.semibold))
                .foregroundStyle(.secondary)
            Text(value)
                .font(.system(.body, design: .monospaced))
        }
        .frame(maxWidth: .infinity, alignment: .leading)
    }

    private func statusBadge(_ text: String, tint: Color) -> some View {
        Text(text)
            .font(.caption.weight(.semibold))
            .foregroundStyle(tint == .secondary ? .secondary : tint)
            .padding(.horizontal, 10)
            .padding(.vertical, 5)
            .background {
                Capsule(style: .continuous)
                    .fill(tint == .secondary ? Color.secondary.opacity(0.12) : tint.opacity(0.14))
            }
    }

    private func dashboardCard<Content: View>(@ViewBuilder content: () -> Content) -> some View {
        VStack(alignment: .leading, spacing: 0) {
            content()
        }
        .padding(18)
        .frame(maxWidth: .infinity, alignment: .leading)
        .background(
            RoundedRectangle(cornerRadius: 12, style: .continuous)
                .fill(Color.white.opacity(0.03))
        )
        .overlay {
            RoundedRectangle(cornerRadius: 12, style: .continuous)
                .stroke(Color.white.opacity(0.06), lineWidth: 1)
        }
    }

    private var apiBadgeText: String {
        guard let apiVersion = server.info?.apiVersion, !apiVersion.isEmpty else {
            return "API unknown"
        }
        return "API \(apiVersion)"
    }

    private var panelBadgeText: String {
        guard let panelVersion = server.info?.panelVersion, !panelVersion.isEmpty else {
            return "KeyHelp unknown"
        }
        return "KeyHelp \(panelVersion)"
    }

    private var summaryLine: String {
        var parts: [String] = []

        if let uptime = server.info?.uptime, !uptime.isEmpty {
            parts.append("Uptime \(uptime)")
        }

        if let serverTime = server.info?.formattedServerTime, !serverTime.isEmpty {
            parts.append("Server time \(serverTime)")
        }

        if parts.isEmpty {
            return "Live summary for \(server.hostname)"
        }

        return parts.joined(separator: " • ")
    }

    private var loadTint: Color {
        switch server.info?.load.level.lowercased() {
        case "warning":
            return .orange
        case "critical":
            return .red
        default:
            return .green
        }
    }

    private var statusTint: Color {
        if !server.pingable {
            return .red
        }
        if server.info?.rebootRequired == true {
            return .yellow
        }
        return .green
    }

    private var statusText: String {
        server.pingable ? "Online" : "Offline"
    }

    private var statusTooltip: String {
        if !server.pingable {
            return "This host is offline."
        }
        return server.info?.statusTooltip ?? "This host is online."
    }
}

#Preview {
    struct PreviewWrapper: View {
        @State var previewServer = Server(hostname: "example.com", info: .placeholder)

        var body: some View {
            SummaryView(server: $previewServer, canRestart: true)
                .padding()
                .frame(width: 1100, height: 760)
        }
    }

    return PreviewWrapper()
}
