import Foundation
import UIKit

struct SystemOverviewPDFExporter {
    private let pageRect = CGRect(x: 0, y: 0, width: 595, height: 842) // A4 portrait
    private let margin: CGFloat = 40
    private let primaryTextColor = UIColor.black
    private let secondaryTextColor = UIColor.darkGray
    private let tertiaryTextColor = UIColor.gray

    // Brand colors for the diagram
    private let chargerColor = UIColor(red: 0.20, green: 0.55, blue: 0.87, alpha: 1.0)   // Blue
    private let batteryColor = UIColor(red: 0.30, green: 0.69, blue: 0.31, alpha: 1.0)   // Green
    private let loadColor = UIColor(red: 0.93, green: 0.55, blue: 0.14, alpha: 1.0)      // Orange
    private let accentColor = UIColor(red: 0.45, green: 0.34, blue: 0.86, alpha: 1.0)    // Purple
    private let cardBackground = UIColor(red: 0.96, green: 0.96, blue: 0.97, alpha: 1.0)
    private let tableHeaderBg = UIColor(red: 0.93, green: 0.93, blue: 0.95, alpha: 1.0)

    struct SystemSnapshot {
        let systemName: String
        let unitSystem: UnitSystem
        let loads: [LoadSnapshot]
        let batteries: [BatterySnapshot]
        let chargers: [ChargerSnapshot]
        let estimatedRuntimeFormatted: String?
        let estimatedChargeTimeFormatted: String?
        let totalPower: Double
        let totalCurrent: Double
        let totalBatteryCapacity: Double
        let totalBatteryEnergy: Double
        let totalUsableCapacity: Double
        let totalUsableEnergy: Double
        let totalChargerPower: Double
        let totalChargerCurrent: Double
    }

    struct LoadSnapshot {
        let name: String
        let voltage: Double
        let current: Double
        let power: Double
        let length: Double
        let crossSection: Double
        let dutyCyclePercent: Double
        let dailyUsageHours: Double
        let recommendedCrossSection: Double
        let voltageDrop: Double
        let voltageDropPercent: Double
        let powerLoss: Double
        let recommendedFuse: Double
        let iconUrl: String?
    }

    struct BatterySnapshot {
        let name: String
        let chemistry: String
        let nominalVoltage: Double
        let capacityAmpHours: Double
        let usableCapacityAmpHours: Double
        let energyWattHours: Double
        let usableEnergyWattHours: Double
        let iconUrl: String?
    }

    struct ChargerSnapshot {
        let name: String
        let inputVoltage: Double
        let outputVoltage: Double
        let maxCurrentAmps: Double
        let effectivePowerWatts: Double
        let sourceType: String
        let iconUrl: String?
    }

    // MARK: - API Diagram Fetching

    static func fetchDiagramImage(snapshot: SystemSnapshot) async -> UIImage? {
        let payload: [String: Any] = [
            "systemName": snapshot.systemName,
            "source": "cable",
            "unitSystem": snapshot.unitSystem == .metric ? "metric" : "imperial",
            "loads": snapshot.loads.map { load in
                var dict: [String: Any] = [
                    "name": load.name,
                    "power": load.power,
                    "voltage": load.voltage,
                    "current": load.current,
                ]
                if let iconUrl = load.iconUrl { dict["iconUrl"] = iconUrl }
                return dict
            },
            "batteries": snapshot.batteries.map { battery in
                var dict: [String: Any] = [
                    "name": battery.name,
                    "voltage": battery.nominalVoltage,
                    "capacityAh": battery.capacityAmpHours,
                    "energyWh": battery.energyWattHours,
                ]
                if let iconUrl = battery.iconUrl { dict["iconUrl"] = iconUrl }
                return dict
            },
            "chargers": snapshot.chargers.map { charger in
                var dict: [String: Any] = [
                    "name": charger.name,
                    "inputVoltage": charger.inputVoltage,
                    "outputVoltage": charger.outputVoltage,
                    "power": charger.effectivePowerWatts,
                    "sourceType": charger.sourceType,
                ]
                if let iconUrl = charger.iconUrl { dict["iconUrl"] = iconUrl }
                return dict
            },
        ]

        guard let jsonData = try? JSONSerialization.data(withJSONObject: payload),
              let url = URL(string: "https://voltplan.app/api/diagram/generate") else {
            return nil
        }

        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        request.setValue("image/png", forHTTPHeaderField: "Accept")
        request.httpBody = jsonData
        request.timeoutInterval = 15

        do {
            let (data, response) = try await URLSession.shared.data(for: request)
            guard let httpResponse = response as? HTTPURLResponse,
                  httpResponse.statusCode == 200 else {
                return nil
            }
            return UIImage(data: data)
        } catch {
            return nil
        }
    }

