/*
 * Copyright (c) Huawei Device Co., Ltd. 2024-2025. All rights reserved.
 * 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 lazy { Dispatch, reduxSubscribe, Unsubscribe } from '@ohos/common/src/main/ets/redux';
import lazy { OhCombinedState } from '@ohos/common/src/main/ets/redux';
import lazy { PersistType, PreferencesService } from '@ohos/common/src/main/ets/service/preferences/PreferencesService';
import lazy { PropTag } from '@ohos/common/src/main/ets/service/preferences/PropTag';
import lazy { AspectRatioOperation } from '@ohos/common/src/main/ets/function/aspectratio/AspectRatioOperation';
import lazy { BaseFunction } from '@ohos/common/src/main/ets/function/core/BaseFunction';
import lazy { FeatureManager } from '@ohos/common/src/main/ets/function/core/FeatureManager';
import lazy { FunctionId } from '@ohos/common/src/main/ets/function/core/functionproperty/FunctionId';
import lazy { FloatingShutterAction } from './FloatingShutterAction';
import camera from '@ohos.multimedia.camera';
import lazy { ModeType } from '@ohos/common/src/main/ets/mode/ModeType';
import lazy { DisplayCalculator } from '@ohos/common/src/main/ets/component/xcomponent/DisplayCalculator';
import lazy { HiLog } from '@ohos/common/src/main/ets/utils/HiLog';
import lazy { ComponentIdKeys } from '@ohos/common/src/main/ets/utils/ComponentIdKeys';
import lazy { AdaptiveLayoutService } from '@ohos/common/src/main/ets/service/UIAdaptive/AdaptiveLayoutService';
import lazy { CommonConstants } from '@ohos/common/src/main/ets/statistics/CommonConstants';
import lazy { BaseComponent } from '@ohos/common/src/main/ets/worker/BaseComponent';
import lazy { EventBusManager } from '@ohos/common/src/main/ets/worker/eventbus/EventBusManager';
import lazy { EventBus } from '@ohos/common/src/main/ets/worker/eventbus/EventBus';
import lazy { WindowService } from '@ohos/common/src/main/ets/service/window/WindowService';
import lazy { DeviceInfo } from '@ohos/common/src/main/ets/component/deviceinfo/DeviceInfo';
import lazy { DisplayService } from '@ohos/common/src/main/ets/service/UIAdaptive/DisplayService';
import lazy { WindowActionType } from '@ohos/common/src/main/ets/redux/actions/WindowActionType';
import lazy { Action } from '@ohos/common/src/main/ets/redux/actions/Action';
import lazy { PositionType } from '@ohos/common/src/main/ets/utils/types';

const FLOATING_SHUTTER_LENGTH: number = 54;
const FLOATING_SHUTTER_MIDDLE: number = 2;
const FLOATING_SHUTTER_CREASE: number = 19;
const FLOATING_SHUTTER_HALF_COLLAPS_HEIGHT = 140;
const FLOATING_SHUTTER_VDE_HALF_COLLAPS_HEIGHT = 45;
const VDE_FLOATING_SHUTTER = 36;
const TOUCH_UP_DAILY: number = 50;
const FOOT_BAR_WIDTH: number = 40;
const FLOATING_SHUTTER_GRL_WIDTH: number = 400;

class LatestPositionInfo {
  public initX: number = 0;
  public initY: number = 0;
}

class FloatingShutterDispatcher {
  private mDispatch: Dispatch = (data) => data;

  public setDispatch(dispatch: Dispatch) {
    this.mDispatch = dispatch;
  }

  public clickFloatingShutterButton(isPicker: boolean): void {
    this.mDispatch(FloatingShutterAction.clickFloatingShutterButton(isPicker));
  }

  public disAbleModeBarChanged(isNeedDisShowingMode: boolean): void {
    this.mDispatch(Action.disAbleModeBarChanged(isNeedDisShowingMode));
  }
}

/* instrument ignore file */
const TAG = 'FloatingShutterButton';

