import { NativeModulesProxy, EventEmitter, requireNativeViewManager } from 'expo-modules-core'
import { ViewProps } from 'react-native'
import React from 'react'

// Get the native module
const ImageEditorNativeModule = NativeModulesProxy.ImageEditor

// Helper to check module availability
function ensureModuleAvailable() {
  if (!ImageEditorNativeModule) {
    throw new Error(
      'ImageEditorSDK native module is not available. ' +
      'Make sure you have:\n' +
      '1. Installed the package: npm install @vitaliez/react-native-image-editor-sdk\n' +
      '2. Run: npx expo prebuild --clean\n' +
      '3. Rebuilt the app: npx expo run:ios\n' +
      '4. Restarted Metro bundler'
    )
  }
}

// Create event emitter lazily to avoid init errors
const createEventEmitter = () => {
  ensureModuleAvailable()
  return new EventEmitter(ImageEditorNativeModule as any)
}

// MARK: - Types

export interface ImageAdjustments {
  brightness?: number      // -1.0 to 1.0
  contrast?: number         // 0.0 to 2.0
  saturation?: number       // 0.0 to 2.0
  exposure?: number         // -2.0 to 2.0
  highlights?: number       // 0.0 to 1.0
  shadows?: number          // -1.0 to 1.0
  temperature?: number      // -1.0 to 1.0
  tint?: number             // -150 to 150
  sharpness?: number        // 0.0 to 2.0
  noiseReduction?: number   // 0.0 to 1.0
  vignette?: number         // 0.0 to 1.0
}

export type FilterPreset =
  | 'vintage'
  | 'dramatic'
  | 'mono'
  | 'noir'
  | 'fade'
  | 'chrome'
  | 'process'
  | 'transfer'
  | 'instant'
  | 'warm'
  | 'cool'

export interface FilterOptions {
  type: FilterPreset
  intensity?: number  // 0.0 to 1.0, default 1.0
}

export interface CropParams {
  x: number
  y: number
  width: number
  height: number
}

export interface ResizeParams {
  width: number
  height: number
}

export type ExportFormat = 'jpeg' | 'png' | 'heic'

export interface ExportOptions {
  format?: ExportFormat
  quality?: number  // 0.0 to 1.0, for JPEG and HEIC
  maxDimension?: number  // Maximum width/height (for thumbnails/previews)
}

export interface ExportResult {
  success: boolean
  uri: string
  size: number
}

export interface ImageLoadedEvent {
  width: number
  height: number
}

export interface ImageSource {
  uri?: string
  path?: string
}

/**
 * LUT (Look-Up Table) options for color grading
 */
export interface LUTOptions {
  name: string        // Unique identifier for the LUT
  filePath: string    // Path to .cube file
}

export interface LUTApplyOptions {
  name: string        // Previously loaded LUT name
  intensity?: number  // 0.0 to 1.0, default 1.0
}

// MARK: - Module API

export const ImageEditorModule = {
  /**
   * Load an image from a file path or URI
   */
  async loadImage(path: string): Promise<ImageLoadedEvent> {
    ensureModuleAvailable()
    return await ImageEditorNativeModule.loadImage(path)
  },

  /**
   * Apply adjustments to the current image
   */
  async applyAdjustments(adjustments: ImageAdjustments): Promise<{ success: boolean }> {
    ensureModuleAvailable()
    return await ImageEditorNativeModule.applyAdjustments(adjustments)
  },

  /**
   * Apply a preset filter
   */
  async applyFilter(filterType: FilterPreset, intensity: number = 1.0): Promise<{ success: boolean }> {
    ensureModuleAvailable()
    return await ImageEditorNativeModule.applyFilter(filterType, intensity)
  },

  /**
   * Crop the image to the specified rectangle
   */
  async crop(params: CropParams): Promise<ImageLoadedEvent & { success: boolean }> {
    ensureModuleAvailable()
    return await ImageEditorNativeModule.crop(params.x, params.y, params.width, params.height)
  },

  /**
   * Rotate the image by the specified angle (in radians)
   */
  async rotate(angle: number): Promise<{ success: boolean }> {
    ensureModuleAvailable()
    return await ImageEditorNativeModule.rotate(angle)
  },

  /**
   * Flip the image horizontally
   */
  async flipHorizontal(): Promise<{ success: boolean }> {
    ensureModuleAvailable()
    return await ImageEditorNativeModule.flipHorizontal()
  },

  /**
   * Flip the image vertically
   */
  async flipVertical(): Promise<{ success: boolean }> {
    ensureModuleAvailable()
    return await ImageEditorNativeModule.flipVertical()
  },

  /**
   * Resize the image to the specified dimensions
   */
  async resize(params: ResizeParams): Promise<{ success: boolean }> {
    ensureModuleAvailable()
    return await ImageEditorNativeModule.resize(params.width, params.height)
  },

  /**
   * Undo the last operation
   * @returns true if undo was successful
   */
  undo(): boolean {
    ensureModuleAvailable()
    return ImageEditorNativeModule.undo()
  },

  /**
   * Redo the last undone operation
   * @returns true if redo was successful
   */
  redo(): boolean {
    ensureModuleAvailable()
    return ImageEditorNativeModule.redo()
  },

  /**
   * Check if undo is available
   */
  canUndo(): boolean {
    ensureModuleAvailable()
    return ImageEditorNativeModule.canUndo()
  },

  /**
   * Check if redo is available
   */
  canRedo(): boolean {
    ensureModuleAvailable()
    return ImageEditorNativeModule.canRedo()
  },

  /**
   * Export the current image
   */
  async export(options: ExportOptions = {}): Promise<ExportResult> {
    ensureModuleAvailable()
    return await ImageEditorNativeModule.export(options)
  },

  /**
   * Get list of available filter presets
   */
  getAvailableFilters(): FilterPreset[] {
    ensureModuleAvailable()
    return ImageEditorNativeModule.getAvailableFilters()
  },

  /**
   * Load a LUT (Look-Up Table) from a .cube file for later use
   * @param options LUT loading options
   */
  async loadLUT(options: LUTOptions): Promise<{ success: boolean; name: string }> {
    ensureModuleAvailable()
    return await ImageEditorNativeModule.loadLUT(options.name, options.filePath)
  },

  /**
   * Apply a previously loaded LUT to the current image
   * @param options LUT application options
   */
  async applyLUT(options: LUTApplyOptions): Promise<{ success: boolean; intensity: number }> {
    ensureModuleAvailable()
    const intensity = options.intensity ?? 1.0
    return await ImageEditorNativeModule.applyLUT(options.name, intensity)
  },

  /**
   * Clear all cached LUTs from memory
   */
  clearLUTCache(): void {
    ensureModuleAvailable()
    ImageEditorNativeModule.clearLUTCache()
  },

  /**
   * Reset the editor and clear the current image
   */
  reset(): void {
    ensureModuleAvailable()
    ImageEditorNativeModule.reset()
  },

  // Event listeners (create emitter per subscription to avoid init errors)
  addImageLoadedListener(listener: (event: ImageLoadedEvent) => void) {
    return (createEventEmitter() as any).addListener('onImageLoaded', listener)
  },

  addImageUpdatedListener(listener: () => void) {
    return (createEventEmitter() as any).addListener('onImageUpdated', listener)
  },

  addExportProgressListener(listener: (progress: number) => void) {
    return (createEventEmitter() as any).addListener('onExportProgress', listener)
  },

  addErrorListener(listener: (event: { error: string }) => void) {
    return (createEventEmitter() as any).addListener('onError', listener)
  },
}