    func export(snapshot: SystemSnapshot, diagramImage: UIImage? = nil) throws -> URL {
        let format = UIGraphicsPDFRendererFormat()
        let renderer = UIGraphicsPDFRenderer(bounds: pageRect, format: format)
        var pageIndex = 1

        let data = renderer.pdfData { context in
            // === PAGE 1: Title + Summary ===
            context.beginPage()
            var cursorY = drawTitleHeader(snapshot: snapshot, in: context.cgContext)
            cursorY = drawSystemSummary(snapshot: snapshot, at: cursorY, in: context.cgContext)
            drawFooter(pageIndex: pageIndex, in: context.cgContext)

            // === PAGE 2: Full-page Diagram ===
            if diagramImage != nil || !snapshot.loads.isEmpty || !snapshot.batteries.isEmpty || !snapshot.chargers.isEmpty {
                pageIndex += 1
                context.beginPage()
                drawFullPageDiagram(snapshot: snapshot, diagramImage: diagramImage, in: context.cgContext)
                drawFooter(pageIndex: pageIndex, in: context.cgContext)
            }

            // === PAGE 2+: Detail Tables ===
            if !snapshot.loads.isEmpty {
                pageIndex += 1
                context.beginPage()
                cursorY = drawPageHeader(
                    title: snapshot.systemName,
                    subtitle: String(localized: "overview.pdf.loads.section", defaultValue: "Loads"),
                    in: context.cgContext
                )
                cursorY = drawLoadsTable(
                    loads: snapshot.loads,
                    unitSystem: snapshot.unitSystem,
                    at: cursorY,
                    in: context,
                    pageIndex: &pageIndex,
                    systemName: snapshot.systemName
                )
                drawFooter(pageIndex: pageIndex, in: context.cgContext)
            }

            if !snapshot.batteries.isEmpty {
                pageIndex += 1
                context.beginPage()
                cursorY = drawPageHeader(
                    title: snapshot.systemName,
                    subtitle: String(localized: "overview.pdf.batteries.section", defaultValue: "Batteries"),
                    in: context.cgContext
                )
                cursorY = drawBatteriesTable(
                    batteries: snapshot.batteries,
                    at: cursorY,
                    in: context,
                    pageIndex: &pageIndex,
                    systemName: snapshot.systemName
                )
                drawFooter(pageIndex: pageIndex, in: context.cgContext)
            }

            if !snapshot.chargers.isEmpty {
                pageIndex += 1
                context.beginPage()
                cursorY = drawPageHeader(
                    title: snapshot.systemName,
                    subtitle: String(localized: "overview.pdf.chargers.section", defaultValue: "Chargers"),
                    in: context.cgContext
                )
                cursorY = drawChargersTable(
                    chargers: snapshot.chargers,
                    at: cursorY,
                    in: context,
                    pageIndex: &pageIndex,
                    systemName: snapshot.systemName
                )
                drawFooter(pageIndex: pageIndex, in: context.cgContext)
            }
        }

        let url = FileManager.default.temporaryDirectory
            .appendingPathComponent("System-Overview-\(UUID().uuidString).pdf")
        try data.write(to: url, options: .atomic)
        return url
    }

    // MARK: - Title Header

    private func drawTitleHeader(snapshot: SystemSnapshot, in context: CGContext) -> CGFloat {
        let availableWidth = pageRect.width - (margin * 2)

        let titleFont = UIFont.systemFont(ofSize: 28, weight: .bold)
        let titleRect = CGRect(x: margin, y: margin, width: availableWidth, height: titleFont.lineHeight + 4)
        snapshot.systemName.draw(in: titleRect, withAttributes: [
            .font: titleFont,
            .foregroundColor: primaryTextColor,
        ])

        let subtitleFont = UIFont.systemFont(ofSize: 14, weight: .medium)
        let dateFormatter = DateFormatter()
        dateFormatter.dateStyle = .long
        let subtitle = "\(dateFormatter.string(from: Date())) · \(snapshot.unitSystem.displayName)"
        let subtitleRect = CGRect(
            x: margin,
            y: titleRect.maxY + 4,
            width: availableWidth,
            height: subtitleFont.lineHeight + 2
        )
        subtitle.draw(in: subtitleRect, withAttributes: [
            .font: subtitleFont,
            .foregroundColor: secondaryTextColor,
        ])

        // Divider line
        let dividerY = subtitleRect.maxY + 12
        context.setStrokeColor(UIColor.separator.cgColor)
        context.setLineWidth(0.5)
        context.move(to: CGPoint(x: margin, y: dividerY))
        context.addLine(to: CGPoint(x: pageRect.width - margin, y: dividerY))
        context.strokePath()

        return dividerY + 16
    }

    // MARK: - System Diagram

    private func drawFullPageDiagram(snapshot: SystemSnapshot, diagramImage: UIImage?, in context: CGContext) {
        let availableWidth = pageRect.width - (margin * 2)
        let availableHeight = pageRect.height - (margin * 2) - 30 // leave room for footer

        if let diagramImage, let cgImage = diagramImage.cgImage {
            let imageAspect = diagramImage.size.width / diagramImage.size.height
            let rectAspect = availableWidth / availableHeight
            var drawRect: CGRect
            if imageAspect > rectAspect {
                let drawHeight = availableWidth / imageAspect
                drawRect = CGRect(
                    x: margin,
                    y: margin + (availableHeight - drawHeight) / 2,
                    width: availableWidth,
                    height: drawHeight
                )
            } else {
                let drawWidth = availableHeight * imageAspect
                drawRect = CGRect(
                    x: margin + (availableWidth - drawWidth) / 2,
                    y: margin,
                    width: drawWidth,
                    height: availableHeight
                )
            }

            context.saveGState()
            context.translateBy(x: 0, y: drawRect.minY + drawRect.maxY)
            context.scaleBy(x: 1, y: -1)
            context.draw(cgImage, in: drawRect)
            context.restoreGState()
        } else {
            // Fallback: draw the block diagram centered on the page
            _ = drawSystemDiagram(snapshot: snapshot, at: margin + (availableHeight - 220) / 2, in: context)
        }
    }

