// Hand-written FFI bindings for EXIF/CGImageSource orientation APIs.
//
// These supplement the auto-generated bindings.g.dart without modifying it.
// They bind the CoreFoundation / ImageIO symbols needed to read and apply
// the EXIF orientation tag when converting images on Darwin (iOS/macOS).
//
// Relevant Apple documentation:
// - CGImageSourceCopyPropertiesAtIndex:
//   https://developer.apple.com/documentation/imageio/cgimagesourcecopypropertiesatindex
// - CGImageSourceCreateThumbnailAtIndex:
//   https://developer.apple.com/documentation/imageio/cgimagesourcecreatethumbnailatindex
// - kCGImagePropertyOrientation:
//   https://developer.apple.com/documentation/imageio/kcgimagepropertyorientation
// - kCGImageSourceCreateThumbnailWithTransform:
//   https://developer.apple.com/documentation/imageio/kcgimagesourcecreatethumbnailwithtransform

// ignore_for_file: type=lint, non_constant_identifier_names
import 'dart:ffi' as ffi;

import 'package:objective_c/objective_c.dart' as objc;

import 'bindings.g.dart';

// ─── CGImageSource properties ────────────────────────────────────────────────

/// Copies the properties dictionary for the image at [index] inside [isrc].
///
/// Returns a retained `CFDictionaryRef` — the caller must `CFRelease` it.
/// Returns `nullptr` if the source or image is invalid.
@ffi.Native<CFDictionaryRef Function(CGImageSourceRef, ffi.Size, CFDictionaryRef)>()
external CFDictionaryRef CGImageSourceCopyPropertiesAtIndex(
  CGImageSourceRef isrc,
  int index,
  CFDictionaryRef options,
);

/// Creates an orientation-corrected image for the entry at [index].
///
/// With `kCGImageSourceCreateThumbnailWithTransform = kCFBooleanTrue` in
/// [options], ImageIO bakes the EXIF rotation and/or flip into the returned
/// pixel data, giving correctly-oriented pixels for any orientation value.
///
/// Returns a retained `CGImageRef` — the caller must `CFRelease` it.
@ffi.Native<CGImageRef Function(CGImageSourceRef, ffi.Size, CFDictionaryRef)>()
external CGImageRef CGImageSourceCreateThumbnailAtIndex(
  CGImageSourceRef isrc,
  int index,
  CFDictionaryRef options,
);

// ─── CFDictionary / CFNumber lookup ──────────────────────────────────────────

/// Returns the value associated with [key] in [theDict], or `nullptr`.
///
/// The returned pointer is not retained — do not `CFRelease` it.
@ffi.Native<ffi.Pointer<ffi.Void> Function(CFDictionaryRef, ffi.Pointer<ffi.Void>)>()
external ffi.Pointer<ffi.Void> CFDictionaryGetValue(
  CFDictionaryRef theDict,
  ffi.Pointer<ffi.Void> key,
);

/// Extracts the numeric value from a `CFNumber` into a native Dart pointer.
///
/// [theType] selects the C numeric type; 9 = `kCFNumberSInt32Type` (int32).
/// Returns `true` on success.
@ffi.Native<ffi.Bool Function(ffi.Pointer<ffi.Void>, ffi.Int32, ffi.Pointer<ffi.Void>)>()
external bool CFNumberGetValue(
  ffi.Pointer<ffi.Void> number,
  int theType,
  ffi.Pointer<ffi.Void> valuePtr,
);

// ─── ImageIO option keys ──────────────────────────────────────────────────────

/// Key: EXIF/CGImage orientation tag in CGImageSource properties dicts.
///
/// Value is a `CFNumberRef` (int32) matching `CGImagePropertyOrientation`:
/// 1=Up, 2=UpMirrored, 3=Down, 4=DownMirrored,
/// 5=LeftMirrored, 6=Right, 7=RightMirrored, 8=Left.
@ffi.Native<ffi.Pointer<objc.CFString>>()
external ffi.Pointer<objc.CFString> kCGImagePropertyOrientation;

/// Key: when `kCFBooleanTrue`, creates a thumbnail from the full image even
/// when no embedded thumbnail is present.
@ffi.Native<ffi.Pointer<objc.CFString>>()
external ffi.Pointer<objc.CFString> kCGImageSourceCreateThumbnailFromImageIfAbsent;

/// Key: when `kCFBooleanTrue`, rotates/flips the thumbnail to match the EXIF
/// orientation tag, producing pixel-correct upright image data.
@ffi.Native<ffi.Pointer<objc.CFString>>()
external ffi.Pointer<objc.CFString> kCGImageSourceCreateThumbnailWithTransform;

/// Key: maximum pixel size (longest edge) for the thumbnail.
///
/// Set this to the source image's longest edge to get full-resolution output
/// from `CGImageSourceCreateThumbnailAtIndex`.
@ffi.Native<ffi.Pointer<objc.CFString>>()
external ffi.Pointer<objc.CFString> kCGImageSourceThumbnailMaxPixelSize;
