//
//  Snooper.h
//  SnoopX
//
//  Created by tzhuan on 2008/8/4.
//  Copyright 2008 NTU CSIE CMLAB. All rights reserved.
//

#import <Cocoa/Cocoa.h>
#import <ApplicationServices/ApplicationServices.h>
#import <ScreenCaptureKit/ScreenCaptureKit.h>
#import <VideoToolbox/VideoToolbox.h>

#define SPACING 6

typedef enum {
	BLUE_INDEX, GREEN_INDEX, RED_INDEX, ALPHA_INDEX
} ColorIndex;

// Synchronize with tags of Graph menu items
typedef enum {
	GSNone, GSHoriStep, GSHoriLinear, GSVertStep, GSVertLinear,
	GSColorVectorscope, GSColorWaveform, GSColorHistogram
} GraphState;

#define GS_COUNT 8

// Display mode selection
typedef enum {
	DisplayModeAuto = 0,
	DisplayModeSDR = 1,
	DisplayModeHDR = 2
} DisplayMode;

// Read-only copy of the most recently captured region, used by the color-plot popup.
// SDR pixels are BGRA8 (matches captureData); HDR pixels are RGBA Float32.
typedef struct {
	BOOL isHDR;
	size_t width;
	size_t height;
	size_t bytesPerRow;
	void *pixels;  // malloc'd; owned by caller; release via -releaseFrameSnapshot:
} SnoopxFrameSnapshot;

@interface Snooper : NSObject <SCStreamDelegate, SCStreamOutput> {
	size_t zoom;
	CGFloat maxBackingScaleFactor;

	// center pixel channels
	size_t cursorRed, cursorGreen, cursorBlue, cursorAlpha;
	
	// HDR values (0.0-2.0+ range when HDR is active)
	CGFloat cursorRedHDR, cursorGreenHDR, cursorBlueHDR, cursorAlphaHDR;

	size_t mainScreenHeight;

	size_t capturePointWidth, capturePointHeight;
	size_t zoomPointWidth, zoomPointHeight;
	size_t viewPointWidth, viewPointHeight;
	NSRect capturePointRect;

	// origin is upper-left
	size_t capturePixelCenterX, capturePixelCenterY;

	// origin is lower-left
	size_t zoomPixelCenterX, zoomPixelCenterY;

	size_t gridPixelSize;

	// Actual captured buffer dimensions passed to zoom function
	size_t actualCapturedWidth, actualCapturedHeight;

	size_t capturePixelWidth, capturePixelHeight;
	size_t zoomPixelWidth, zoomPixelHeight;
	size_t viewPixelWidth, viewPixelHeight;
	size_t cropPixelX, cropPixelY;

	CGContextRef captureContext, zoomContext, viewContext;

	CGFloat cursorPointX, cursorPointY; // Changed from int to CGFloat to support physical pixel alignment on Retina
	CGFloat actualSamplePointX, actualSamplePointY; // Clamped position actually being sampled (for display)
	int cursorPixelX, cursorPixelY;

	// in pixel
	unsigned char* captureData;
	size_t captureDataWidth;
	size_t captureDataHeight;
	size_t captureDataBytesPerRow;
	// size_t captureDataCenterX, captureDataCenterY;

	// CGColor objects
	CGColorRef cgRed, cgGreen, cgBlue, cgWhite, cgBlack, cgGray;

	// For CGBitmapContext
	CGColorSpaceRef colorSpace;
	CGImageAlphaInfo alphaInfo;
	CGBitmapInfo bitmapInfo;
	size_t bitsPerComponent;
	size_t bitsPerPixel;
	size_t bytesPerPixel;
	
	// HDR support
	BOOL isHDRCapable;
	BOOL useHDRCapture;
	
	// ScreenCaptureKit (macOS 12.3+)
	SCStream *captureStream API_AVAILABLE(macos(12.3));
	SCContentFilter *contentFilter API_AVAILABLE(macos(12.3));
	CVPixelBufferRef latestPixelBuffer;
	BOOL useScreenCaptureKit;
	dispatch_semaphore_t pixelBufferSemaphore;

	GraphState graph;
	BOOL highlight;
	BOOL statistics; // Independent of graph mode
	BOOL swatch;

	DisplayMode displayMode;

	char statisticsInfoString[256];

	// SDR statistics (8-bit values 0-255)
	size_t min[3], max[3], mean[3], mediam[3];

	// HDR statistics (Float16 values 0.0-5.0+)
	CGFloat hdrMinR, hdrMinG, hdrMinB;
	CGFloat hdrMaxR, hdrMaxG, hdrMaxB;
	CGFloat hdrAvgR, hdrAvgG, hdrAvgB;
	CGFloat hdrMedR, hdrMedG, hdrMedB;