    private func drawSystemDiagram(snapshot: SystemSnapshot, diagramImage: UIImage? = nil, at yPosition: CGFloat, in context: CGContext) -> CGFloat {
        let availableWidth = pageRect.width - (margin * 2)
        let diagramHeight: CGFloat = 220
        let diagramRect = CGRect(x: margin, y: yPosition, width: availableWidth, height: diagramHeight)

        // If an API-fetched diagram image is available, draw it and return
        if let diagramImage, let cgImage = diagramImage.cgImage {
            // Draw diagram background card
            let bgPath = UIBezierPath(roundedRect: diagramRect, cornerRadius: 12)
            context.setFillColor(cardBackground.cgColor)
            context.addPath(bgPath.cgPath)
            context.fillPath()

            // Scale the image to fit within the diagram rect while maintaining aspect ratio
            let imageAspect = diagramImage.size.width / diagramImage.size.height
            let rectAspect = diagramRect.width / diagramRect.height
            var drawRect: CGRect
            if imageAspect > rectAspect {
                // Image is wider than rect — fit to width
                let drawHeight = diagramRect.width / imageAspect
                drawRect = CGRect(
                    x: diagramRect.minX,
                    y: diagramRect.minY + (diagramRect.height - drawHeight) / 2,
                    width: diagramRect.width,
                    height: drawHeight
                )
            } else {
                // Image is taller than rect — fit to height
                let drawWidth = diagramRect.height * imageAspect
                drawRect = CGRect(
                    x: diagramRect.minX + (diagramRect.width - drawWidth) / 2,
                    y: diagramRect.minY,
                    width: drawWidth,
                    height: diagramRect.height
                )
            }

            // CGContext draws images with flipped Y axis, so we need to flip
            context.saveGState()
            context.translateBy(x: 0, y: drawRect.minY + drawRect.maxY)
            context.scaleBy(x: 1, y: -1)
            context.draw(cgImage, in: drawRect)
            context.restoreGState()

            return diagramRect.maxY + 20
        }

        // Fallback: draw diagram with Core Graphics

        // Draw diagram background card
        let bgPath = UIBezierPath(roundedRect: diagramRect, cornerRadius: 12)
        context.setFillColor(cardBackground.cgColor)
        context.addPath(bgPath.cgPath)
        context.fillPath()

        // Layout: 3 columns — Chargers | Battery Bank | Loads
        let columnWidth = availableWidth / 3
        let chargerX = margin
        let batteryX = margin + columnWidth
        let loadX = margin + columnWidth * 2
        let blockInset: CGFloat = 12
        let topPadding: CGFloat = 16

        // Column headers
        let headerFont = UIFont.systemFont(ofSize: 11, weight: .bold)
        let headerAttrs: [NSAttributedString.Key: Any] = [.font: headerFont, .foregroundColor: tertiaryTextColor]

        let chargersLabel = String(localized: "overview.pdf.diagram.chargers", defaultValue: "CHARGERS")
        let batteriesLabel = String(localized: "overview.pdf.diagram.batteries", defaultValue: "BATTERY BANK")
        let loadsLabel = String(localized: "overview.pdf.diagram.loads", defaultValue: "LOADS")

        drawCenteredText(chargersLabel, in: CGRect(x: chargerX, y: yPosition + 10, width: columnWidth, height: 14), attributes: headerAttrs)
        drawCenteredText(batteriesLabel, in: CGRect(x: batteryX, y: yPosition + 10, width: columnWidth, height: 14), attributes: headerAttrs)
        drawCenteredText(loadsLabel, in: CGRect(x: loadX, y: yPosition + 10, width: columnWidth, height: 14), attributes: headerAttrs)

        let contentTop = yPosition + topPadding + 16

        // Draw charger blocks (left column)
        let maxBlocks = 4
        let chargerBlockHeight: CGFloat = 36
        let chargerSpacing: CGFloat = 6
        let chargersToShow = Array(snapshot.chargers.prefix(maxBlocks))
        var chargerCenters: [CGFloat] = []

        for (i, charger) in chargersToShow.enumerated() {
            let blockY = contentTop + CGFloat(i) * (chargerBlockHeight + chargerSpacing)
            let blockRect = CGRect(
                x: chargerX + blockInset,
                y: blockY,
                width: columnWidth - blockInset * 2,
                height: chargerBlockHeight
            )
            drawComponentBlock(
                name: charger.name,
                detail: formatPower(charger.effectivePowerWatts),
                color: chargerColor,
                rect: blockRect,
                in: context
            )
            chargerCenters.append(blockY + chargerBlockHeight / 2)
        }

        if snapshot.chargers.count > maxBlocks {
            let moreY = contentTop + CGFloat(maxBlocks) * (chargerBlockHeight + chargerSpacing)
            let moreText = "+\(snapshot.chargers.count - maxBlocks)"
            let moreFont = UIFont.systemFont(ofSize: 11, weight: .medium)
            drawCenteredText(
                moreText,
                in: CGRect(x: chargerX + blockInset, y: moreY, width: columnWidth - blockInset * 2, height: 16),
                attributes: [.font: moreFont, .foregroundColor: tertiaryTextColor]
            )
        }

        // Draw battery bank (center — one large block)
        let batteryBlockHeight: CGFloat = min(
            CGFloat(max(chargersToShow.count, min(snapshot.loads.count, maxBlocks))) * (chargerBlockHeight + chargerSpacing) - chargerSpacing,
            diagramHeight - topPadding - 36
        )
        let batteryBlockRect = CGRect(
            x: batteryX + blockInset,
            y: contentTop,
            width: columnWidth - blockInset * 2,
            height: max(batteryBlockHeight, 60)
        )
        drawBatteryBlock(snapshot: snapshot, rect: batteryBlockRect, in: context)
        let batteryCenterY = batteryBlockRect.midY

        // Draw load blocks (right column)
        let loadsToShow = Array(snapshot.loads.prefix(maxBlocks))
        var loadCenters: [CGFloat] = []

        for (i, load) in loadsToShow.enumerated() {
            let blockY = contentTop + CGFloat(i) * (chargerBlockHeight + chargerSpacing)
            let blockRect = CGRect(
                x: loadX + blockInset,
                y: blockY,
                width: columnWidth - blockInset * 2,
                height: chargerBlockHeight
            )
            drawComponentBlock(
                name: load.name,
                detail: formatPower(load.power),
                color: loadColor,
                rect: blockRect,
                in: context
            )
            loadCenters.append(blockY + chargerBlockHeight / 2)
        }

        if snapshot.loads.count > maxBlocks {
            let moreY = contentTop + CGFloat(maxBlocks) * (chargerBlockHeight + chargerSpacing)
            let moreText = "+\(snapshot.loads.count - maxBlocks)"
            let moreFont = UIFont.systemFont(ofSize: 11, weight: .medium)
            drawCenteredText(
                moreText,
                in: CGRect(x: loadX + blockInset, y: moreY, width: columnWidth - blockInset * 2, height: 16),
                attributes: [.font: moreFont, .foregroundColor: tertiaryTextColor]
            )
        }

        // Draw connection arrows: chargers → battery
        let arrowLineWidth: CGFloat = 1.5
        for centerY in chargerCenters {
            let startX = chargerX + columnWidth - blockInset
            let endX = batteryBlockRect.minX
            drawArrow(
                from: CGPoint(x: startX, y: centerY),
                to: CGPoint(x: endX, y: batteryCenterY),
                color: chargerColor,
                lineWidth: arrowLineWidth,
                in: context
            )
        }

        // Draw connection arrows: battery → loads
        for centerY in loadCenters {
            let startX = batteryBlockRect.maxX
            let endX = loadX + blockInset
            drawArrow(
                from: CGPoint(x: startX, y: batteryCenterY),
                to: CGPoint(x: endX, y: centerY),
                color: loadColor,
                lineWidth: arrowLineWidth,
                in: context
            )
        }

        // Handle empty states
        if snapshot.chargers.isEmpty {
            let emptyFont = UIFont.italicSystemFont(ofSize: 11)
            let emptyText = "–"
            drawCenteredText(
                emptyText,
                in: CGRect(x: chargerX + blockInset, y: contentTop + 20, width: columnWidth - blockInset * 2, height: 16),
                attributes: [.font: emptyFont, .foregroundColor: tertiaryTextColor]
            )
        }
        if snapshot.loads.isEmpty {
            let emptyFont = UIFont.italicSystemFont(ofSize: 11)
            let emptyText = "–"
            drawCenteredText(
                emptyText,
                in: CGRect(x: loadX + blockInset, y: contentTop + 20, width: columnWidth - blockInset * 2, height: 16),
                attributes: [.font: emptyFont, .foregroundColor: tertiaryTextColor]
            )
        }

        return diagramRect.maxY + 20
    }

