import { image } from '@kit.ImageKit';
import Matrix4 from '@ohos.matrix4'
import fs from '@ohos.file.fs';
import router from '@ohos.router';
import display from '@ohos.display';
import { Constants } from '../utils/Constants';
import { getPixelMap } from '../utils/DecodeAndEncodeUtil';
import { RotateType } from '../viewmodel/viewAndModel';
import { encodeToPng } from '../utils/EncodeUtil';
import Logger from '../Logger';
import { CircleImageProcessor } from '../utils/CircleImageProcessor';

const TAG: string = 'CircleImageEditInfo';

@Extend(Row)
function bottomIconStyle() {
  .size({ width: '20%', height: '100%' })
  .justifyContent(FlexAlign.Center)
}

@Extend(Text)
function textStyle() {
  .size({ width: '20%', height: '100%' })
  .textAlign(TextAlign.Center)
}

@Extend(Image)
function iconStyle() {
  .size({ width: 24, height: 24 })
  .fillColor('#FFFFFF')
  .opacity(0.9)
}

@Component
export struct CropView {
  @StorageProp('filePath') filePath: string = '';
  @StorageProp('cropperRotate') cropperRotate: string = '';
  @StorageProp('initWidth') initWidth: number = 0;
  @StorageProp('initHeight') initHeight: number = 0;
  @StorageProp('textTitle') title: string = '';
  @StorageProp('cancelText') cancel: string = '';
  @StorageProp('cancelTextColor') cancelTextColor: string = '';
  @StorageProp('chooseText') choose: string = '';
  @StorageProp('chooseTextColor') chooseTextColor: string = '';
  @StorageProp('freeStyleCropEnabled') freeStyleCropEnabled: boolean = false;
  @StorageProp('cropperCircleOverlay') cropperCircleOverlay: boolean = false;
  @StorageProp('enableRotationGesture') enableRotationGesture: boolean = false;
  @State private model: CropModel = new CropModel();
  private settings: RenderingContextSettings = new RenderingContextSettings(true);
  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings);
  @State pm: PixelMap | undefined = undefined;
  @State private matrix: object = Matrix4.identity()
    .translate({ x: 0, y: 0 })
    .scale({ x: this.model.scale, y: this.model.scale });
  @State screenWidth: number = 0;
  @State screenHeight: number = 0;
  @State imageWidth: number = 0;
  @State imageHeight: number = 0;
  @State angle: number = 0;
  @State gestureAngle: number = 0
  private tempScale = 1;
  private startOffsetX: number = 0;
  private startOffsetY: number = 0;
  private initialAngle: number = 0;
  private initialScale: number = 1;
  private initialOffsetX: number = 0;
  private initialOffsetY: number = 0;
  private initialImageWidth: number = 0;
  private initialImageHeight: number = 0;
  private isImageAnimation: boolean = true
  private isStackAnimation: boolean = true
  @StorageProp('bottomRectHeight')
  bottomRectHeight: number = 0;
  @StorageProp('topRectHeight')
  topRectHeight: number = 0;

  aboutToAppear(): void {
    this.screenHeight = this.getUIContext().px2vp(display.getDefaultDisplaySync().height);
    this.filePath = AppStorage.Get('filePath') || ''
    this.model.setImage(this.filePath)
    getPixelMap(this.filePath)
      .then((pixelMap: image.PixelMap) => {
        if (pixelMap) {
          this.model.src = pixelMap;
          pixelMap.getImageInfo().then((imageInfo) => {
            this.imageHeight = imageInfo.size == undefined ? 0 : imageInfo.size?.height;
            this.imageWidth = imageInfo.size == undefined ? 0 : imageInfo.size?.width;
            this.initialImageWidth = this.imageWidth;
            this.initialImageHeight = this.imageHeight;
          })
        }
      })
  }

  @Builder
  CropTitleBar() {
    Text(this.title)
      .fontColor(Color.White)
      .fontSize(20)
      .textAlign(TextAlign.Center)
      .width('100%')
      .height(46)
      .position({ x: 0, y: 20 })
      .backgroundColor(Color.Black)
  }

  @Builder
  BottomToolbar() {
    Row() {
      Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.Center }) {
        Text(this.cancel)
          .textStyle()
          .fontColor(this.cancelTextColor)
          .onClick(async () => {
            router.back()
          });
        Row() {
          Image($r('app.media.ic_anti_clockwise'))
            .iconStyle()
            .visibility(this.cropperRotate === 'true' ? Visibility.Hidden : Visibility.Visible)
            .onClick(async () => {
              this.rotateImage(RotateType.ANTI_CLOCK);
            });
        }
        .bottomIconStyle();

        Row() {
          Image($r('app.media.ic_reset'))
            .iconStyle()
            .onClick(() => {
              this.resetAllTransformations();
            });
        }
        .bottomIconStyle();

        Row() {
          Image($r('app.media.ic_clockwise'))
            .iconStyle()
            .visibility(this.cropperRotate === 'true' ? Visibility.Hidden : Visibility.Visible)
            .onClick(() => {
              this.rotateImage(RotateType.CLOCKWISE);
            });
        }
        .bottomIconStyle();

        Text(this.choose)
          .textStyle()
          .fontColor(this.chooseTextColor)
          .onClick(async () => {
            if (this.model.src) {
              try {
                // 进行普通的正方形裁剪
                const squarePm = await this.model.crop(image.PixelMapFormat.RGBA_8888);

                // 对裁剪后的图片应用旋转
                const normalizedAngle = ((this.angle % 360) + 360) % 360;
                if (normalizedAngle !== 0) {
                  await squarePm.rotate(normalizedAngle);
                }

                // 转换为真正的圆形图片
                const circlePm = await CircleImageProcessor.createTrueCircleImage(squarePm);

                // 保存为PNG格式（支持透明度）
                let imgPath = await encodeToPng(this, circlePm);

                // 清理资源
                squarePm.release();
                circlePm.release();

                // 保存路径
                AppStorage.setOrCreate('cropImagePath', imgPath);
                AppStorage.setOrCreate('isCircleImage', true);
                router.back()
              } catch (error) {
                Logger.error(TAG, "Circle crop failed:" + JSON.stringify(error));
              }
            }
          })
      }
      .width('100%')
      .height(56)
      .backgroundColor(Color.Black)
      .margin({ bottom: 30 })
    }
    .width('100%')
    .height(56)
    .position({ x: 0, y: (this.screenHeight - 66) })
    .backgroundColor(Color.Black)
  }

  build() {
    Stack() {
      Stack() {
        Image(this.model.src)
          .width('100%')
          .height('100%')
          .alt(this.model.previewSource)
          .objectFit(ImageFit.Contain)
          .transform(this.matrix)
          .animation({ duration: this.isImageAnimation ? 300 : 0 })
          .onComplete((msg) => {
            if (msg) {
              // 图片加载成功
              this.model.imageWidth = msg.width;
              this.model.imageHeight = msg.height;
              this.model.componentWidth = msg.componentWidth;
              this.model.componentHeight = msg.componentHeight;
              this.saveInitialState();
              this.checkImageAdapt();
              if (this.model.imageLoadEventListener != null && msg.loadingStatus == 1) {
                this.model.imageLoadEventListener.onImageLoaded(msg);
              }
            }
          })
          .onError((error) => {
            if (this.model.imageLoadEventListener != null) {
              this.model.imageLoadEventListener.onImageLoadError(error);
            }
          })
      }
      .rotate({ angle: this.angle })
      .width('100%')
      .height('100%')
      .animation({ duration: this.isStackAnimation ? 300 : 0 })
      .priorityGesture(
        TapGesture({ count: 2, fingers: 1 })
          .onAction((event: GestureEvent) => {
            if (!event) {
              return
            }
            if (this.model.zoomEnabled) {
              if (this.model.scale != 1) {
                this.model.scale = 1;
                this.updateMatrix();
              } else {
                this.zoomTo(2);
              }
            }

            this.checkImageAdapt();
          })
      )
      .gesture(
        GestureGroup(GestureMode.Parallel,
          // 拖动手势
          PanGesture({})
            .onActionStart(() => {
              Logger.info(TAG, "CropView Pan gesture start");
              this.startOffsetX = this.model.offsetX;
              this.startOffsetY = this.model.offsetY;
              this.isImageAnimation = false
            })
            .onActionUpdate((event: GestureEvent) => {
              Logger.info(TAG, "CropView Pan gesture update" + JSON.stringify(event));
              if (event) {
                if (this.model.panEnabled) {
                  let distanceX: number = this.startOffsetX + vp2px(event.offsetX) / this.model.scale;
                  let distanceY: number = this.startOffsetY + vp2px(event.offsetY) / this.model.scale;
                  this.model.offsetX = distanceX;
                  this.model.offsetY = distanceY;
                  this.updateMatrix()
                }
              }
            })
            .onActionEnd(() => {
              Logger.info(TAG, "CropView Pan gesture end");
              this.checkImageAdapt();
              this.isImageAnimation = true
            }),
          // 缩放手势
          PinchGesture({ fingers: 2 })
            .onActionStart(() => {
              this.isStackAnimation = false
              this.tempScale = this.model.scale
            })
            .onActionUpdate((event) => {
              if (event) {
                if (!this.model.zoomEnabled) {
                  return;
                }
                this.zoomTo(Math.min(5.0, Math.max(0.1, (this.tempScale * event.scale))))
              }
            })
            .onActionEnd((event) => {
              this.checkImageAdapt()
              this.updateMatrix()
              this.isStackAnimation = true
            }),
          //旋转手势
          RotationGesture({})
            .onActionStart(() => {
              if (this.enableRotationGesture) {
                // 记录手势起始
                this.gestureAngle = this.angle
                // 关闭动画避免旋转错误
                this.isStackAnimation = false
              }
            })
            .onActionUpdate((event: GestureEvent) => {
              if (this.enableRotationGesture) {
                let normalizedAngle = event.angle
                if (normalizedAngle < 0) {
                  normalizedAngle += 360
                }
                this.angle = this.gestureAngle + normalizedAngle
              }
            })
            .onActionEnd(() => {
              if (this.enableRotationGesture) {
                this.isStackAnimation = false
                const tmp = this.angle % 360
                this.angle = tmp
                let time = setTimeout(() => {
                  this.isStackAnimation = true
                  this.angle = closestAngle
                  this.updateMatrix()
                  this.checkImageAdapt()
                  clearTimeout(time)
                }, 50)

                // 计算最近的吸附角度
                const snapAngles = [0, 90, 180, 270, 360]
                let closestAngle = snapAngles[0]
                let minDiff = Infinity

                for (const snapAngle of snapAngles) {
                  const diff = Math.abs(tmp - snapAngle)
                  if (diff < minDiff) {
                    minDiff = diff
                    closestAngle = snapAngle
                  }
                }
              }
            })
        )
      )

      Canvas(this.context)
        .width('100%')
        .height('100%')
        .backgroundColor(Color.Transparent)
        .onReady(() => {
          if (this.context == null) {
            return
          }
          let height = this.context.height
          let width = this.context.width
          this.context.fillStyle = this.model.maskColor;
          this.context.fillRect(0, 0, width, height)
          let centerX = width / 2;
          let centerY = height / 2;
          this.context.globalCompositeOperation = 'destination-out'
          this.context.fillStyle = 'white'
          let frameWidthInVp = px2vp(this.model.frameWidth);
          let frameHeightInVp = px2vp(this.model.getFrameHeight());
          this.context.beginPath();
          this.context.arc(centerX, centerY, px2vp(this.model.frameWidth / 2), 0, 2 * Math.PI);
          this.context.fill();
          this.context.globalCompositeOperation = 'source-over';
          this.context.strokeStyle = this.model.strokeColor;
          let radius = Math.min(frameWidthInVp, frameHeightInVp) / 2;
          this.context.beginPath();
          this.context.arc(centerX, centerY, radius, 0, 2 * Math.PI);
          this.context.closePath();
          this.context.lineWidth = 1;
          this.context.stroke();
        })
        .enabled(false)

      this.CropTitleBar()

      this.BottomToolbar()
    }
    .backgroundColor(Color.Black)
  }

  /**
   * 检查手势操作后，图片是否填满取景框，没填满则进行调整
   */
  private checkImageAdapt() {
    let offsetX = this.model.offsetX;
    let offsetY = this.model.offsetY;
    let scale = this.model.scale;
    Logger.info(TAG, "CropView offsetX: " + offsetX + ", offsetY: " + offsetY + ", scale: " + scale);

    // 图片适配控件的时候也进行了缩放，计算出这个缩放比例
    let widthScale = this.model.componentWidth / this.model.imageWidth;
    let heightScale = this.model.componentHeight / this.model.imageHeight;
    let adaptScale = Math.min(widthScale, heightScale);
    Logger.info(TAG,
      "CropView Image scale: " + adaptScale + "while attaching the component[" + this.model.componentWidth + ", " +
      this.model.componentHeight);

    // 经过两次缩放(适配控件、手势)后，图片的实际显示大小
    let showWidth = this.model.imageWidth * adaptScale * this.model.scale;
    let showHeight = this.model.imageHeight * adaptScale * this.model.scale;
    let imageX = (this.model.componentWidth - showWidth) / 2;
    let imageY = (this.model.componentHeight - showHeight) / 2;
    Logger.info(TAG, "CropView Image left top is: (" + imageX + ", " + imageY + ")");

    // 取景框的左上角坐标
    let frameX = (this.model.componentWidth - this.model.frameWidth) / 2;
    let frameY = (this.model.componentHeight - this.model.getFrameHeight()) / 2;

    // 图片左上角坐标
    let showX = imageX + offsetX * scale;
    let showY = imageY + offsetY * scale;
    Logger.info(TAG, "CropView Image show at (" + showX + ", " + showY + ")");

    if (this.model.frameWidth > showWidth || this.model.getFrameHeight() > showHeight) { // 图片缩放后，大小不足以填满取景框
      let xScale = this.model.frameWidth / showWidth;
      let yScale = this.model.getFrameHeight() / showHeight;
      let newScale = Math.max(xScale, yScale);
      this.model.scale = this.model.scale * newScale;
      showX *= newScale;
      showY *= newScale;
    }

    // 调整x轴方向位置，使图像填满取景框
    if (showX > frameX) {
      showX = frameX;
    } else if (showX + showWidth < frameX + this.model.frameWidth) {
      showX = frameX + this.model.frameWidth - showWidth;
    }
    // 调整y轴方向位置，使图像填满取景框
    if (showY > frameY) {
      showY = frameY;
    } else if (showY + showHeight < frameY + this.model.getFrameHeight()) {
      showY = frameY + this.model.getFrameHeight() - showHeight;
    }
    this.model.offsetX = (showX - imageX) / scale;
    this.model.offsetY = (showY - imageY) / scale;
    this.updateMatrix();
  }

  public zoomTo(scale: number): void {
    this.model.scale = scale;
    this.updateMatrix();
  }

  public updateMatrix(): void {
    this.matrix = Matrix4.identity()
      .translate({ x: this.model.offsetX, y: this.model.offsetY })
      .scale({ x: this.model.scale, y: this.model.scale })
  }

  public rotateImage(rotateType: RotateType) {
    Logger.info(TAG, "into rotateImage rotateType : " + rotateType)
    if (rotateType === RotateType.CLOCKWISE) {
      if (!this.model.src) {
        Logger.info(TAG, "into rotateImage return")
        return;
      }
      try {
        this.model.src.rotate(Constants.CLOCK_WISE)
          .then(() => {
            this.angle = this.angle + Constants.CLOCK_WISE;
            Logger.info(TAG, `into rotateImage  Constants.CLOCK_WISE return ${this.angle}`,)
          })
      } catch (error) {
      }
    }
    if (rotateType === RotateType.ANTI_CLOCK) {
      if (!this.model.src) {
        Logger.info(TAG, "into rotateImage return")
        return;
      }
      try {
        this.model.src.rotate(Constants.ANTI_CLOCK)
          .then(() => {
            this.angle = this.angle + Constants.ANTI_CLOCK;
            Logger.info(TAG, `into rotateImage Constants.ANTI_CLOCK return ${this.angle}`,)
          })
      } catch (error) {
      }
    }
  }

  // 保存初始状态方法
  private saveInitialState(): void {
    this.initialAngle = this.angle;
    this.initialScale = this.model.scale;
    this.initialOffsetX = this.model.offsetX;
    this.initialOffsetY = this.model.offsetY;
    Logger.info(TAG, "Initial state saved: " +
      `angle=${this.initialAngle}, scale=${this.initialScale}, offsetX=${this.initialOffsetX}, offsetY=${this.initialOffsetY}`);
  }

  // 重置所有变换的方法
  private resetAllTransformations(): void {
    Logger.info(TAG, "Resetting all transformations...");

    // 重置位置和缩放
    this.model.scale = this.initialScale;
    this.model.offsetX = this.initialOffsetX;
    this.model.offsetY = this.initialOffsetY;

    // 重置旋转角度
    if (this.angle !== this.initialAngle) {
      let angleDifference = this.initialAngle - this.angle;

      // 如果有PixelMap且需要旋转
      if (this.model.src && angleDifference !== 0) {
        angleDifference = angleDifference % 360
        // 异步旋转图片
        this.model.src.rotate(angleDifference)
          .then(() => {
            this.angle = this.initialAngle;
            Logger.info(TAG, `Image rotated back by ${angleDifference} degrees`);
            this.updateMatrix();
            this.checkImageAdapt();
          })
          .catch((error: Error) => {
            Logger.error(TAG, "Failed to reset rotation: " + JSON.stringify(error));
            // 即使旋转失败，也更新UI状态
            this.angle = this.initialAngle;
            this.updateMatrix();
            this.checkImageAdapt();
          });
      } else {
        // 无需旋转或没有PixelMap，直接更新
        this.angle = this.initialAngle;
        this.updateMatrix();
        this.checkImageAdapt();
      }
    } else {
      // 角度相同，直接更新
      this.updateMatrix();
      this.checkImageAdapt();
    }

    // 重置图片宽高到初始值
    if (this.imageWidth !== this.initialImageWidth || this.imageHeight !== this.initialImageHeight) {
      this.imageWidth = this.initialImageWidth;
      this.imageHeight = this.initialImageHeight;
    }

    Logger.info(TAG, "All transformations have been reset: " +
      `angle=${this.angle}, scale=${this.model.scale}, offsetX=${this.model.offsetX}, offsetY=${this.model.offsetY}`);
  }
}

