/*
 * Copyright (C) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
// Import the complete async request package
import { AsyncCallback, Callback, BusinessError } from '@ohos.base';
import image from '@ohos.multimedia.image';

// RejectString
type RejectString = (e: BusinessError<string>) => void;

namespace effectKit {
  loadLibrary('effectKit_ani')

  export enum TileMode {
    CLAMP,
    REPEAT,
    MIRROR,
    DECAL
  }

  /**
   * The Filter of FilterChain.
   * @typedef Filter
   * @syscap SystemCapability.Multimedia.Image.Core
   * @since 9
   */
  /**
   * The Filter of FilterChain.
   * @typedef Filter
   * @syscap SystemCapability.Multimedia.Image.Core
   * @form
   * @atomicservice
   * @since 12
   */

  export interface Color {
    red: int;
    green: int;
    blue: int;
    alpha: int;
  }

  export class ColorInternal implements Color {
    red: int;
    green: int;
    blue: int;
    alpha: int;
  }
  
  export interface Filter {
    /**
    * A blur effect is added to the image.
    * @param { double } radius - The degree of blur, the value is measured in pixels.
    * @returns { Filter } Filters for the current effect have been added.
    * @syscap SystemCapability.Multimedia.Image.Core
    * @since 9
    */
    /**
    * A blur effect is added to the image.
    * @param { double } radius - The degree of blur, the value is measured in pixels.
    * @returns { Filter } Filters for the current effect have been added.
    * @syscap SystemCapability.Multimedia.Image.Core
    * @form
    * @atomicservice
    * @since 12
    */
    blur(radius: double): Filter;

    /**
    * A Grayscale effect is added to the image.
    * @returns { Filter } Filters for the current effect have been added.
    * @syscap SystemCapability.Multimedia.Image.Core
    * @since 9
    */
    /**
    * A Grayscale effect is added to the image.
    * @returns { Filter } Filters for the current effect have been added.
    * @syscap SystemCapability.Multimedia.Image.Core
    * @form
    * @atomicservice
    * @since 12
    */
    /**
    * A Grayscale effect is added to the image.
    * @returns { Filter } Filters for the current effect have been added.
    * @syscap SystemCapability.Multimedia.Image.Core
    * @form
    * @atomicservice
    * @since 14
    */
    grayscale(): Filter;

    /**
    * Gets the PixelMap where all filter effects have been added to the image.
    * @returns { Promise<image.PixelMap> } - returns the PixelMap generated.
    * @syscap SystemCapability.Multimedia.Image.Core
    * @since 11
    */
    /**
    * Gets the PixelMap where all filter effects have been added to the image.
    * @returns { Promise<image.PixelMap> } - returns the PixelMap generated.
    * @syscap SystemCapability.Multimedia.Image.Core
    * @form
    * @atomicservice
    * @since 12
    */
    getEffectPixelMap(): Promise<image.PixelMap>;

    /**
    * Gets the PixelMap where all filter effects have been added to the image.
    * @param { boolean } useCpuRender - The value indicates whether to use CPU rendering.
    * @returns { Promise<image.PixelMap> } - returns the PixelMap generated.
    * @syscap SystemCapability.Multimedia.Image.Core
    * @since 11
    */
    /**
    * Gets the PixelMap where all filter effects have been added to the image.
    * @param { boolean } useCpuRender - The value indicates whether to use CPU rendering.
    * @returns { Promise<image.PixelMap> } - returns the PixelMap generated.
    * @syscap SystemCapability.Multimedia.Image.Core
    * @form
    * @atomicservice
    * @since 12
    */
    getEffectPixelMap(useCpuRender: boolean): Promise<image.PixelMap>;
    
    /**
     * Adds the blur effect to the filter linked list, and returns the head node of the linked list.
     * @param { double } radius - Blur radius, in pixels. The blur effect is proportional to the configured value.
     * A larger value indicates a more obvious effect.
     * @param { TileMode } tileMode - Tile mode of the shader effect. The blur effect of image edges is affected. Currently,
     * only CPU rendering is supported. Therefore, the tile mode supports only DECAL.
     * @returns { Filter } Final image effect.
     * @syscap SystemCapability.Multimedia.Image.Core
     * @since 14
     */
    blur(radius: double, tileMode: TileMode): Filter;

    /**
     * A Brightness effect is added to the image.
     * @param { double } bright - The degree of light and darkness,the value range is 0 to 1.
     * @returns { Filter } Filters for the current effect have been added.
     * @syscap SystemCapability.Multimedia.Image.Core
     * @since 9
     */
    /**
     * A Brightness effect is added to the image.
     * @param { double } bright - The degree of light and darkness,the value range is 0 to 1.
     * @returns { Filter } Filters for the current effect have been added.
     * @syscap SystemCapability.Multimedia.Image.Core
     * @form
     * @atomicservice
     * @since 12
     */
    /**
     * Adds the brightness effect to the filter linked list, and returns the head node of the linked list.
     * @param { double } bright - Brightness value, ranging from 0 to 1. When the value is 0, the image brightness remains unchanged.
     * @returns { Filter } Final image effect.
     * @syscap SystemCapability.Multimedia.Image.Core
     * @crossplatform
     * @form
     * @atomicservice
     * @since 14
     */
    brightness(bright: double): Filter;

    /**
     * A invert effect is added to the image.
     * @returns { Filter } Filters for the current effect have been added.
     * @syscap SystemCapability.Multimedia.Image.Core
     * @since 12
     */
    /**
     * Adds the inversion effect to the filter linked list, and returns the head node of the linked list.
     * @returns { Filter } Final image effect.
     * @syscap SystemCapability.Multimedia.Image.Core
     * @crossplatform
     * @since 14
     */
    invert(): Filter;

    /**
     * A custom effect is added to the image.
     *
     * @param { Array<double> } colorMatrix - A matrix of 5x4 size for create effect filter.
     * @returns { Filter } Filters for the current effect have been added.
     * @throws { BusinessError } 401 - Input parameter error.
     * @syscap SystemCapability.Multimedia.Image.Core
     * @since 12
     */
    /**
     * Adds a custom effect to the filter linked list, and returns the head node of the linked list.
     *
     * @param { Array<double> } colorMatrix - Custom color matrix.
     * A 5 x 4 matrix can be created. The value range of the matrix element is [0, 1],
     * where 0 indicates that the color channel is not involved in the calculation,
     * and 1 indicates that the color channel is involved in the calculation and retains the original weight.
     * @returns { Filter } Final image effect.
     * @throws { BusinessError } 401 - Input parameter error.
     * @syscap SystemCapability.Multimedia.Image.Core
     * @crossplatform
     * @since 14
     */
    setColorMatrix(colorMatrix: Array<double>): Filter;

    /**
     * Obtains image.PixelMap of the source image to which the filter linked list is added.
     * @returns { image.PixelMap } image.PixelMap.
     * @syscap SystemCapability.Multimedia.Image.Core
     * @since 9
     * @deprecated since 11
     * @useinstead effectKit.Filter#getEffectPixelMap
     */
    getPixelMap(): image.PixelMap;

  }


  export class FilterInternal implements Filter {
    static {
	  loadLibrary('effectKit_ani')
    }

    private nativeObj: long = 0;

    constructor(context:long) {
      this.nativeObj = context;
    }

    public native blurNative(radius: double): Filter;

    public native grayscaleNative(): Filter;

    public native getEffectPixelMapNative(useCpuRender: boolean): image.PixelMap;

    public native blurNative(radius: double, tileMode: TileMode): Filter;

    public native brightnessNative(bright: double): Filter;

    public native invertNative(): Filter;

    public native setColorMatrixNative(colorMatrix: Array<double>): Filter;

    public native getPixelMapNative(): image.PixelMap;

    private static native kitTransferStaticNative(input: ESValue): Object;

	private static native kitTransferDynamicNative(nativeObj: long): ESValue;

    public blur(radius: double): Filter {
      return this.blurNative(radius);
    }

    public grayscale(): Filter {
      return this.grayscaleNative();
    }

    public getEffectPixelMap(): Promise<image.PixelMap> {
      return new Promise<image.PixelMap>((resolve: (value: image.PixelMap) => void,
        reject: (error: BusinessError) => void) => {
        taskpool.execute((): image.PixelMap => {
          let pixelMap = this.getEffectPixelMapNative(false);
          return pixelMap;
        }).then((ret: Any) => {
          resolve(ret as image.PixelMap);
        }).catch((err: Any) => {
          reject(err as BusinessError);
        });
      });
    }

    public getEffectPixelMap(useCpuRender: boolean): Promise<image.PixelMap> {
      return new Promise<image.PixelMap>((resolve: (value: image.PixelMap) => void,
        reject: (error: BusinessError) => void) => {
        taskpool.execute((): image.PixelMap => {
          let pixelMap = this.getEffectPixelMapNative(useCpuRender);
          return pixelMap;
        }).then((ret: Any) => {
          resolve(ret as image.PixelMap);
        }).catch((err: Any) => {
          reject(err as BusinessError);
        });
      });
    }

    public blur(radius: double, tileMode: TileMode): Filter {
      return this.blurNative(radius, tileMode);
    }
    public brightness(bright: double): Filter {
      return this.brightnessNative(bright);
    }
    public invert(): Filter {
      return this.invertNative();
    }
    public setColorMatrix(colorMatrix: Array<double>): Filter {
      return this.setColorMatrixNative(colorMatrix);
    }
    public getPixelMap(): image.PixelMap {
      return this.getPixelMapNative();
    }
    public static kitTransferStatic(input: Any): Object {
	  return FilterInternal.kitTransferStaticNative(ESValue.wrap(input));
	}   
	public static kitTransferDynamic(input: Object): Any {
	  return FilterInternal.kitTransferDynamicNative((input as FilterInternal).nativeObj).unwrap();
	}
  }

  export native function createEffect(source: image.PixelMap): Filter;


  export interface ColorPicker {
    getMainColor(): Promise<Color>;
    getMainColorSync(): Color;
    getLargestProportionColor(): Color;
    getTopProportionColors(colorCount: int): Array<Color | null>;
    getHighestSaturationColor(): Color;
    getAverageColor(): Color;
    isBlackOrWhiteOrGrayColor(color: long): boolean;
    getMorandiShadowColor(): Color;
    getDeepenImmersionColor(): Color;
    getImmersiveBackgroundColor(): Color;
    getImmersiveForegroundColor(): Color;
    discriminatePictureLightDegree(): PictureLightDegree;
    getReverseColor(): Color;
  }

  export enum PictureLightDegree {
    UNKOWN_LIGHT_COLOR_DEGREE_PICTURE = 0,
    EXTREMELY_LIGHT_COLOR_PICTURE = 1,
    LIGHT_COLOR_PICTURE = 2,
    DARK_COLOR_PICTURE = 3,
    EXTREMELY_DARK_COLOR_PICTURE = 4,
    FLOWERY_PICTURE = 5,
    EXTREMELY_FLOWERY_PICTURE = 6,
  }

  export class ColorPickerInternal implements ColorPicker {
    static {
	  loadLibrary('effectKit_ani')
	}

    private nativeObj: long = 0;

    constructor(context:long) {
      this.nativeObj = context;
    }

    public native getMainColorSyncNative(): Color;
    public native getLargestProportionColorNative(): Color;
    public native getTopProportionColorsNative(colorCount: int): Array<Color | null>;
    public native getHighestSaturationColorNative(): Color;
    public native getAverageColorNative(): Color;
    public native isBlackOrWhiteOrGrayColorNative(color: long): boolean;
    public native getMorandiShadowColorNative(): Color;
    public native getDeepenImmersionColorNative(): Color;
    public native getImmersiveBackgroundColorNative(): Color;
    public native getImmersiveForegroundColorNative(): Color;
    public native discriminatePictureLightDegreeNative(): PictureLightDegree;
    public native getReverseColorNative(): Color;
    private static native kitTransferStaticNative(input: ESValue): Object;
	private static native kitTransferDynamicNative(nativeObj: long): ESValue;

    public getMainColor(): Promise<Color> {
      return new Promise<Color>((resolve: (value: Color) => void,
        reject: (error: BusinessError) => void) => {
        taskpool.execute((): Color => {
          let color = this.getMainColorSync();
          return color;
        }).then((ret: Any) => {
          resolve(ret as Color);
        }).catch((err: Any) => {
          reject(err as BusinessError);
        });
      });
    }
    public getMainColorSync(): Color {
      return this.getMainColorSyncNative();
    }
    public getLargestProportionColor(): Color {
      return this.getLargestProportionColorNative();
    }
    public getTopProportionColors(colorCount: int): Array<Color | null> {
      return this.getTopProportionColorsNative(colorCount);
    }
    public getHighestSaturationColor(): Color {
      return this.getHighestSaturationColorNative();
    }
    public getAverageColor(): Color {
      return this.getAverageColorNative();
    }
    public isBlackOrWhiteOrGrayColor(color: long): boolean {
      return this.isBlackOrWhiteOrGrayColorNative(color);
    }
    public getMorandiShadowColor(): Color {
      return this.getMorandiShadowColorNative();
    }
    public getDeepenImmersionColor(): Color {
      return this.getDeepenImmersionColorNative();
    }
    public getImmersiveBackgroundColor(): Color {
      return this.getImmersiveBackgroundColorNative();
    }
    public getImmersiveForegroundColor(): Color {
      return this.getImmersiveForegroundColorNative();
    }
    public discriminatePictureLightDegree(): PictureLightDegree {
      return this.discriminatePictureLightDegreeNative();
    }
    public getReverseColor(): Color {
      return this.getReverseColorNative();
    }
    public static kitTransferStatic(input: Any): Object {
	  return ColorPickerInternal.kitTransferStaticNative(ESValue.wrap(input));
	}
	public static kitTransferDynamic(input: Object): Any {
	  return ColorPickerInternal.kitTransferDynamicNative((input as ColorPickerInternal).nativeObj).unwrap();
	}
  }

  native function createColorPickerNormal(source: image.PixelMap): ColorPicker
  native function createColorPickerWithRegion(source: image.PixelMap, region: Array<double>): ColorPicker

  export function createColorPicker(source: image.PixelMap): Promise<ColorPicker> {
    return new Promise<ColorPicker>((resolve : (v: ColorPicker) => void, reject: RejectString) => {
      let cb = (): ColorPicker => {
        return createColorPickerNormal(source)
      };
      taskpool.execute(cb).then((ret: Any): void => {
        if (ret === null || ret === undefined) {
          let ret1: BusinessError<string> = {
            code: -1,
            data: "Operation failed",
            name: "",
            message: ""
          };
          reject(ret1);
        } else {
          let colorpicker = ret as ColorPicker;
          resolve(colorpicker);
        }
      }).catch((err: Any) => {
        reject(err as BusinessError<string>);   
      });
    });
  }

  export function createColorPicker(source: image.PixelMap, region: Array<double>): Promise<ColorPicker> {
    return new Promise<ColorPicker>((resolve : (v: ColorPicker) => void, reject: RejectString) => {
      let cb = (): ColorPicker => { return createColorPickerWithRegion(source, region) };
      taskpool.execute(cb).then((ret: Any): void => {
        if (ret === null || ret === undefined) {
          let ret1: BusinessError<string> = {
            code: -1,
            data: "Operation failed",
            name: "",
            message: ""
          };
          reject(ret1);
        } else {
          let colorpicker = ret as ColorPicker;
          resolve(colorpicker);
        }
      }).catch((err: Any) => {
        reject(err as BusinessError<string>);
      });
    });
  }

  export function createColorPicker(source: image.PixelMap, callback: AsyncCallback<ColorPicker | undefined>): void {
    try {
      const result = createColorPickerNormal(source);
      if (result) {
        callback(null, result);
      } else {
        const error: BusinessError = {
          code: -1,
          name: "EffectKitNativeError",
          message: "Failed to create ColorPicker. Native method returned null or undefined."
        };
        callback(error, undefined);
      }
    } catch (e) {
      const error: BusinessError = {
        code: (e as BusinessError).code || -1,
        name: (e as BusinessError).name || "EffectKitNativeError",
        message: (e as BusinessError).message || "An unexpected native error occurred."
      };
      callback(error, undefined);
    }

  }

  export function createColorPicker(source: image.PixelMap, region: Array<double>, callback: AsyncCallback<ColorPicker | undefined>): void {
    try {
      const result = createColorPickerWithRegion(source, region);
      if (result) {
        callback(null, result);
      } else {
        const error: BusinessError = {
          code: -1,
          name: "EffectKitNativeError",
          message: "Failed to create ColorPicker with region. Native method returned null or undefined."
        };
        callback(error, undefined);
      }
    } catch (e) {
      const error: BusinessError = {
        code: (e as BusinessError).code || -1,
        name: (e as BusinessError).name || "EffectKitNativeError",
        message: (e as BusinessError).message || "An unexpected native error occurred."
      };
      callback(error, undefined);
    }
  }
}

export default effectKit;