// Copyright (c) 2024 Huawei Device Co., Ltd. All rights reserved
// Use of this source code is governed by a Apache-2.0 license that can be
// found in the LICENSE file.

import { RNOHContext, RNViewBase } from '@rnoh/react-native-openharmony';
import { colorFiltersItem, LOTTLE_STRING } from './common/AnimationType';
import { AnimationObject, layersItem } from './common/Animation';
import { RNOHLogger } from "@rnoh/react-native-openharmony/ts";
import { RNC } from './generated';
import { JSON } from '@kit.ArkTS';
import { LottieView, LottieController, lottie, LottieListener } from '@ohos/lottie-turbo'
import { convertImageFolder } from './LottieTurboAnimationTools';

export const LOTTIE_TURBO_TYPE: string = RNC.LottieTurboAnimationView.NAME

@Component
export struct LottieTurboAnimationView {
  public static readonly NAME = RNC.LottieTurboAnimationView.NAME
  ctx!: RNOHContext;
  tag: number = 0;
  private logger!: RNOHLogger;
  @State descriptorWrapper: RNC.LottieTurboAnimationView.DescriptorWrapper = {} as RNC.LottieTurboAnimationView.DescriptorWrapper;
  private unregisterDescriptorChangesListener?: () => void = undefined;
  private cleanupCommandCallback?: () => void = undefined;
  private path: string | undefined = undefined;
  private lottieController: LottieController | null = new LottieController();
  private cacheComposition: boolean = true;
  @State @Watch('onStateChanged') progress: number = 0;
  @State @Watch('onStateChanged') speed: number = 1;
  @State @Watch('onStateChanged') imagePath: string | undefined = undefined;
  private autoPlay: boolean = true;
  private loop: boolean = true;
  private animationData: string | undefined = undefined;
  private eventEmitter: RNC.LottieTurboAnimationView.EventEmitter | undefined = undefined;
  private listener: LottieListener | null = null;
  private contentMode: string | undefined = undefined;
  private lottieID: string | null = null;
  private isOnComplete: boolean = false;

  aboutToAppear() {
    // 创建EventEmitter实例，用于处理事件的订阅和触发
    this.eventEmitter = new RNC.LottieTurboAnimationView.EventEmitter(this.ctx.rnInstance, this.tag)
    this.logger = this.ctx!.logger.clone(RNC.LottieTurboAnimationView.NAME)
    this.onDescriptorWrapperChange(this.ctx.descriptorRegistry.findDescriptorWrapperByTag<RNC.LottieTurboAnimationView.DescriptorWrapper>(this.tag)!)
    this.initData()
    this.subscribeToDescriptorChanges();
    this.commandCallback();
    this.logger.info(`testlottie:${JSON.stringify(this.descriptorWrapper.props.sourceJson)}`)
  }

  private onDescriptorWrapperChange(descriptorWrapper: RNC.LottieTurboAnimationView.DescriptorWrapper) {
    this.descriptorWrapper = descriptorWrapper
  }

  subscribeToDescriptorChanges(): void {
    this.unregisterDescriptorChangesListener = this.ctx.descriptorRegistry.subscribeToDescriptorChanges(this.tag,
      (newDescriptor: object) => {
        this.descriptorWrapper = (newDescriptor as RNC.LottieTurboAnimationView.DescriptorWrapper);
        this.updateData()
      }
    )
  }

  /**
   * 初始化数据
   * handleColorFilters colorFilters 图层替换还未实现
   */
  private initData() {
    if (!this.descriptorWrapper.props) {
      return
    }
    this.lottieID = `${this.tag}${new Date().getTime()}`;
    this.addEventListener();
    this.updateData();
  }

  /**
   * 状态切换
   * @param propName
   */
  onStateChanged(propName: string): void {
    if (this.lottieController) {
      this.onSwitchLottie(propName);
      return;
    }
  }

  onSwitchLottie(propName: string): void {
    if (this.lottieController == null) {
      return;
    }
    switch (propName) {
      case LOTTLE_STRING.progress:
        this.setProgress();
        break;
      case LOTTLE_STRING.speed:
        this.setSpeed()
        break;
      default:
        break;
    }
  }

  /**
   * 设置速度
   */
  setSpeed(): void {
    this.lottieController?.setSpeed(this.descriptorWrapper.props.speed)
  }