	// Most recent HDR capture region within latestPixelBuffer.
	// Populated in the HDR branch of snoopCGImageFrom; consumed by -copyFrameSnapshot:.
	size_t hdrCaptureRectX;
	size_t hdrCaptureRectY;
	size_t hdrCaptureRectWidth;
	size_t hdrCaptureRectHeight;
	BOOL hdrCaptureRectValid;
}

@property(readonly) size_t cursorRed;
@property(readonly) size_t cursorGreen;
@property(readonly) size_t cursorBlue;
@property(readonly) size_t cursorAlpha;

// HDR support - actual HDR values (0.0-2.0+) when HDR is active
@property(readonly) CGFloat cursorRedHDR;
@property(readonly) CGFloat cursorGreenHDR;
@property(readonly) CGFloat cursorBlueHDR;
@property(readonly) CGFloat cursorAlphaHDR;
@property(readonly) BOOL isHDRActive;      // True HDR content (Float16 buffer, not SDR mode)
@property(readonly) BOOL useModernPipeline; // ScreenCaptureKit active and delivering frames

@property(readwrite, assign) BOOL highlight;
@property(readwrite, assign) BOOL statistics;
@property(readwrite, assign) BOOL swatch;
@property(readwrite, assign) GraphState graph;

- (NSImage*) snoopFrom:(NSArray*)screens;
- (CGImageRef) snoopCGImageFrom:(NSArray*)screens CF_RETURNS_RETAINED; // HDR-preserving version
- (void) setZoom:(size_t)z;
- (void) setCursorPointX:(CGFloat)x Y:(CGFloat)y;
- (CGFloat) getActualSamplePointX;
- (CGFloat) getActualSamplePointY;
- (void) setViewPointWidth:(size_t)width Height:(size_t)height;
- (void) resetPointSizes;
- (void) resetPixelSizes;
- (void) resetCapturePointRect;
- (CGImageRef) getScreenshotFor:(id)screen In:(CGRect)rect;
- (CGContextRef) initCaptureContextWithImage:(CGImageRef)screenshot;
- (unsigned char*) initCaptureData;
- (CGContextRef) initZoomContext;
- (CGContextRef) getCaptureContextFrom:(NSArray*)screens;
- (CGContextRef) getZoomContext;
- (CGImageRef) getCropImage;
- (void) captureCursorColor;
- (void) drawImage:(CGImageRef)image At:(CGRect)rect;
- (void) setMainScreenHeight:(size_t)height;
- (void) setMaxBackingScaleFactor:(CGFloat)factor;
- (void) setHDRCapable:(BOOL)capable;
- (void) setDisplayMode:(DisplayMode)mode;
- (NSRect) getCurrentDisplayFrame;

// ScreenCaptureKit methods (macOS 12.3+)
- (void) setupScreenCaptureKit API_AVAILABLE(macos(12.3));
- (void) stopScreenCaptureKit API_AVAILABLE(macos(12.3));
- (BOOL) readHDRPixelFromBuffer:(CVPixelBufferRef)pixelBuffer atX:(size_t)x Y:(size_t)y API_AVAILABLE(macos(12.3));
- (NSImage*) createHDRMagnifiedImage API_AVAILABLE(macos(12.3));
- (CGImageRef) createHDRCGImageFromBuffer:(CVPixelBufferRef)pixelBuffer
									rectX:(int64_t)rectX
									rectY:(int64_t)rectY
									width:(size_t)width
								   height:(size_t)height
									 zoom:(size_t)zoomFactor API_AVAILABLE(macos(12.3));
- (BOOL) extractRegionFromYCbCrBuffer:(CVPixelBufferRef)pixelBuffer
                               toData:(unsigned char*)data
                                width:(size_t)dataWidth
                               height:(size_t)dataHeight
                         bytesPerRow:(size_t)dataBytesPerRow
                               rectX:(size_t)rectX
                               rectY:(size_t)rectY API_AVAILABLE(macos(12.3));
- (BOOL) extractRegionFromHDRBuffer:(CVPixelBufferRef)pixelBuffer 
                             toData:(unsigned char*)data
                              width:(size_t)dataWidth
                             height:(size_t)dataHeight
                       bytesPerRow:(size_t)dataBytesPerRow
                             rectX:(size_t)rectX
                             rectY:(size_t)rectY API_AVAILABLE(macos(12.3));

- (void) drawCenter;
- (void) drawHorizontalGraph;
- (void) drawVerticalGraph;
- (void) drawGraphCanvasWithRect:(CGRect)rect;
- (void) drawGraph;
- (void) drawStatistics;

- (NSString*) createStatisticsInfoString;

// Color-plot popup support: copy the most recently captured region into a caller-owned buffer.
// Returns YES on success. On HDR-active streams pixels are RGBA Float32; otherwise BGRA8.
- (BOOL) copyFrameSnapshot:(SnoopxFrameSnapshot*)outSnap;
- (void) releaseFrameSnapshot:(SnoopxFrameSnapshot*)snap;

// - (unsigned char*) getNormalizedBitmapDataFrom:(CGImageRef)image with:(BOOL*)shouldFree;

@end