// MARK: - View Component

export interface ImageEditorViewProps extends ViewProps {
  /**
   * Image source to load
   */
  source?: ImageSource

  /**
   * Adjustments to apply
   */
  adjustments?: ImageAdjustments

  /**
   * Filter to apply
   */
  filter?: FilterOptions

  /**
   * Enable drawing mode
   */
  drawingEnabled?: boolean

  /**
   * Drawing brush size
   */
  drawingBrushSize?: number

  /**
   * Drawing color (hex string)
   */
  drawingColor?: string

  /**
   * Called when the view is ready
   */
  onReady?: () => void

  /**
   * Called when an image is loaded
   */
  onImageLoaded?: (event: { nativeEvent: ImageLoadedEvent }) => void

  /**
   * Called when the image changes
   */
  onImageChanged?: (event: { nativeEvent: ImageLoadedEvent }) => void

  /**
   * Called when an error occurs
   */
  onError?: (event: { nativeEvent: { error: string } }) => void
}

// Get the native view manager
const NativeView = requireNativeViewManager('ImageEditorView')

/**
 * Native image editor view component
 */
export class ImageEditorView extends React.Component<ImageEditorViewProps> {
  private nativeRef = React.createRef<any>();

  /**
   * Crop the image
   */
  async crop(params: CropParams): Promise<void> {
    if (this.nativeRef.current) {
      await this.nativeRef.current.crop(params.x, params.y, params.width, params.height)
    }
  }

  /**
   * Rotate the image
   */
  async rotate(angle: number): Promise<void> {
    if (this.nativeRef.current) {
      await this.nativeRef.current.rotate(angle)
    }
  }

  /**
   * Flip horizontally
   */
  async flipHorizontal(): Promise<void> {
    if (this.nativeRef.current) {
      await this.nativeRef.current.flipHorizontal()
    }
  }

  /**
   * Flip vertically
   */
  async flipVertical(): Promise<void> {
    if (this.nativeRef.current) {
      await this.nativeRef.current.flipVertical()
    }
  }

  /**
   * Undo last operation
   */
  async undo(): Promise<void> {
    if (this.nativeRef.current) {
      await this.nativeRef.current.undo()
    }
  }

  /**
   * Redo last operation
   */
  async redo(): Promise<void> {
    if (this.nativeRef.current) {
      await this.nativeRef.current.redo()
    }
  }

  /**
   * Export the current image
   */
  async export(options: ExportOptions = {}): Promise<ExportResult> {
    if (this.nativeRef.current) {
      return await this.nativeRef.current.export(options)
    }
    throw new Error('View not ready')
  }

  render() {
    return (
      <NativeView
        ref={this.nativeRef}
        {...this.props}
      />
    )
  }
}

// Export UI component
export { ImageEditorUI, ImageEditorUIPresets } from './ImageEditorUI'
export type {
  ImageEditorUIProps,
  ImageEditorUIConfig,
  ImageEditorUIRef
} from './ImageEditorUI'

// Default export
export default {
  ImageEditorModule,
  ImageEditorView,
}