interface ImageLoadedEvent {
  width: number;
  height: number;
  componentWidth: number;
  componentHeight: number;
  loadingStatus: number;
  contentWidth: number;
  contentHeight: number;
  contentOffsetX: number;
  contentOffsetY: number;
}

export interface ImageLoadEventListener {

  onImageLoaded(msg: ImageLoadedEvent): void;

  onImageLoadError(error: ImageError): void;
}

export class CropModel {
  /**
   * PixelMap图片对象
   *
   */
  src?: image.PixelMap = undefined;
  /**
   * 图片地址
   */
  path: string = '';
  /**
   * 图片预览
   */
  previewSource: string | Resource = '';
  /**
   * 是否可以拖动
   */
  panEnabled: boolean = true;
  /**
   * 是否可以缩放
   */
  zoomEnabled: boolean = true;
  /**
   * 取景框宽度
   */
  frameWidth = 1000;
  /**
   * 取景框宽高比
   */
  frameRatio = 1;
  /**
   * 遮罩颜色
   */
  maskColor: string = '#AA000000';
  /**
   * 取景框边框颜色
   */
  strokeColor: string = '#FFFFFF';
  /**
   * 图片加载监听
   */
  imageLoadEventListener: ImageLoadEventListener | null = null;
  /**
   * 图片宽度
   */
  imageWidth: number = 0;
  /**
   * 图片高度
   */
  imageHeight: number = 0;
  /**
   * 控件宽度
   */
  componentWidth: number = 0;
  /**
   * 控件高度
   */
  componentHeight: number = 0;
  /**
   * 手势缩放比例
   */
  scale: number = 1;
  /**
   * x轴方向偏移量
   */
  offsetX: number = 0;
  /**
   * y轴方向偏移量
   */
  offsetY: number = 0;

