import AppKit
import Foundation

public struct SkeletonThumbnailTemplate: Equatable, Sendable {
    public let category: AppCategory
    public let headerHeight: CGFloat
    public let contentRows: Int
    public let accentStripeCount: Int

    public init(category: AppCategory, headerHeight: CGFloat, contentRows: Int, accentStripeCount: Int) {
        self.category = category
        self.headerHeight = headerHeight
        self.contentRows = contentRows
        self.accentStripeCount = accentStripeCount
    }

    public static func template(for category: AppCategory) -> SkeletonThumbnailTemplate {
        switch category {
        case .finder:
            return SkeletonThumbnailTemplate(category: category, headerHeight: 18, contentRows: 4, accentStripeCount: 1)
        case .browser:
            return SkeletonThumbnailTemplate(category: category, headerHeight: 20, contentRows: 3, accentStripeCount: 3)
        case .terminal:
            return SkeletonThumbnailTemplate(category: category, headerHeight: 16, contentRows: 5, accentStripeCount: 0)
        case .editorIDE:
            return SkeletonThumbnailTemplate(category: category, headerHeight: 16, contentRows: 6, accentStripeCount: 2)
        case .chat:
            return SkeletonThumbnailTemplate(category: category, headerHeight: 16, contentRows: 4, accentStripeCount: 1)
        case .documentNotes:
            return SkeletonThumbnailTemplate(category: category, headerHeight: 14, contentRows: 5, accentStripeCount: 0)
        case .generic:
            return SkeletonThumbnailTemplate(category: category, headerHeight: 16, contentRows: 3, accentStripeCount: 1)
        }
    }
}

public enum SkeletonThumbnailPalette {
    public static let headerAlpha: CGFloat = 0.10
    public static let contentRowAlpha: CGFloat = 0.075
    public static let accentStripeAlpha: CGFloat = 0.28
    public static let titleBandAlpha: CGFloat = 0.86
}

@MainActor
public final class NativeSkeletonThumbnailProvider: SkeletonThumbnailProviderProtocol {
    public static let defaultSize = NSSize(width: 120, height: 80)

    private let size: NSSize

    public init(size: NSSize = NativeSkeletonThumbnailProvider.defaultSize) {
        self.size = size
    }

    public func skeleton(for app: AlignerApp) -> NSImage {
        drawSkeleton(template: SkeletonThumbnailTemplate.template(for: app.category), title: nil)
    }

    public func withOverlayTitle(_ title: String, for app: AlignerApp) -> NSImage {
        drawSkeleton(template: SkeletonThumbnailTemplate.template(for: app.category), title: title)
    }

    private func drawSkeleton(template: SkeletonThumbnailTemplate, title: String?) -> NSImage {
        let image = NSImage(size: size)
        image.lockFocus()

        let bounds = NSRect(origin: .zero, size: size)
        NSColor.windowBackgroundColor.setFill()
        NSBezierPath(roundedRect: bounds, xRadius: 6, yRadius: 6).fill()

        drawHeader(template: template, in: bounds)
        drawContentRows(template: template, in: bounds, reservesTitleBand: title != nil)
        drawAccentStripes(template: template, in: bounds)

        if let title, !title.isEmpty {
            drawTitle(title, in: bounds)
        }

        image.unlockFocus()
        return image
    }

    private func drawHeader(template: SkeletonThumbnailTemplate, in bounds: NSRect) {
        let header = NSRect(
            x: 0,
            y: bounds.height - template.headerHeight,
            width: bounds.width,
            height: template.headerHeight
        )
        color(for: template.category).withAlphaComponent(SkeletonThumbnailPalette.headerAlpha).setFill()
        NSBezierPath(roundedRect: header, xRadius: 6, yRadius: 6).fill()
    }

    private func drawContentRows(
        template: SkeletonThumbnailTemplate,
        in bounds: NSRect,
        reservesTitleBand: Bool
    ) {
        let rowHeight: CGFloat = 6
        let rowSpacing: CGFloat = 6
        let startY = bounds.height - template.headerHeight - 14
        let minimumY: CGFloat = reservesTitleBand ? 24 : 8
        let maxWidth = bounds.width - 24
        let maximumRows = max(0, Int(floor((startY - minimumY + rowSpacing) / (rowHeight + rowSpacing))))
        let rowsToDraw = min(template.contentRows, maximumRows)

        for row in 0..<rowsToDraw {
            let widthRatio = 1 - CGFloat(row % 3) * 0.18
            let rect = NSRect(
                x: 12,
                y: startY - CGFloat(row) * (rowHeight + rowSpacing),
                width: maxWidth * widthRatio,
                height: rowHeight
            )
            NSColor.secondaryLabelColor.withAlphaComponent(SkeletonThumbnailPalette.contentRowAlpha).setFill()
            NSBezierPath(roundedRect: rect, xRadius: 3, yRadius: 3).fill()
        }
    }

    private func drawAccentStripes(template: SkeletonThumbnailTemplate, in bounds: NSRect) {
        guard template.accentStripeCount > 0 else { return }

        let stripeWidth: CGFloat = 8
        for stripe in 0..<template.accentStripeCount {
            let rect = NSRect(
                x: 12 + CGFloat(stripe) * (stripeWidth + 4),
                y: bounds.height - template.headerHeight + 5,
                width: stripeWidth,
                height: max(4, template.headerHeight - 10)
            )
            color(for: template.category).withAlphaComponent(SkeletonThumbnailPalette.accentStripeAlpha).setFill()
            NSBezierPath(roundedRect: rect, xRadius: 3, yRadius: 3).fill()
        }
    }

    private func drawTitle(_ title: String, in bounds: NSRect) {
        let titleBand = NSRect(x: 0, y: 0, width: bounds.width, height: 24)
        NSColor.windowBackgroundColor.withAlphaComponent(SkeletonThumbnailPalette.titleBandAlpha).setFill()
        NSBezierPath(roundedRect: titleBand, xRadius: 6, yRadius: 6).fill()

        let paragraph = NSMutableParagraphStyle()
        paragraph.alignment = .center
        paragraph.lineBreakMode = .byTruncatingTail

        let attributes: [NSAttributedString.Key: Any] = [
            .font: NSFont.systemFont(ofSize: 10, weight: .semibold),
            .foregroundColor: NSColor.labelColor,
            .paragraphStyle: paragraph
        ]
        let rect = NSRect(x: 8, y: 6, width: bounds.width - 16, height: 14)
        title.draw(in: rect, withAttributes: attributes)
    }

    private func color(for category: AppCategory) -> NSColor {
        switch category {
        case .finder:
            return .systemBlue
        case .browser:
            return .systemTeal
        case .terminal:
            return .systemGreen
        case .editorIDE:
            return .systemPurple
        case .chat:
            return .systemMint
        case .documentNotes:
            return .systemYellow
        case .generic:
            return .tertiaryLabelColor
        }
    }
}
