import Foundation
import UIKit

struct SystemBillOfMaterialsPDFExporter {
    private let pageRect = CGRect(x: 0, y: 0, width: 595, height: 842) // A4 portrait in points
    private let margin: CGFloat = 40
    private let primaryTextColor = UIColor.black
    private let secondaryTextColor = UIColor.darkGray
    private let tertiaryTextColor = UIColor.gray
    private let accentColor = UIColor(red: 0.45, green: 0.34, blue: 0.86, alpha: 1)

    func export(
        systemName: String,
        unitSystem: UnitSystem,
        sections: [BillOfMaterialsSectionSnapshot]
    ) throws -> URL {
        let format = UIGraphicsPDFRendererFormat()
        let renderer = UIGraphicsPDFRenderer(bounds: pageRect, format: format)
        var pageIndex = 1

        let data = renderer.pdfData { context in
            var cursorY = beginPage(
                context: context,
                pageIndex: pageIndex,
                systemName: systemName,
                unitSystem: unitSystem,
                isFirstPage: true
            )

            if sections.isEmpty {
                cursorY = ensureSpace(
                    requiredHeight: 60,
                    cursorY: cursorY,
                    context: context,
                    pageIndex: &pageIndex,
                    systemName: systemName,
                    unitSystem: unitSystem
                )
                let emptyMessage = String(
                    localized: "bom.pdf.placeholder.empty",
                    defaultValue: "No components available."
                )
                drawPlaceholder(in: context.cgContext, text: emptyMessage, at: cursorY)
            } else {
                for section in sections {
                    let requiredHeight = sectionHeight(for: section)
                    cursorY = ensureSpace(
                        requiredHeight: requiredHeight,
                        cursorY: cursorY,
                        context: context,
                        pageIndex: &pageIndex,
                        systemName: systemName,
                        unitSystem: unitSystem
                    )

                    cursorY = drawSectionHeader(
                        title: section.title,
                        subtitle: section.subtitle,
                        at: cursorY,
                        in: context.cgContext
                    )

                    for item in section.items {
                        cursorY = drawItem(item, at: cursorY, in: context.cgContext)
                        cursorY += 12
                    }

                    cursorY += 8
                }
            }

            drawFooter(pageIndex: pageIndex, in: context.cgContext)
        }

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

    private func beginPage(
        context: UIGraphicsPDFRendererContext,
        pageIndex: Int,
        systemName: String,
        unitSystem: UnitSystem,
        isFirstPage: Bool
    ) -> CGFloat {
        context.beginPage()
        let titleFont = UIFont.systemFont(ofSize: isFirstPage ? 26 : 18, weight: .bold)
        let subtitleFont = UIFont.systemFont(ofSize: isFirstPage ? 16 : 12, weight: .medium)
        let title = isFirstPage
            ? String(
                localized: "bom.pdf.header.title",
                defaultValue: "System Bill of Materials"
            )
            : systemName

        let subtitle: String
        if isFirstPage {
            let format = String(
                localized: "bom.pdf.header.subtitle",
                defaultValue: "%@ • %@"
            )
            subtitle = String(
                format: format,
                locale: Locale.current,
                systemName,
                unitSystem.displayName
            )
        } else {
            let format = String(
                localized: "bom.pdf.header.inline",
                defaultValue: "Unit System: %@"
            )
            subtitle = String(
                format: format,
                locale: Locale.current,
                unitSystem.displayName
            )
        }

        let availableWidth = pageRect.width - (margin * 2)
        let titleRect = CGRect(x: margin, y: margin, width: availableWidth, height: titleFont.lineHeight + 4)
        title.draw(in: titleRect, withAttributes: [
            .font: titleFont,
            .foregroundColor: primaryTextColor
        ])

        let subtitleRect = CGRect(
            x: margin,
            y: titleRect.maxY + 4,
            width: availableWidth,
            height: subtitleFont.lineHeight + 2
        )
        subtitle.draw(in: subtitleRect, withAttributes: [
            .font: subtitleFont,
            .foregroundColor: secondaryTextColor
        ])

        return subtitleRect.maxY + (isFirstPage ? 24 : 12)
    }

    private func ensureSpace(
        requiredHeight: CGFloat,
        cursorY: CGFloat,
        context: UIGraphicsPDFRendererContext,
        pageIndex: inout Int,
        systemName: String,
        unitSystem: UnitSystem
    ) -> CGFloat {
        if cursorY + requiredHeight <= pageRect.height - margin {
            return cursorY
        }

        drawFooter(pageIndex: pageIndex, in: context.cgContext)
        pageIndex += 1
        return beginPage(
            context: context,
            pageIndex: pageIndex,
            systemName: systemName,
            unitSystem: unitSystem,
            isFirstPage: false
        )
    }

    private var sectionHeaderHeight: CGFloat {
        let headerFont = UIFont.systemFont(ofSize: 18, weight: .semibold)
        let subtitleFont = UIFont.systemFont(ofSize: 12, weight: .medium)
        return headerFont.lineHeight + subtitleFont.lineHeight + 14
    }

    private func sectionHeight(for section: BillOfMaterialsSectionSnapshot) -> CGFloat {
        let itemsHeight = section.items.reduce(0) { partialResult, item in
            partialResult + itemBlockHeight(for: item) + 12
        }
        return sectionHeaderHeight + itemsHeight + 8
    }

    private func drawSectionHeader(title: String, subtitle: String, at yPosition: CGFloat, in context: CGContext) -> CGFloat {
        var cursorY = yPosition
        let headerFont = UIFont.systemFont(ofSize: 18, weight: .semibold)
        let subtitleFont = UIFont.systemFont(ofSize: 12, weight: .medium)
        let availableWidth = pageRect.width - (margin * 2)

        title.draw(
            in: CGRect(x: margin, y: cursorY, width: availableWidth, height: headerFont.lineHeight + 4),
            withAttributes: [
                .font: headerFont,
                .foregroundColor: primaryTextColor
            ]
        )
        cursorY += headerFont.lineHeight + 4

        subtitle.draw(
            in: CGRect(x: margin, y: cursorY, width: availableWidth, height: subtitleFont.lineHeight + 2),
            withAttributes: [
                .font: subtitleFont,
                .foregroundColor: secondaryTextColor
            ]
        )
        cursorY += subtitleFont.lineHeight + 10

        return cursorY
    }

    private func itemBlockHeight(for item: BillOfMaterialsItemSnapshot) -> CGFloat {
        let metricFont = UIFont.systemFont(ofSize: 13, weight: .semibold)
        let titleFont = UIFont.systemFont(ofSize: 14, weight: item.isPrimaryComponent ? .semibold : .medium)
        let detailFont = UIFont.systemFont(ofSize: 12, weight: .regular)
        var height: CGFloat = 0
        if item.metric != nil {
            height += metricFont.lineHeight + 2
        }
        height += titleFont.lineHeight + 2
        if !item.detail.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
            height += detailFont.lineHeight + 4
        }
        return height + 4
    }

