import CoreData
import SwiftUI

struct PumpView: View {
    let reservoir: Decimal?
    let name: String
    let expiresAtDate: Date?
    let activatedAtDate: Date?
    let timerDate: Date
    let pumpStatusHighlightMessage: String?
    let battery: [OpenAPS_Battery]
    @Environment(\.colorScheme) var colorScheme

    let NORMAL_PATCH_AGE = TimeInterval.hours(80)

    private var batteryFormatter: NumberFormatter {
        let formatter = NumberFormatter()
        formatter.numberStyle = .percent
        return formatter
    }

    private var hourglassIcon: String {
        if activatedAtDate != nil { return "hourglass.badge.plus" }
        guard let expiration = expiresAtDate else { return "hourglass" }

        let hoursRemaining = expiration.timeIntervalSince(timerDate) / 3600

        switch hoursRemaining {
        case 60 ... 72:
            return "hourglass.bottomhalf.filled"
        case 12 ..< 60:
            return "hourglass"
        case -8 ..< 12:
            return "hourglass.tophalf.filled"
        default:
            return "hourglass"
        }
    }

    var body: some View {
        if let pumpStatusHighlightMessage = pumpStatusHighlightMessage { // display message instead pump info
            VStack(alignment: .center) {
                Text(pumpStatusHighlightMessage).font(.footnote).fontWeight(.bold)
                    .multilineTextAlignment(.center).frame(maxWidth: /*@START_MENU_TOKEN@*/ .infinity/*@END_MENU_TOKEN@*/)
            }.frame(width: 100)
        } else {
            VStack(alignment: .leading, spacing: 20) {
                if reservoir == nil && battery.isEmpty {
                    VStack(alignment: .center, spacing: 12) {
                        HStack {
                            Image(systemName: "keyboard.onehanded.left")
                                .font(.body)
                                .imageScale(.large)
                        }
                        HStack {
                            Text("Add pump")
                                .font(.caption)
                                .bold()
                        }
                    }
                    .frame(alignment: .top)
                }
                if let reservoir = reservoir {
                    HStack {
                        Image(systemName: "cross.vial.fill")
                            .font(.callout)

                        if reservoir == 0xDEAD_BEEF {
                            Text("50+ " + String(localized: "U", comment: "Insulin unit"))
                                .font(.callout)
                                .fontWeight(.bold)
                                .fontDesign(.rounded)
                        } else {
                            Text(
                                Formatter.integerFormatter
                                    .string(from: reservoir as NSNumber)! + String(localized: " U", comment: "Insulin unit")
                            )
                            .font(.callout)
                            .fontWeight(.bold)
                            .fontDesign(.rounded)
                        }
                    }
                    .padding(.vertical, 5)
                    .padding(.horizontal, 10)
                    .foregroundStyle(reservoirColor)
                    .overlay(
                        Capsule()
                            .stroke(reservoirColor.opacity(0.4), lineWidth: 2)
                    )
                }

                if (battery.first?.display) != nil, let shouldBatteryDisplay = battery.first?.display, shouldBatteryDisplay {
                    HStack {
                        Image(systemName: "battery.100")
                            .font(.callout)
                            .foregroundStyle(batteryColor)
                        Text("\(Formatter.integerFormatter.string(for: battery.first?.percent ?? 100) ?? "100") %")
                            .font(.callout).fontWeight(.bold).fontDesign(.rounded)
                    }
                }

                if let date = expiresAtDate {
                    PatchTimer(forDate: date)
                }
            }
        }
    }

    @ViewBuilder private func PatchTimer(forDate date: Date) -> some View {
        HStack {
            Image(systemName: hourglassIcon)
                .font(.callout)
                .foregroundStyle(timerColor, timerColorSecondary)
                .symbolRenderingMode(.palette)

            let remainingTimeString = remainingTimeString(time: date.timeIntervalSince(timerDate))

            Text(remainingTimeString)
                .font(date.timeIntervalSince(timerDate) > 0 ? .callout : .subheadline)
                .fontWeight(.bold)
                .fontDesign(.rounded)
                .lineLimit(2)
                .multilineTextAlignment(.leading)
                .frame(
                    // If the string is > 6 chars, i.e., exceeds "xd yh", limit width to 80 pts
                    // This forces the "Replace pod" string to wrap to 2 lines.
                    maxWidth: remainingTimeString.count > 6 ? 80 : .infinity,
                    alignment: .leading
                )
        }
        // aligns the stopwatch icon exactly with the first pixel of the reservoir icon
        .padding(.leading, date.timeIntervalSince(timerDate) > 0 || activatedAtDate != nil ? 12 : 0)
    }