    private func drawComponentBlock(name: String, detail: String, color: UIColor, rect: CGRect, in context: CGContext) {
        // Rounded rect with colored left border
        let path = UIBezierPath(roundedRect: rect, cornerRadius: 6)
        context.setFillColor(UIColor.white.cgColor)
        context.addPath(path.cgPath)
        context.fillPath()

        // Left accent bar
        let barRect = CGRect(x: rect.minX, y: rect.minY, width: 4, height: rect.height)
        let barPath = UIBezierPath(
            roundedRect: barRect,
            byRoundingCorners: [.topLeft, .bottomLeft],
            cornerRadii: CGSize(width: 6, height: 6)
        )
        context.setFillColor(color.cgColor)
        context.addPath(barPath.cgPath)
        context.fillPath()

        // Subtle border
        context.setStrokeColor(UIColor(white: 0.85, alpha: 1).cgColor)
        context.setLineWidth(0.5)
        context.addPath(path.cgPath)
        context.strokePath()

        // Name
        let nameFont = UIFont.systemFont(ofSize: 10, weight: .semibold)
        let textX = rect.minX + 10
        let textWidth = rect.width - 14
        let truncatedName = truncateText(name, font: nameFont, maxWidth: textWidth)
        truncatedName.draw(
            in: CGRect(x: textX, y: rect.minY + 4, width: textWidth, height: nameFont.lineHeight),
            withAttributes: [.font: nameFont, .foregroundColor: primaryTextColor]
        )

        // Detail
        let detailFont = UIFont.systemFont(ofSize: 9, weight: .regular)
        detail.draw(
            in: CGRect(x: textX, y: rect.minY + 4 + nameFont.lineHeight, width: textWidth, height: detailFont.lineHeight),
            withAttributes: [.font: detailFont, .foregroundColor: secondaryTextColor]
        )
    }