    private func drawItem(_ item: BillOfMaterialsItemSnapshot, at yPosition: CGFloat, in context: CGContext) -> CGFloat {
        let metricFont = UIFont.systemFont(ofSize: 13, weight: .semibold)
        let titleFont = UIFont.systemFont(ofSize: 14, weight: item.isPrimaryComponent ? .semibold : .medium)
        let detailFont = UIFont.systemFont(ofSize: 12, weight: .regular)
        let titleAttributes: [NSAttributedString.Key: Any] = [
            .font: titleFont,
            .foregroundColor: primaryTextColor
        ]
        let detailAttributes: [NSAttributedString.Key: Any] = [
            .font: detailFont,
            .foregroundColor: secondaryTextColor
        ]
        let metricAttributes: [NSAttributedString.Key: Any] = [
            .font: metricFont,
            .foregroundColor: accentColor
        ]

        let bulletWidth: CGFloat = 6
        let spacing: CGFloat = 8
        let availableWidth = pageRect.width - (margin * 2) - bulletWidth - spacing
        let firstLineHeight = item.metric != nil ? metricFont.lineHeight : titleFont.lineHeight
        let bulletRect = CGRect(
            x: margin,
            y: yPosition + (firstLineHeight / 2) - (bulletWidth / 2),
            width: bulletWidth,
            height: bulletWidth
        )
        context.setFillColor(accentColor.cgColor)
        context.fillEllipse(in: bulletRect)

        var cursorY = yPosition
        let textX = margin + bulletWidth + spacing

        if let metric = item.metric {
            let metricRect = CGRect(x: textX, y: cursorY, width: availableWidth, height: metricFont.lineHeight + 2)
            metric.draw(in: metricRect, withAttributes: metricAttributes)
            cursorY = metricRect.maxY + 2
        }

        let titleRect = CGRect(
            x: textX,
            y: cursorY,
            width: availableWidth,
            height: titleFont.lineHeight + 2
        )
        item.title.draw(in: titleRect, withAttributes: titleAttributes)
        cursorY = titleRect.maxY + 2

        if !item.detail.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
            let detailRect = CGRect(
                x: textX,
                y: cursorY,
                width: availableWidth,
                height: detailFont.lineHeight + 4
            )
            item.detail.draw(in: detailRect, withAttributes: detailAttributes)
            cursorY = detailRect.maxY
        }

        return cursorY
    }

    private func drawFooter(pageIndex: Int, in context: CGContext) {
        let footerFont = UIFont.systemFont(ofSize: 11, weight: .regular)
        let attributes: [NSAttributedString.Key: Any] = [
            .font: footerFont,
            .foregroundColor: tertiaryTextColor
        ]
        let format = String(
            localized: "bom.pdf.page.number",
            defaultValue: "Page %d"
        )
        let text = String(format: format, locale: Locale.current, pageIndex)
        let size = text.size(withAttributes: attributes)
        let origin = CGPoint(
            x: (pageRect.width - size.width) / 2,
            y: pageRect.height - margin + 10
        )
        text.draw(at: origin, withAttributes: attributes)
    }

    private func drawPlaceholder(in context: CGContext, text: String, at yPosition: CGFloat) {
        let font = UIFont.systemFont(ofSize: 14, weight: .regular)
        let attributes: [NSAttributedString.Key: Any] = [
            .font: font,
            .foregroundColor: secondaryTextColor
        ]
        text.draw(
            in: CGRect(x: margin, y: yPosition, width: pageRect.width - (margin * 2), height: font.lineHeight + 4),
            withAttributes: attributes
        )
    }
}
