import AppKit
import XCTest
@testable import SiliconPulseApp
@testable import SiliconPulseCore

@MainActor
final class GaugeRenderTests: XCTestCase {
    func test_menuBarRendererProducesExpectedPixelSize() {
        let model = GaugeModel(
            domain: .cpu,
            bucket: .yellow,
            fillFraction: 0.6,
            displayValue: "66 C")

        let image = GaugeImageRenderer.renderMenuBarImage(for: model, scale: 2)

        XCTAssertNotNil(image)
        XCTAssertEqual(image?.size.width, 22)
        XCTAssertEqual(image?.size.height, 22)
        XCTAssertTrue(image?.isTemplate == false)
    }

    func test_distinctGaugeStatesProduceDistinctBitmaps() throws {
        let red = GaugeModel(domain: .cpu, bucket: .red, fillFraction: 1, displayValue: "99 C")
        let normal = GaugeModel(domain: .cpu, bucket: .white, fillFraction: 0, displayValue: "35 C")
        let noData = GaugeModel(domain: .gpu, bucket: .white, fillFraction: nil, displayValue: "No data")

        let redData = try XCTUnwrap(GaugeImageRenderer.renderMenuBarImage(for: red, scale: 2)?.pngData())
        let normalData = try XCTUnwrap(GaugeImageRenderer.renderMenuBarImage(for: normal, scale: 2)?.pngData())
        let noDataData = try XCTUnwrap(GaugeImageRenderer.renderMenuBarImage(for: noData, scale: 2)?.pngData())

        XCTAssertNotEqual(redData, normalData)
        XCTAssertNotEqual(normalData, noDataData)
        XCTAssertNotEqual(redData, noDataData)
    }

    func test_menuBarRendererFillsVerticallyFromBottom() throws {
        let model = GaugeModel(domain: .memory, bucket: .yellow, fillFraction: 0.5, displayValue: "50%")
        let image = try XCTUnwrap(GaugeImageRenderer.renderMenuBarImage(for: model, scale: 2))
        let bitmap = try XCTUnwrap(image.bitmap())

        let centerX = bitmap.pixelsWide / 2
        let lowerSample = try XCTUnwrap(bitmap.colorAt(x: centerX, y: Int(Double(bitmap.pixelsHigh) * 0.72)))
        let upperSample = try XCTUnwrap(bitmap.colorAt(x: centerX, y: Int(Double(bitmap.pixelsHigh) * 0.25)))

        XCTAssertGreaterThan(lowerSample.alphaComponent, 0.45)
        XCTAssertLessThan(upperSample.alphaComponent, 0.35)
    }

    func test_menuBarRendererKeepsThermometerColumnNarrowerThanCircle() throws {
        let model = GaugeModel(domain: .gpu, bucket: .red, fillFraction: 1, displayValue: "99 C")
        let image = try XCTUnwrap(GaugeImageRenderer.renderMenuBarImage(for: model, scale: 2))
        let bitmap = try XCTUnwrap(image.bitmap())

        let centerY = bitmap.pixelsHigh / 2
        let centerX = bitmap.pixelsWide / 2
        let center = try XCTUnwrap(bitmap.colorAt(x: centerX, y: centerY))
        let side = try XCTUnwrap(bitmap.colorAt(x: Int(Double(bitmap.pixelsWide) * 0.15), y: centerY))

        XCTAssertGreaterThan(center.alphaComponent, 0.45)
        XCTAssertLessThan(side.alphaComponent, 0.25)
    }
}

private extension NSImage {
    func pngData() -> Data? {
        guard let tiffRepresentation,
              let bitmap = NSBitmapImageRep(data: tiffRepresentation)
        else { return nil }
        return bitmap.representation(using: .png, properties: [:])
    }

    func bitmap() -> NSBitmapImageRep? {
        guard let tiffRepresentation else { return nil }
        return NSBitmapImageRep(data: tiffRepresentation)
    }
}