    private func drawBatteryBlock(snapshot: SystemSnapshot, rect: CGRect, in context: CGContext) {
        // Large rounded block
        let path = UIBezierPath(roundedRect: rect, cornerRadius: 10)
        context.setFillColor(batteryColor.withAlphaComponent(0.08).cgColor)
        context.addPath(path.cgPath)
        context.fillPath()

        // Border
        context.setStrokeColor(batteryColor.withAlphaComponent(0.4).cgColor)
        context.setLineWidth(1.5)
        context.addPath(path.cgPath)
        context.strokePath()

        let textX = rect.minX + 12
        let textWidth = rect.width - 24

        if snapshot.batteries.isEmpty {
            let emptyFont = UIFont.italicSystemFont(ofSize: 11)
            let emptyText = String(localized: "overview.pdf.diagram.no.batteries", defaultValue: "No batteries")
            drawCenteredText(
                emptyText,
                in: CGRect(x: textX, y: rect.midY - 8, width: textWidth, height: 16),
                attributes: [.font: emptyFont, .foregroundColor: tertiaryTextColor]
            )
            return
        }

        // Battery icon text
        let iconFont = UIFont.systemFont(ofSize: 22, weight: .light)
        let iconText = "⚡"
        drawCenteredText(
            iconText,
            in: CGRect(x: textX, y: rect.minY + 10, width: textWidth, height: 26),
            attributes: [.font: iconFont, .foregroundColor: batteryColor]
        )

        // Capacity
        let capacityFont = UIFont.systemFont(ofSize: 14, weight: .bold)
        let capacityText = "\(formatNumber(snapshot.totalBatteryCapacity)) Ah"
        drawCenteredText(
            capacityText,
            in: CGRect(x: textX, y: rect.minY + 38, width: textWidth, height: 18),
            attributes: [.font: capacityFont, .foregroundColor: primaryTextColor]
        )

        // Energy
        let energyFont = UIFont.systemFont(ofSize: 11, weight: .medium)
        let energyText = "\(formatNumber(snapshot.totalBatteryEnergy)) Wh"
        drawCenteredText(
            energyText,
            in: CGRect(x: textX, y: rect.minY + 56, width: textWidth, height: 14),
            attributes: [.font: energyFont, .foregroundColor: secondaryTextColor]
        )

        // Usable
        let usableFont = UIFont.systemFont(ofSize: 10, weight: .regular)
        let usableLabel = String(localized: "overview.pdf.diagram.usable", defaultValue: "Usable")
        let usableText = "\(usableLabel): \(formatNumber(snapshot.totalUsableCapacity)) Ah"
        drawCenteredText(
            usableText,
            in: CGRect(x: textX, y: rect.minY + 72, width: textWidth, height: 14),
            attributes: [.font: usableFont, .foregroundColor: tertiaryTextColor]
        )

        // Count
        if snapshot.batteries.count > 1 {
            let countFont = UIFont.systemFont(ofSize: 10, weight: .medium)
            let countText = "\(snapshot.batteries.count)×"
            drawCenteredText(
                countText,
                in: CGRect(x: textX, y: rect.maxY - 22, width: textWidth, height: 14),
                attributes: [.font: countFont, .foregroundColor: batteryColor]
            )
        }
    }

    private func drawArrow(from start: CGPoint, to end: CGPoint, color: UIColor, lineWidth: CGFloat, in context: CGContext) {
        context.setStrokeColor(color.withAlphaComponent(0.5).cgColor)
        context.setLineWidth(lineWidth)
        context.setLineCap(.round)

        // Draw a curved line
        let controlX = (start.x + end.x) / 2
        context.move(to: start)
        context.addCurve(
            to: end,
            control1: CGPoint(x: controlX, y: start.y),
            control2: CGPoint(x: controlX, y: end.y)
        )
        context.strokePath()

        // Arrowhead
        let arrowSize: CGFloat = 5
        let angle = atan2(end.y - start.y, end.x - start.x)
        context.setFillColor(color.withAlphaComponent(0.5).cgColor)
        context.move(to: end)
        context.addLine(to: CGPoint(
            x: end.x - arrowSize * cos(angle - .pi / 6),
            y: end.y - arrowSize * sin(angle - .pi / 6)
        ))
        context.addLine(to: CGPoint(
            x: end.x - arrowSize * cos(angle + .pi / 6),
            y: end.y - arrowSize * sin(angle + .pi / 6)
        ))
        context.closePath()
        context.fillPath()
    }

    // MARK: - System Summary

    private func drawSystemSummary(snapshot: SystemSnapshot, at yPosition: CGFloat, in context: CGContext) -> CGFloat {
        let availableWidth = pageRect.width - (margin * 2)

        // Section title
        let sectionFont = UIFont.systemFont(ofSize: 16, weight: .bold)
        let sectionTitle = String(localized: "overview.pdf.summary.title", defaultValue: "System Summary")
        sectionTitle.draw(
            in: CGRect(x: margin, y: yPosition, width: availableWidth, height: sectionFont.lineHeight + 4),
            withAttributes: [.font: sectionFont, .foregroundColor: primaryTextColor]
        )
        var cursorY = yPosition + sectionFont.lineHeight + 12

        // Summary grid: 2 columns × 3 rows
        let colWidth = (availableWidth - 16) / 2
        let rowHeight: CGFloat = 52

        let runtimeLabel = String(localized: "overview.pdf.summary.runtime", defaultValue: "Estimated Runtime")
        let chargeTimeLabel = String(localized: "overview.pdf.summary.chargetime", defaultValue: "Charge Time")
        let totalPowerLabel = String(localized: "overview.pdf.summary.totalpower", defaultValue: "Total Power")
        let totalCurrentLabel = String(localized: "overview.pdf.summary.totalcurrent", defaultValue: "Total Current")
        let batteryCapacityLabel = String(localized: "overview.pdf.summary.batterycapacity", defaultValue: "Battery Capacity")
        let chargerPowerLabel = String(localized: "overview.pdf.summary.chargerpower", defaultValue: "Charger Power")

        let summaryItems: [(String, String, UIColor)] = [
            (runtimeLabel, snapshot.estimatedRuntimeFormatted ?? "–", loadColor),
            (chargeTimeLabel, snapshot.estimatedChargeTimeFormatted ?? "–", chargerColor),
            (totalPowerLabel, formatPower(snapshot.totalPower), loadColor),
            (totalCurrentLabel, "\(formatNumber(snapshot.totalCurrent)) A", loadColor),
            (batteryCapacityLabel, "\(formatNumber(snapshot.totalUsableEnergy)) Wh", batteryColor),
            (chargerPowerLabel, formatPower(snapshot.totalChargerPower), chargerColor),
        ]

        for (i, item) in summaryItems.enumerated() {
            let col = i % 2
            let row = i / 2
            let x = margin + CGFloat(col) * (colWidth + 16)
            let y = cursorY + CGFloat(row) * rowHeight

            drawSummaryCard(label: item.0, value: item.1, color: item.2, rect: CGRect(x: x, y: y, width: colWidth, height: rowHeight - 8), in: context)
        }

        return cursorY + CGFloat((summaryItems.count + 1) / 2) * rowHeight + 8
    }