  public setImage(path: string, previewSource?: string | Resource): CropModel {
    this.path = path;
    if (!!previewSource) {
      this.previewSource = previewSource;
    }
    return this;
  }

  public setScale(scale: number): CropModel {
    this.scale = scale;
    return this;
  }

  public isPanEnabled(): boolean {
    return this.panEnabled;
  }

  public setPanEnabled(panEnabled: boolean): CropModel {
    this.panEnabled = panEnabled;
    return this;
  }

  public setZoomEnabled(zoomEnabled: boolean): CropModel {
    this.zoomEnabled = zoomEnabled;
    return this;
  }

  public setFrameWidth(frameWidth: number): CropModel {
    this.frameWidth = frameWidth;
    return this;
  }

  public setFrameRatio(frameRatio: number): CropModel {
    this.frameRatio = frameRatio;
    return this;
  }

  public setMaskColor(color: string): CropModel {
    this.maskColor = color;
    return this;
  }

  public setStrokeColor(color: string): CropModel {
    this.strokeColor = color;
    return this;
  }

  public setImageLoadEventListener(listener: ImageLoadEventListener): CropModel {
    this.imageLoadEventListener = listener;
    return this;
  }

  public getScale(): number {
    return this.scale;
  }

  public isZoomEnabled(): boolean {
    return this.zoomEnabled;
  }