  /**
   * 帧率播放
   */
  setProgress(): void {
    const frame = this.getAnimateFrame();
    console.log('frame = ' + frame);
    this.lottieController?.goToAndStop(frame, true);
  }

  getAnimateFrame(): number {
    const totalFrames: number = this.lottieController?.totalFrames ?? 0;
    return Math.ceil(this.descriptorWrapper.props.progress * totalFrames);
  }

  /**
   * 改变动画颜色
   */
  handleColorFilters(): void {
    if (!this.animationData) {
      return
    }
    const data = JSON.parse(this.animationData) as AnimationObject
    const layersData: Array<layersItem> = data?.layers ?? [];
    const colorFiltersData: Array<colorFiltersItem> =
      (this.descriptorWrapper.props.colorFilters ?? []) as Array<colorFiltersItem>;
    for (const item of colorFiltersData) {
      const index: number = layersData.findIndex((layersItem: layersItem) => layersItem?.nm === item?.keypath);
      const color: Array<number> = this.getColorByColorFilters(item);
      const isIndex: boolean = index !== (-1);
      const isColor: boolean = color.length === 3;
      if (isIndex && isColor) {
        this.lottieController?.changeColor(`**.${item?.keypath}.**`, color);
        this.logger.debug(`colorFilters success: ${item?.keypath}, ${color}`);
      } else {
        this.logger.error('colorFilters fail:not find keyPath', item?.keypath);
      }
    }
  }

  /**
   * 转换颜色RGB
   * @param colorFiltersItem
   * @returns
   */
  getColorByColorFilters(colorFiltersItem: colorFiltersItem): Array<number> {
    const color: string = colorFiltersItem?.color;
    if (color) {
      const processColor: number = Number(color);
      const r: number = (processColor >> 16) & 0xff;
      const g: number = (processColor >> 8) & 0xff;
      const b: number = processColor & 0xff;
      this.logger.debug(`getColorByColorFilters, r=${r}, g=${g}, b=${b}`);
      return [r, g, b];
    }
    this.logger.error('colorFilters fail:not find color', colorFiltersItem?.keypath);
    return [];
  }

  /**
   * 更新数据
   * imageAssetsFolder ?
   */
  updateData(): void {
    if(this.descriptorWrapper.props.imageAssetsFolder){
      if(this.descriptorWrapper.props.sourceJson){
        const jsonData = JSON.stringify(convertImageFolder(JSON.parse(this.descriptorWrapper.props.sourceJson) as AnimationObject,
          this.descriptorWrapper.props.imageAssetsFolder as string));
        this.logger.info(`updateData jsonData:${JSON.stringify(jsonData)}`)
        this.imagePath = this.getUIContext().getHostContext()?.resourceDir + "/"
        this.animationData = jsonData
      }
    } else {
      this.animationData = this.descriptorWrapper.props.sourceJson
    }
    this.path = this.descriptorWrapper.props.sourceURL
    this.contentMode = this.descriptorWrapper.props?.resizeMode?.replace(this.descriptorWrapper.props.resizeMode[0],
      this.descriptorWrapper.props.resizeMode[0].toUpperCase());
    this.loop = Boolean(this.descriptorWrapper.props.loop);
    this.autoPlay = Boolean(this.descriptorWrapper.props.autoPlay);
    this.cacheComposition = Boolean(this.descriptorWrapper.props.cacheComposition);
    this.reloadLottie();
    this.handleColorFilters();
    this.progress = this.descriptorWrapper.props.progress;
    this.speed = this.descriptorWrapper.props.speed;
  }

  /**
   * 添加监听
   * onLoopComplete 动画循环播放一轮完成
   * onDataReady 资源加载完成
   * onComplete 动画播放完成
   * onDataFailed 数据加载失败，json文件异常
   */
  addEventListener() {
    this.listener = new LottieListener({
      onLoopComplete: () => {
        this.eventEmitter!.emit("animationLoop",{})
      },
      onDataReady: () => {
        if(Array.isArray(this.descriptorWrapper.props.colorFilters)){
          if(this.descriptorWrapper.props.colorFilters.length > 0)
          this.handleColorFilters();
        }
        if (this.descriptorWrapper.props.speed != 1){
          this.setSpeed()
        }
        this.eventEmitter!.emit("animationLoaded", {});
      },
      onComplete: () => {
        if(this.isOnComplete == true){
          this.isOnComplete = false
        } else {
          this.onAnimationEnd()
        }
      },
      onDataFailed: () => {
        this.eventEmitter!.emit("animationFailure", { error: 'data_failed' });
      }
    })
  }