@Component
export struct FloatingShutterButton {
  private mEventBus: EventBus = EventBusManager.getInstance().getEventBus();
  private mBase: BaseComponent = new BaseComponent();
  private mSubscriber: Unsubscribe = {
    destroy: () => {
    }
  };
  // 移动的偏移量
  @State moveOffsetY: number = 0;
  @State moveOffsetX: number = 0;
  @State previewPositionDefault: number = AdaptiveLayoutService.getInstance().previewPosition4to3;
  @State previewPosition1to1: number = AdaptiveLayoutService.getInstance().previewPosition1to1;
  private latestPosition: LatestPositionInfo = { initX: 0, initY: 0 };
  private initX: number = 0;
  private initY: number = 0;
  // 按下时自身顶点xy轴位置
  private selfY: number = 0;
  private selfX: number = 0;
  // 按下时距屏幕的xy轴位置
  private screenY: number = 0;
  private screenX: number = 0;
  @State screenWidth: number = 0;
  @State screenHeight: number = 0;
  private isShowLandscape: boolean = false;
  @State @Watch('resetOffset') isShowSemiCollapsed: boolean = false;
  private adjustLandscapeX: number = 0;
  @State previewWidthDefault: number = 0;
  @State previewHeightDefault: number = 0;
  @State previewHeight1to1: number = 0;
  private mAction: FloatingShutterDispatcher = new FloatingShutterDispatcher();
  protected mPreferencesService: PreferencesService = PreferencesService.getInstance();
  private isPicker: boolean = false;
  @State @Watch('resetOffsetY') isHalfCollapsLEM: boolean = false;
  @State @Watch('updateDensity') density: number = 1//DisplayService.getInstance().getDisplay().densityPixels;
  @State isShowSubScreenRadius: boolean = false;
  @State isShowRingLightView: boolean = false;
  @State isVdeLandscape: boolean = false;
  @State isVdeSemiCollapsed: boolean = false;
  private isClickFloatingShutterButton: boolean = false;
  @State isShowLowAngleShotView: boolean = false;
  @Prop footBarPosition: number = 0;
  @State mode: ModeType = ModeType.NONE;
  @Prop isHdr: boolean = false;
  @State isShowTricollaps: boolean = false;
  @Prop @Watch('initPosition') previewPosition: PositionType = { x: 0, y: 0 };
  @State xComponentWidth: number = 0;
  @State xComponentHeight: number = 0;

  aboutToAppear() {
    this.mSubscriber = reduxSubscribe((state: OhCombinedState) => {
      this.screenWidth = state.get<number>('windowReducer', 'windowWidth');
      this.screenHeight = state.get<number>('windowReducer', 'windowHeight');
      this.isShowLandscape = state.get<boolean>('collapsReducer', 'isShowLandscape');
      this.isShowSemiCollapsed = state.get<boolean>('collapsReducer', 'isShowSemiCollapsed');
      this.density = state.get<number>('collapsReducer', 'density');
      this.isHalfCollapsLEM = state.get<boolean>('collapsReducer', 'isHalfCollapsLEM');
      this.isShowRingLightView = state.get<boolean>('ringLightReducer', 'isShowRingLightView');
      this.isVdeLandscape = state.get<boolean>('collapsReducer', 'isVdeLandscape');
      this.isVdeSemiCollapsed = state.get<boolean>('collapsReducer', 'isVdeSemiCollapsed')
      this.isShowLowAngleShotView = state.get<boolean>('collapsReducer', 'isShowLowAngleShotView');
      this.mode = state.get<ModeType>('modeReducer', 'mode');
      this.isShowTricollaps = state.get<boolean>('collapsReducer', 'isShowTricollaps');
      this.xComponentWidth = state.get<number>('previewReducer', 'xComponentWidth');
      this.xComponentHeight = state.get<number>('previewReducer', 'xComponentHeight');
    }, (dispatch: Dispatch) => {
      this.mAction.setDispatch(dispatch);
    });
    this.mEventBus.on(WindowActionType.ON_SIZE_CHANGE, this.initPosition.bind(this), this.mBase.hashCode());
    this.initPosition();
  }

