import AppKit


enum ImageLoaderError: Error
{
	case loadFailed(_ message: String)
}

struct NSImageLoader: LoaderProtocol
{
	typealias T = Image

	func load(url: URL) -> T?
	{
		guard let image = try? NSImageLoader.loadImage(url: url) else { return nil }
		return image
	}

	func load(url: URL, content: inout ContentManager) -> T? { return load(url: url) }

	static func loadImage(url: URL) throws -> Image
	{
		try autoreleasepool
		{
			// Open as a Core Graphics image
			guard let nsImg = NSImage(contentsOf: url),
				let image = nsImg.cgImage(forProposedRect: nil, context: nil, hints: nil)
			else { throw ImageLoaderError.loadFailed("Failed to open image \"\(url.absoluteString)\"") }

			// Convert to 8-bit ARGB (SRGB) w/ premultiplied alpha
			let alphaInfo = image.alphaInfo == .none ? CGImageAlphaInfo.noneSkipLast : CGImageAlphaInfo.premultipliedLast
			guard let colourspace = CGColorSpace(name: CGColorSpace.sRGB),
				let context = CGContext(data: nil,
				width: image.width,
				height: image.height,
				bitsPerComponent: 8,
				bytesPerRow: image.width * 4,
				space: colourspace,
				bitmapInfo: alphaInfo.rawValue | CGBitmapInfo.byteOrder32Big.rawValue)
			else { throw ImageLoaderError.loadFailed("Coudn't create graphics context") }
			let flipVertical = CGAffineTransform(a: 1, b: 0, c: 0, d: -1, tx: 0, ty: CGFloat(image.height))
			context.concatenate(flipVertical)
			context.draw(image, in: CGRect(x: 0, y: 0, width: image.width, height: image.height))

			guard let data = context.data else { throw ImageLoaderError.loadFailed("what") }
			return Image(
				pixels: Data(bytes: data, count: 4 * image.width * image.height),
				width: image.width,
				height: image.height)
		}
	}
}