    private func drawSummaryCard(label: String, value: String, color: UIColor, rect: CGRect, in context: CGContext) {
        // Card background
        let path = UIBezierPath(roundedRect: rect, cornerRadius: 8)
        context.setFillColor(color.withAlphaComponent(0.06).cgColor)
        context.addPath(path.cgPath)
        context.fillPath()

        // Left accent bar
        let barRect = CGRect(x: rect.minX, y: rect.minY, width: 3, height: rect.height)
        let barPath = UIBezierPath(
            roundedRect: barRect,
            byRoundingCorners: [.topLeft, .bottomLeft],
            cornerRadii: CGSize(width: 8, height: 8)
        )
        context.setFillColor(color.cgColor)
        context.addPath(barPath.cgPath)
        context.fillPath()

        let labelFont = UIFont.systemFont(ofSize: 10, weight: .medium)
        let valueFont = UIFont.systemFont(ofSize: 16, weight: .bold)

        label.draw(
            in: CGRect(x: rect.minX + 10, y: rect.minY + 8, width: rect.width - 14, height: labelFont.lineHeight),
            withAttributes: [.font: labelFont, .foregroundColor: tertiaryTextColor]
        )
        value.draw(
            in: CGRect(x: rect.minX + 10, y: rect.minY + 8 + labelFont.lineHeight + 2, width: rect.width - 14, height: valueFont.lineHeight),
            withAttributes: [.font: valueFont, .foregroundColor: primaryTextColor]
        )
    }

    // MARK: - Detail Tables

    private func drawLoadsTable(
        loads: [LoadSnapshot],
        unitSystem: UnitSystem,
        at yPosition: CGFloat,
        in context: UIGraphicsPDFRendererContext,
        pageIndex: inout Int,
        systemName: String
    ) -> CGFloat {
        var cursorY = yPosition

        let wireUnit = unitSystem.wireAreaUnit
        let lengthUnit = unitSystem.lengthUnit

        for load in loads {
            let requiredHeight: CGFloat = 130
            cursorY = ensureSpace(requiredHeight: requiredHeight, cursorY: cursorY, context: context, pageIndex: &pageIndex, systemName: systemName)

            // Load name header
            let nameFont = UIFont.systemFont(ofSize: 14, weight: .bold)
            load.name.draw(
                in: CGRect(x: margin, y: cursorY, width: pageRect.width - margin * 2, height: nameFont.lineHeight + 2),
                withAttributes: [.font: nameFont, .foregroundColor: loadColor]
            )
            cursorY += nameFont.lineHeight + 6

            // Two-column detail grid
            let colWidth = (pageRect.width - margin * 2 - 16) / 2
            let labelFont = UIFont.systemFont(ofSize: 10, weight: .medium)
            let valueFont = UIFont.systemFont(ofSize: 11, weight: .semibold)

            let voltageLabel = String(localized: "overview.pdf.load.voltage", defaultValue: "Voltage")
            let currentLabel = String(localized: "overview.pdf.load.current", defaultValue: "Current")
            let powerLabel = String(localized: "overview.pdf.load.power", defaultValue: "Power")
            let lengthLabel = String(localized: "overview.pdf.load.length", defaultValue: "Cable Length")
            let cableLabel = String(localized: "overview.pdf.load.cable", defaultValue: "Cable Size")
            let vDropLabel = String(localized: "overview.pdf.load.vdrop", defaultValue: "Voltage Drop")
            let pLossLabel = String(localized: "overview.pdf.load.ploss", defaultValue: "Power Loss")
            let fuseLabel = String(localized: "overview.pdf.load.fuse", defaultValue: "Fuse")

            let rows: [(String, String, String, String)] = [
                (voltageLabel, "\(formatNumber(load.voltage)) V", currentLabel, "\(formatNumber(load.current)) A"),
                (powerLabel, formatPower(load.power), lengthLabel, "\(formatNumber(load.length)) \(lengthUnit)"),
                (cableLabel, "\(formatNumber(load.recommendedCrossSection)) \(wireUnit)", vDropLabel, "\(formatNumber(load.voltageDropPercent))%"),
                (pLossLabel, formatPower(load.powerLoss), fuseLabel, "\(formatNumber(load.recommendedFuse)) A"),
            ]

            for row in rows {
                // Left column
                row.0.draw(
                    in: CGRect(x: margin, y: cursorY, width: colWidth, height: labelFont.lineHeight),
                    withAttributes: [.font: labelFont, .foregroundColor: tertiaryTextColor]
                )
                row.1.draw(
                    in: CGRect(x: margin, y: cursorY + labelFont.lineHeight, width: colWidth, height: valueFont.lineHeight),
                    withAttributes: [.font: valueFont, .foregroundColor: primaryTextColor]
                )
                // Right column
                row.2.draw(
                    in: CGRect(x: margin + colWidth + 16, y: cursorY, width: colWidth, height: labelFont.lineHeight),
                    withAttributes: [.font: labelFont, .foregroundColor: tertiaryTextColor]
                )
                row.3.draw(
                    in: CGRect(x: margin + colWidth + 16, y: cursorY + labelFont.lineHeight, width: colWidth, height: valueFont.lineHeight),
                    withAttributes: [.font: valueFont, .foregroundColor: primaryTextColor]
                )

                cursorY += labelFont.lineHeight + valueFont.lineHeight + 4
            }

            // Divider
            cursorY += 4
            context.cgContext.setStrokeColor(UIColor.separator.cgColor)
            context.cgContext.setLineWidth(0.5)
            context.cgContext.move(to: CGPoint(x: margin, y: cursorY))
            context.cgContext.addLine(to: CGPoint(x: pageRect.width - margin, y: cursorY))
            context.cgContext.strokePath()
            cursorY += 12
        }

        return cursorY
    }