  private resetOffsetY(): void {
    if (this.isVdeSemiCollapsed) {
      this.resetVdeSemiCollapsOffsetY();
      return;
    }
    if (DeviceInfo.isTablet()) {
      this.resetTabletOffsetY();
      return;
    }
    if (this.isHalfCollapsLEM) {
      let halfCollapsHeight: number = FLOATING_SHUTTER_HALF_COLLAPS_HEIGHT;
      if (this.moveOffsetY <= 0) {
        this.moveOffsetY = 0;
      } else if (this.moveOffsetY >= this.previewHeightDefault + halfCollapsHeight) {
        this.moveOffsetY = this.previewHeightDefault + halfCollapsHeight;
      }
      return;
    }
    let previewPosition: number = this.previewPositionDefault;
    let previewHeight: number = this.isVdeLandscape ? this.previewWidthDefault : this.previewHeightDefault;
    if (this.moveOffsetY <= previewPosition) {
      this.moveOffsetY = previewPosition;
    } else if (this.moveOffsetY >= previewPosition + previewHeight - FLOATING_SHUTTER_LENGTH) {
      this.moveOffsetY = previewPosition + previewHeight - FLOATING_SHUTTER_LENGTH;
    }
  }

  private resetOffset(): void {
    if (DeviceInfo.isTablet()) {
      this.resetTabletOffsetX();
      return;
    }
    if (this.isShowSemiCollapsed) {
      if (this.moveOffsetX <= (this.screenWidth - this.previewWidthDefault) /
        FLOATING_SHUTTER_MIDDLE - this.adjustLandscapeX) {
        this.moveOffsetX = (this.screenWidth - this.previewWidthDefault) /
          FLOATING_SHUTTER_MIDDLE - this.adjustLandscapeX;
      } else if (this.moveOffsetX >= this.screenWidth / 2 - FLOATING_SHUTTER_LENGTH - FLOATING_SHUTTER_CREASE) {
        this.moveOffsetX = this.screenWidth / 2 - FLOATING_SHUTTER_LENGTH - FLOATING_SHUTTER_CREASE;
      }
    } else if (this.isShowTricollaps) {
      if (this.moveOffsetX <= (this.screenWidth - this.previewWidthDefault) /
        FLOATING_SHUTTER_MIDDLE - this.adjustLandscapeX) {
        this.moveOffsetX = (this.screenWidth - this.previewWidthDefault) /
          FLOATING_SHUTTER_MIDDLE - this.adjustLandscapeX;
      } else if (this.moveOffsetX >= this.screenWidth - FLOATING_SHUTTER_LENGTH - (
        (this.screenWidth - this.previewWidthDefault) / FLOATING_SHUTTER_MIDDLE) - this.adjustLandscapeX +
        FLOATING_SHUTTER_GRL_WIDTH) {
        this.moveOffsetX = this.screenWidth - FLOATING_SHUTTER_LENGTH -
          ((this.screenWidth - this.previewWidthDefault) / FLOATING_SHUTTER_MIDDLE) - this.adjustLandscapeX +
          FLOATING_SHUTTER_GRL_WIDTH;
      }
    } else {
      if (this.moveOffsetX <= (this.screenWidth - this.previewWidthDefault) /
        FLOATING_SHUTTER_MIDDLE - this.adjustLandscapeX) {
        this.moveOffsetX = (this.screenWidth - this.previewWidthDefault) /
          FLOATING_SHUTTER_MIDDLE - this.adjustLandscapeX;
      } else if (this.moveOffsetX >= this.screenWidth - FLOATING_SHUTTER_LENGTH - (
        (this.screenWidth - this.previewWidthDefault) / FLOATING_SHUTTER_MIDDLE) - this.adjustLandscapeX) {
        this.moveOffsetX = this.screenWidth - FLOATING_SHUTTER_LENGTH -
          ((this.screenWidth - this.previewWidthDefault) / FLOATING_SHUTTER_MIDDLE) - this.adjustLandscapeX;
      }
    }
  }

  private resetTabletOffsetY(): void {
    let previewPosition: number = WindowService.getInstance().isVertical() ? this.previewPosition.y : 0;
    if (this.moveOffsetY <= previewPosition) {
      this.moveOffsetY = previewPosition;
    } else if (this.moveOffsetY >= previewPosition + this.xComponentHeight - FLOATING_SHUTTER_LENGTH) {
      this.moveOffsetY = previewPosition + this.xComponentHeight - FLOATING_SHUTTER_LENGTH;
    }
  }