  public getImageWidth(): number {
    return this.imageWidth;
  }

  public getImageHeight(): number {
    return this.imageHeight;
  }

  public getFrameHeight() {
    return this.frameWidth / this.frameRatio;
  }

  public reset(): void {
    this.scale = 1;
    this.offsetX = 0;
    this.offsetY = 0;
  }

  public async crop(format: image.PixelMapFormat): Promise<image.PixelMap> {

    if (!this.path || this.path == '') {
      throw new Error('Please set path first');
    }
    if (this.imageWidth == 0 || this.imageHeight == 0) {
      throw new Error('The image is not loaded');
    }

    // 图片适配控件的时候也进行了缩放，计算出这个缩放比例
    let widthScale = this.componentWidth / this.imageWidth;
    let heightScale = this.componentHeight / this.imageHeight;
    let adaptScale = Math.min(widthScale, heightScale);

    // 经过两次缩放(适配控件、手势)后，图片的实际显示大小
    let totalScale = adaptScale * this.scale;
    let showWidth = this.imageWidth * totalScale;
    let showHeight = this.imageHeight * totalScale;
    let imageX = (this.componentWidth - showWidth) / 2;
    let imageY = (this.componentHeight - showHeight) / 2;

    // 取景框的左上角坐标
    let frameX = (this.componentWidth - this.frameWidth) / 2;
    let frameY = (this.componentHeight - this.getFrameHeight()) / 2;

    // 图片左上角坐标
    let showX = imageX + this.offsetX * this.scale;
    let showY = imageY + this.offsetY * this.scale;

    let x = (frameX - showX) / totalScale;
    let y = (frameY - showY) / totalScale;
    let file = fs.openSync(this.path, fs.OpenMode.READ_ONLY)
    let imageSource: image.ImageSource = image.createImageSource(file.fd);
    let decodingOptions: image.DecodingOptions = {
      editable: true,
      desiredPixelFormat: image.PixelMapFormat.BGRA_8888,
    }

    // 创建pixelMap
    let pm = await imageSource.createPixelMap(decodingOptions);
    let cp = await this.copyPixelMap(pm);
    pm.release();
    let region: image.Region =
      { x: x, y: y, size: { width: this.frameWidth / totalScale, height: this.getFrameHeight() / totalScale } };
    cp.cropSync(region);
    return cp;
  }

  async copyPixelMap(pm: PixelMap): Promise<PixelMap> {
    const imageInfo: image.ImageInfo = await pm.getImageInfo();
    const buffer: ArrayBuffer = new ArrayBuffer(pm.getPixelBytesNumber());
    await pm.readPixelsToBuffer(buffer);
    const opts: image.InitializationOptions = {
      editable: true,
      pixelFormat: image.PixelMapFormat.RGBA_8888,
      size: { height: imageInfo.size.height, width: imageInfo.size.width }
    };
    return image.createPixelMap(buffer, opts);
  }
}

@Entry
@Component
export struct CircleImageInfo {
  @State private model: CropModel = new CropModel();

  build() {
    Column() {
      CropView({
        model: this.model,
      })
        .layoutWeight(1)
        .width('100%')
    }
    .height('100%')
    .width('100%')
  }
}