    private func drawBatteriesTable(
        batteries: [BatterySnapshot],
        at yPosition: CGFloat,
        in context: UIGraphicsPDFRendererContext,
        pageIndex: inout Int,
        systemName: String
    ) -> CGFloat {
        var cursorY = yPosition

        for battery in batteries {
            let requiredHeight: CGFloat = 90
            cursorY = ensureSpace(requiredHeight: requiredHeight, cursorY: cursorY, context: context, pageIndex: &pageIndex, systemName: systemName)

            let nameFont = UIFont.systemFont(ofSize: 14, weight: .bold)
            battery.name.draw(
                in: CGRect(x: margin, y: cursorY, width: pageRect.width - margin * 2, height: nameFont.lineHeight + 2),
                withAttributes: [.font: nameFont, .foregroundColor: batteryColor]
            )
            cursorY += nameFont.lineHeight + 6

            let colWidth = (pageRect.width - margin * 2 - 16) / 2
            let labelFont = UIFont.systemFont(ofSize: 10, weight: .medium)
            let valueFont = UIFont.systemFont(ofSize: 11, weight: .semibold)

            let chemistryLabel = String(localized: "overview.pdf.battery.chemistry", defaultValue: "Chemistry")
            let voltageLabel = String(localized: "overview.pdf.battery.voltage", defaultValue: "Voltage")
            let capacityLabel = String(localized: "overview.pdf.battery.capacity", defaultValue: "Capacity")
            let usableLabel = String(localized: "overview.pdf.battery.usable", defaultValue: "Usable Capacity")
            let energyLabel = String(localized: "overview.pdf.battery.energy", defaultValue: "Energy")
            let usableEnergyLabel = String(localized: "overview.pdf.battery.usableenergy", defaultValue: "Usable Energy")

            let rows: [(String, String, String, String)] = [
                (chemistryLabel, battery.chemistry, voltageLabel, "\(formatNumber(battery.nominalVoltage)) V"),
                (capacityLabel, "\(formatNumber(battery.capacityAmpHours)) Ah", usableLabel, "\(formatNumber(battery.usableCapacityAmpHours)) Ah"),
                (energyLabel, "\(formatNumber(battery.energyWattHours)) Wh", usableEnergyLabel, "\(formatNumber(battery.usableEnergyWattHours)) Wh"),
            ]

            for row in rows {
                row.0.draw(
                    in: CGRect(x: margin, y: cursorY, width: colWidth, height: labelFont.lineHeight),
                    withAttributes: [.font: labelFont, .foregroundColor: tertiaryTextColor]
                )
                row.1.draw(
                    in: CGRect(x: margin, y: cursorY + labelFont.lineHeight, width: colWidth, height: valueFont.lineHeight),
                    withAttributes: [.font: valueFont, .foregroundColor: primaryTextColor]
                )
                row.2.draw(
                    in: CGRect(x: margin + colWidth + 16, y: cursorY, width: colWidth, height: labelFont.lineHeight),
                    withAttributes: [.font: labelFont, .foregroundColor: tertiaryTextColor]
                )
                row.3.draw(
                    in: CGRect(x: margin + colWidth + 16, y: cursorY + labelFont.lineHeight, width: colWidth, height: valueFont.lineHeight),
                    withAttributes: [.font: valueFont, .foregroundColor: primaryTextColor]
                )
                cursorY += labelFont.lineHeight + valueFont.lineHeight + 4
            }

            cursorY += 4
            context.cgContext.setStrokeColor(UIColor.separator.cgColor)
            context.cgContext.setLineWidth(0.5)
            context.cgContext.move(to: CGPoint(x: margin, y: cursorY))
            context.cgContext.addLine(to: CGPoint(x: pageRect.width - margin, y: cursorY))
            context.cgContext.strokePath()
            cursorY += 12
        }

        return cursorY
    }