  private resetTabletOffsetX(): void {
    let footBarWidth: number = WindowService.getInstance().isVertical() ? 130 : this.adjustLandscapeX;
    if (this.moveOffsetX <= 0) {
      this.moveOffsetX = 0;
    } else if (this.moveOffsetX >= this.screenWidth - FLOATING_SHUTTER_LENGTH - footBarWidth) {
      this.moveOffsetX = this.screenWidth - FLOATING_SHUTTER_LENGTH - footBarWidth;
    }
  }

  aboutToDisappear(): void {
    this.mSubscriber.destroy();
  }

  initDefaultPreviewSize(): void {
    const functionImpl: BaseFunction = FeatureManager.getInstance().getFunction(FunctionId.ASPECT_RATIO);
    let previewSizeDefault = AspectRatioOperation.getPreviewProfile(functionImpl.getDefaultValue() as number,
      camera.CameraPosition.CAMERA_POSITION_BACK, ModeType.PHOTO).size;
    let previewRatioDefault = previewSizeDefault.width / previewSizeDefault.height;
    let xComponentSizeDefault = DisplayCalculator.calcSurfaceDisplaySize(previewRatioDefault, this.screenWidth,
      this.screenHeight);
    this.previewWidthDefault = xComponentSizeDefault.width;
    // this.previewHeightDefault = xComponentSizeDefault.height;
    this.previewHeightDefault = xComponentSizeDefault.width; // 1:1 防止拖动范围超过了界面下方的模式名
    if (this.isShowLandscape) {
      let isVertical = WindowService.getInstance().isVertical();
      HiLog.d(TAG, `isVertical: ${isVertical}, ${JSON.stringify(xComponentSizeDefault)}`);
      this.previewWidthDefault = DeviceInfo.isTablet() ? xComponentSizeDefault.width :
        isVertical ? xComponentSizeDefault.width : this.screenHeight - FOOT_BAR_WIDTH;
      this.previewHeightDefault = isVertical ? xComponentSizeDefault.height : this.screenHeight;
    }
    HiLog.i(TAG,
      `initDefaultPreviewSize done, previewWidthDefault: ${this.previewWidthDefault},
      this.previewHeightDefault:${this.previewHeightDefault}.`);
  }

  build() {
    Column()
      .width(FLOATING_SHUTTER_LENGTH)
      .height(FLOATING_SHUTTER_LENGTH)
      .borderRadius(this.isShowSubScreenRadius ? 0 : FLOATING_SHUTTER_LENGTH / FLOATING_SHUTTER_MIDDLE)
      .aspectRatio(1)
      .backgroundColor(Color.White)
      .opacity(0.9)
      .shadow({
        radius: 2,
        color: 'rgba(0, 0, 0, 0.2)',
        offsetX: 0,
        offsetY: 0
      })
      .key(ComponentIdKeys.FLOATING_SHUTTER_1)
      .position({
        x: this.moveOffsetX,
        y: this.moveOffsetY,
      })
      .accessibilityLevel(CommonConstants.ACCESSIBILITY_LEVEL_YES)
      .accessibilityText($r('app.string.floating_shutter'))
      .onClick((): void => {
        HiLog.d(TAG, 'Click capture.');
        this.isClickFloatingShutterButton = true;
        this.mAction.clickFloatingShutterButton(this.isPicker);
      })
      .onTouch((event?: TouchEvent) => this.onTouchEvent(event))
  }