    private func remainingTimeString(time: TimeInterval) -> String {
        guard time > 0 else {
            return String(localized: "Replace pod", comment: "View/Header when pod expired")
        }

        var time = time
        let days = Int(time / 1.days.timeInterval)
        time -= days.days.timeInterval
        let hours = Int(time / 1.hours.timeInterval)
        time -= hours.hours.timeInterval
        let minutes = Int(time / 1.minutes.timeInterval)

        if days >= 1 {
            return "\(days)" + String(localized: "d", comment: "abbreviation for days") + " \(hours)" +
                String(localized: "h", comment: "abbreviation for hours")
        }

        if hours >= 1 {
            var remainingHoursString = "\(hours)" + String(localized: "h", comment: "abbreviation for hours")
            if hours < 12 {
                remainingHoursString += " " + "\(minutes)" +
                    String(localized: "m", comment: "abbreviation for minutes")
            }
            return remainingHoursString
        }

        return "\(minutes)" + String(localized: "m", comment: "abbreviation for minutes")
    }

    private var batteryColor: Color {
        guard let battery = battery.first else {
            return .gray
        }

        switch battery.percent {
        case ...10:
            return Color.loopRed
        case ...20:
            return Color.orange
        default:
            return Color.loopGreen
        }
    }

    private var reservoirColor: Color {
        guard let reservoir = reservoir else {
            return .gray
        }

        switch reservoir {
        case ...10:
            return Color.loopRed
        case ...30:
            return Color.orange
        default:
            return Color.insulin
        }
    }

    private var timerColor: Color {
        if let activatedAt = activatedAtDate {
            return abs(activatedAt.timeIntervalSinceNow) > NORMAL_PATCH_AGE ? Color.yellow : Color.loopGreen
        }

        guard let expiresAt = expiresAtDate else {
            return .gray
        }

        let time = expiresAt.timeIntervalSince(timerDate)

        switch time {
        case ...8.hours.timeInterval:
            return Color.loopRed
        case ...1.days.timeInterval:
            return Color.orange
        default:
            return Color.loopGreen
        }
    }

    private var timerColorSecondary: Color {
        if activatedAtDate != nil {
            return Color.gray
        }

        return Color.yellow
    }
}

// #Preview("message") {
//    PumpView(
//        reservoir: .constant(Decimal(10.0)),
//        battery: .constant(nil),
//        name: .constant("Pump test"),
//        expiresAtDate: .constant(Date().addingTimeInterval(24.hours)),
//        timerDate: .constant(Date()),
//        pumpStatusHighlightMessage: .constant("⚠️\n Insulin suspended")
//    )
// }
//
// #Preview("pump reservoir") {
//    PumpView(
//        reservoir: .constant(Decimal(40.0)),
//        battery: .constant(Battery(percent: 50, voltage: 2.0, string: BatteryState.normal, display: true)),
//        name: .constant("Pump test"),
//        expiresAtDate: .constant(nil),
//        timerDate: .constant(Date().addingTimeInterval(-24.hours)),
//        pumpStatusHighlightMessage: .constant(nil)
//    )
// }
//
// #Preview("pump expiration") {
//    PumpView(
//        reservoir: .constant(Decimal(10.0)),
//        battery: .constant(Battery(percent: 50, voltage: 2.0, string: BatteryState.normal, display: false)),
//        name: .constant("Pump test"),
//        expiresAtDate: .constant(Date().addingTimeInterval(2.hours)),
//        timerDate: .constant(Date().addingTimeInterval(2.hours)),
//        pumpStatusHighlightMessage: .constant(nil)
//    )
// }
//
// #Preview("no pump") {
//    PumpView(
//        reservoir: .constant(nil),
//        name: .constant(nil),
//        expiresAtDate: .constant(""),
//        timerDate: .constant(nil),
//        timeZone: .constant(Date()),
//        pumpStatusHighlightMessage: .constant(nil)
//    )
// }