    private func drawChargersTable(
        chargers: [ChargerSnapshot],
        at yPosition: CGFloat,
        in context: UIGraphicsPDFRendererContext,
        pageIndex: inout Int,
        systemName: String
    ) -> CGFloat {
        var cursorY = yPosition

        for charger in chargers {
            let requiredHeight: CGFloat = 70
            cursorY = ensureSpace(requiredHeight: requiredHeight, cursorY: cursorY, context: context, pageIndex: &pageIndex, systemName: systemName)

            let nameFont = UIFont.systemFont(ofSize: 14, weight: .bold)
            charger.name.draw(
                in: CGRect(x: margin, y: cursorY, width: pageRect.width - margin * 2, height: nameFont.lineHeight + 2),
                withAttributes: [.font: nameFont, .foregroundColor: chargerColor]
            )
            cursorY += nameFont.lineHeight + 6

            let colWidth = (pageRect.width - margin * 2 - 16) / 2
            let labelFont = UIFont.systemFont(ofSize: 10, weight: .medium)
            let valueFont = UIFont.systemFont(ofSize: 11, weight: .semibold)

            let inputLabel = String(localized: "overview.pdf.charger.input", defaultValue: "Input Voltage")
            let outputLabel = String(localized: "overview.pdf.charger.output", defaultValue: "Output Voltage")
            let currentLabel = String(localized: "overview.pdf.charger.current", defaultValue: "Max Current")
            let powerLabel = String(localized: "overview.pdf.charger.power", defaultValue: "Power")

            let rows: [(String, String, String, String)] = [
                (inputLabel, "\(formatNumber(charger.inputVoltage)) V", outputLabel, "\(formatNumber(charger.outputVoltage)) V"),
                (currentLabel, "\(formatNumber(charger.maxCurrentAmps)) A", powerLabel, formatPower(charger.effectivePowerWatts)),
            ]

            for row in rows {
                row.0.draw(
                    in: CGRect(x: margin, y: cursorY, width: colWidth, height: labelFont.lineHeight),
                    withAttributes: [.font: labelFont, .foregroundColor: tertiaryTextColor]
                )
                row.1.draw(
                    in: CGRect(x: margin, y: cursorY + labelFont.lineHeight, width: colWidth, height: valueFont.lineHeight),
                    withAttributes: [.font: valueFont, .foregroundColor: primaryTextColor]
                )
                row.2.draw(
                    in: CGRect(x: margin + colWidth + 16, y: cursorY, width: colWidth, height: labelFont.lineHeight),
                    withAttributes: [.font: labelFont, .foregroundColor: tertiaryTextColor]
                )
                row.3.draw(
                    in: CGRect(x: margin + colWidth + 16, y: cursorY + labelFont.lineHeight, width: colWidth, height: valueFont.lineHeight),
                    withAttributes: [.font: valueFont, .foregroundColor: primaryTextColor]
                )
                cursorY += labelFont.lineHeight + valueFont.lineHeight + 4
            }

            cursorY += 4
            context.cgContext.setStrokeColor(UIColor.separator.cgColor)
            context.cgContext.setLineWidth(0.5)
            context.cgContext.move(to: CGPoint(x: margin, y: cursorY))
            context.cgContext.addLine(to: CGPoint(x: pageRect.width - margin, y: cursorY))
            context.cgContext.strokePath()
            cursorY += 12
        }

        return cursorY
    }

    // MARK: - Page Layout Helpers

    private func drawPageHeader(title: String, subtitle: String, in context: CGContext) -> CGFloat {
        let availableWidth = pageRect.width - (margin * 2)

        let titleFont = UIFont.systemFont(ofSize: 18, weight: .bold)
        let titleRect = CGRect(x: margin, y: margin, width: availableWidth, height: titleFont.lineHeight + 4)
        title.draw(in: titleRect, withAttributes: [
            .font: titleFont,
            .foregroundColor: primaryTextColor,
        ])

        let subtitleFont = UIFont.systemFont(ofSize: 14, weight: .semibold)
        let subtitleRect = CGRect(
            x: margin,
            y: titleRect.maxY + 4,
            width: availableWidth,
            height: subtitleFont.lineHeight + 2
        )
        subtitle.draw(in: subtitleRect, withAttributes: [
            .font: subtitleFont,
            .foregroundColor: accentColor,
        ])

        return subtitleRect.maxY + 16
    }

    private func ensureSpace(
        requiredHeight: CGFloat,
        cursorY: CGFloat,
        context: UIGraphicsPDFRendererContext,
        pageIndex: inout Int,
        systemName: String
    ) -> CGFloat {
        if cursorY + requiredHeight <= pageRect.height - margin - 20 {
            return cursorY
        }
        drawFooter(pageIndex: pageIndex, in: context.cgContext)
        pageIndex += 1
        context.beginPage()
        return drawPageHeader(
            title: systemName,
            subtitle: String(localized: "overview.pdf.continued", defaultValue: "Continued"),
            in: context.cgContext
        )
    }

    private func drawFooter(pageIndex: Int, in context: CGContext) {
        let footerFont = UIFont.systemFont(ofSize: 9, weight: .regular)
        let attributes: [NSAttributedString.Key: Any] = [
            .font: footerFont,
            .foregroundColor: tertiaryTextColor,
        ]

        // Page number
        let format = String(localized: "overview.pdf.page.number", defaultValue: "Page %d")
        let pageText = String(format: format, locale: Locale.current, pageIndex)
        let pageSize = pageText.size(withAttributes: attributes)
        pageText.draw(
            at: CGPoint(x: (pageRect.width - pageSize.width) / 2, y: pageRect.height - margin + 10),
            withAttributes: attributes
        )

        // Branding
        let brandText = "Generated by Cable"
        let brandSize = brandText.size(withAttributes: attributes)
        brandText.draw(
            at: CGPoint(x: pageRect.width - margin - brandSize.width, y: pageRect.height - margin + 10),
            withAttributes: attributes
        )
    }

    // MARK: - Formatting Helpers

    private func drawCenteredText(_ text: String, in rect: CGRect, attributes: [NSAttributedString.Key: Any]) {
        let size = text.size(withAttributes: attributes)
        let x = rect.origin.x + (rect.width - size.width) / 2
        text.draw(at: CGPoint(x: x, y: rect.origin.y), withAttributes: attributes)
    }

    private func formatNumber(_ value: Double) -> String {
        if value == 0 { return "0" }
        if value == value.rounded() && abs(value) < 10000 {
            return String(format: "%.0f", value)
        }
        return String(format: "%.1f", value)
    }

    private func formatPower(_ watts: Double) -> String {
        "\(formatNumber(watts)) W"
    }

    private func truncateText(_ text: String, font: UIFont, maxWidth: CGFloat) -> String {
        let attrs: [NSAttributedString.Key: Any] = [.font: font]
        if text.size(withAttributes: attrs).width <= maxWidth { return text }
        var truncated = text
        while truncated.count > 1 {
            truncated = String(truncated.dropLast())
            let candidate = truncated + "…"
            if candidate.size(withAttributes: attrs).width <= maxWidth {
                return candidate
            }
        }
        return "…"
    }
}