  private onTouchEvent(event?: TouchEvent | undefined): void {
    if (event === undefined) {
      return;
    }
    switch (event?.type) {
      case TouchType?.Down: {
        for (let i = 0, l = event.touches.length; i < l; i++) {
          if (this.isInRegion(event?.touches[i]?.x, event?.touches[i]?.y)) {
            this.selfY = event?.touches[i]?.y;
            this.selfX = event?.touches[i]?.x;
            break;
          }
        }
        this.mAction.disAbleModeBarChanged(true);
        HiLog.i(TAG, `TouchType?.Down :selfY: ${this.selfY}, selfX:${this.selfX}.`);
      }
        break;
      case TouchType?.Move: {
        this.screenY = event?.changedTouches[0]?.screenY;
        this.screenX = event?.changedTouches[0]?.screenX;
        this.moveOffsetY = this.screenY - this.selfY;
        this.moveOffsetX = this.screenX - this.selfX;
        this.resetOffsetY();
        this.resetOffset();
      }
        break;
      case TouchType?.Up: {
        // 延迟响应touch up事件,防止click事件后响应,点击拍照之后悬浮快拍组件跳变位置。
        let timer = setTimeout(() => {
          HiLog.i(TAG, `touch up isClickFloatingShutterButton: ${this.isClickFloatingShutterButton}.`);
          if (!this.isClickFloatingShutterButton) {
            this.moveOffsetX = this.screenX - this.selfX;
            this.moveOffsetY = this.screenY - this.selfY;
            this.resetOffsetY();
            this.resetOffset();
            this.latestPosition.initX = this.moveOffsetX;
            this.latestPosition.initY = this.moveOffsetY;
            HiLog.i(TAG, `moveOffsetY: ${this.moveOffsetY}, moveOffsetX:${this.moveOffsetX}.`);
            this.mPreferencesService.putPropValue(PersistType.FOREVER,
              PropTag.FLOATING_SHUTTER, JSON.stringify(this.latestPosition));
          }
          this.isClickFloatingShutterButton = false;
          this.mAction.disAbleModeBarChanged(false);
          clearTimeout(timer);
        }, TOUCH_UP_DAILY);
      }
      default:
        break;
    }
  }

  private isInRegion(touchX: number, touchY: number): boolean {
    return touchX > 0 && touchX < FLOATING_SHUTTER_LENGTH && touchY > 0 && touchY < FLOATING_SHUTTER_LENGTH;
  }

  private initPosition() {
    this.initDefaultPreviewSize();
    this.previewPositionDefault = this.setPreViewTopPosition();
    this.adjustLandscapeX = this.isShowLandscape ?
      (this.screenWidth - this.previewWidthDefault) / FLOATING_SHUTTER_MIDDLE : 0;
    const latestPositionStr: string = this.mPreferencesService.getPropValue(PersistType.FOREVER,
      PropTag.FLOATING_SHUTTER, JSON.stringify(this.latestPosition)) as string;
    this.latestPosition = JSON.parse(latestPositionStr);
    this.moveOffsetX = this.latestPosition.initX;
    this.initY = this.latestPosition.initY;
    this.moveOffsetY = this.initY ? this.initY : this.previewPositionDefault;
    this.resetOffsetY();
    this.resetOffset();
  }

  private setPreViewTopPosition(): number {
    let position: number = this.previewPositionDefault;
    if (this.isShowLandscape) {
      position = 0;
    }
    if (DeviceInfo.isTablet()) {
      if (WindowService.getInstance().isVertical()) {
        position = this.previewPosition.y;
      } else {
        position = 0;
      }
    }
    HiLog.i(TAG, `button on PreViewTopPosition: ${position}.`);
    return position;
  }

  private updateDensity() {
    HiLog.i(TAG, 'updateDensity density=' + this.density);
    this.initPosition();
  }

  private lowAngleChangeOffsetY(): void {
    if (!this.isVdeSemiCollapsed) {
      return;
    }
    animateToImmediately({
      curve: Curve.Sharp, duration: 300, delay: 0,
    }, () => {
      this.resetVdeSemiCollapsOffsetY();
    });
  }

  private resetVdeSemiCollapsOffsetY() {
    if (this.isShowLowAngleShotView) {
      if (this.moveOffsetY <= this.previewHeightDefault / 2 + FLOATING_SHUTTER_LENGTH) {
        this.moveOffsetY = this.previewHeightDefault / 2 + FLOATING_SHUTTER_LENGTH;
      } else if (this.moveOffsetY > this.footBarPosition - FLOATING_SHUTTER_LENGTH / 2) {
        this.moveOffsetY = this.footBarPosition - FLOATING_SHUTTER_LENGTH / 2;
      }
      return;
    }
    if (this.moveOffsetY <= 0) {
      this.moveOffsetY = 0;
    } else if (this.moveOffsetY >= this.previewHeightDefault / 2) {
      this.moveOffsetY = this.previewHeightDefault / 2;
    }
  }
}