  /**
   * 控制暂停 、播放
   */
  commandCallback(): void {
    this.cleanupCommandCallback = this.ctx.componentCommandReceiver.registerCommandCallback(
      this.tag,
      (command: string, args: object) => {
        if (this.lottieController == null) {
          return;
        }
        switch (command) {
          case LOTTLE_STRING.play:
            this.play(args as number[]);
            break;
          case LOTTLE_STRING.reset:
            this.reset();
            break;
          case LOTTLE_STRING.pause:
            this.pause();
            break;
          case LOTTLE_STRING.resume:
            this.resume();
            break;
          default:
            this.logger.warn('not find command');
            break;
        }
      })
  }

  /**
   * play 播放
   * pause 暂停
   * resume 暂停/播放切换
   * reset 从新播放
   */
  play(args: number[]): void {
    const startFrame = args[0];
    const endFrame = args[1];
    if(this.lottieController?.isPaused == false)
    {
      this.onAnimationCancel()
    }
    this.isOnComplete = true;
    this.lottieController?.stop();
    if (this.progress !== 0) {
      this.progress = 0;
      this.lottieController?.goToAndPlay(this.getAnimateFrame(), true);
      return;
    }
    if (args.length > 1 && startFrame != -1 && endFrame != -1) {
      if (startFrame > endFrame) {
        this.lottieController?.setSegment(endFrame, startFrame);
        if (this.descriptorWrapper.props.speed > 0) {
          this.lottieController?.setDirection(-1);
        }
      } else {
        this.lottieController?.setSegment(startFrame, endFrame);
        if (this.descriptorWrapper.props.speed < 0) {
          this.lottieController?.setDirection(-1);
        }
      }
    }
    this.lottieController?.play();
  }

  pause(): void {
    this.lottieController?.pause();
  }

  resume(): void {
    if (this.lottieController?.isPaused) {
      this.lottieController?.togglePause();
    }
  }

  reset(): void {
    if(this.lottieController?.isPaused == false)
      {
        this.onAnimationCancel()
      }
    this.isOnComplete = true;
    this.lottieController?.stop();
  }

  /**
   * 结束播放
   */
  onAnimationEnd(): void {
    this.onAnimationFinish(false);
  }

  onAnimationFinish(isCancelled: boolean): void {
    this.eventEmitter!.emit("animationFinish", { isCancelled: isCancelled });
  }

  onAnimationCancel(): void {
    this.onAnimationFinish(true);
  }

  /**
   * 自动播放
   */
  setAutoPlay(): void {
    this.lottieController?.goToAndPlay(this.getAnimateFrame(), true);
  }

  /**
   * 重新加载动画
   */
  reloadLottie() {
    this.lottieController?.reload({
      path: this.path,
      animationData: this.animationData,
      loop: this.loop,
      autoplay: this.autoPlay,
      contentMode: this.contentMode,
    })
  }

  /**
   * 页面销毁处理
   * aboutToDisappear
   * destroyAnimation
   */
  aboutToDisappear() {
    this.cleanupCommandCallback?.();
    this.unregisterDescriptorChangesListener?.();
    this.destroyAnimation();
    if (this.lottieID) {
      lottie.destroy(this.lottieID);
    }
    this.lottieID = null;
    this.listener = null;
  }

  destroyAnimation(): void {
    if (this.lottieController == null) {
      return;
    }
    if (this.lottieController.isPaused === false) {
      this.onAnimationEnd();
    }
    this.lottieController?.destroy();
    lottie.destroy(this.lottieID);
    this.lottieController = null;
  }

  /**
   * autoSkip 没有传递 默认为true
   */
  build() {
    RNViewBase({ ctx: this.ctx, tag: this.tag }) {
      LottieView({
        lottieId: this.lottieID,
        path: this.path,
        animationData: this.animationData,
        loop: this.loop, //是否循环播放，非必须，默认为true
        autoplay: this.autoPlay, //是否自动播放，非必须，默认为true
        controller: this.lottieController, //lottie动画控制器
        contentMode: this.contentMode,
        listener: this.listener,
        useCache: this.cacheComposition,
        imagePath: this.imagePath
      })
        .width('100%')
        .height('100%')
    }
  }
}
