/*
 * 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 { LogDomain, LogHelper } from '@ohos/basicutils';
import { AppCenterGridStyleConfig } from '../common/AppCenterGridStyleConfig';
import { AppGridItemInfo } from '@ohos/launchercommon/src/main/ets/bean/AppGridItemInfo';
import { SCBSessionRect } from '@ohos/windowscene';

const TAG = 'FoldedDeviceAcViewModel';
const logger: LogHelper = LogHelper.getLogHelper(LogDomain.HOME, 'AC-' + TAG);
const INVALID_SCREEN_ID: number = -1;

export enum SCBFoldedState {
  UNKNOWN = 0,
  HALF_FOLDED_VIRTUAL_KEYBOARD,
  HALF_FOLDED_PHYSICAL_KEYBOARD,
  HALF_FOLDED,
  UNFOLDED_VERTICAL,
  UNFOLDED_HORIZONTAL
}

export class FoldStatusChangeEvent {
  public screenId: number = INVALID_SCREEN_ID
  public curState: number = 0;
  public tarState: number = 0;
  public foldCreaseRegion: SCBSessionRect = new SCBSessionRect(0, 0, 0, 0);
  public bSideWidth: number = 0;
  public bSideHeight: number = 0;
  public cSideWidth: number = 0;
  public cSideHeight: number = 0;
  public rotation: number = 0;
}

export enum FoldAcGridLayoutConstants {
  DEFAULT_HPR_APP_CENTER_GRID_ROWS = 5,
  DEFAULT_HPR_APP_CENTER_GRID_COLUMNS = 8,
  DEFAULT_HPR_APP_CENTER_HORIZONTAL_GRID_ROWS = 4,
  DEFAULT_HPR_APP_CENTER_HORIZONTAL_GRID_COLUMNS = 10
}

/**
 * 大屏幕机专用VM
 */
export class FoldedDeviceAcViewModel {
  public static readonly FOLD_STATE_CHANGE_EVT_NAME = 'hopper_state_change';
  public static readonly ROTATE_DOOR_VALUE = 300;
  public static readonly SQUEEZE_TRIGGER_Y_OFFSET_VALUE = 41.3;
  private static mInstance: Map<number, FoldedDeviceAcViewModel> = new Map();
  private static readonly ANIMATION_TIME_UNFOLDED_ASC: number[] = [418, 385, 334, 300];
  private static readonly ANIMATION_TIME_FOLDED_ASC: number[] = [300, 400, 405];
  private static readonly ANIMATION_TIME_UNFOLDED_OPACITY_ASC: number[] = [518, 495, 384, 197];
  private static readonly ANIMATION_TIME_FOLDED_OPACITY_ASC: number[] = [518, 495, 384];
  private static readonly ANIMATION_TIME_FOLDED_DESC: number[] = [310, 305, 300];
  private static readonly ANIMATION_TIME_UNFOLDED_DESC: number[] = [380, 350, 320, 300];
  /**
   * 是否大屏幕机设备
   */
  private mIsFoldedDevice: boolean = false;
  private mCurrentFoldState: SCBFoldedState;
  private mLastFoldState: SCBFoldedState;
  private mCurrentRotation: number = 0;
  private swiperItemSpace: number = 0;
  private mLastColumns: number = 8;
  private mAcGridPaddingTop: number = 0;
  private mAcDraggableAreaBottom: number = 0;
  private mAcBSideBottom: number = 0;
  private mUnfoldedAcBSideBottom: number = 0;
  private mAcCSideTop: number = 0;
  private squeezeTriggerYOffsetValue: number = 41.34;
  private screenId: number = 0;

  protected foldedVerticalAppItemPosX: number[] = [];
  protected foldedVerticalAppItemRtlPosX: number[] = [];
  protected foldedVerticalAppItemPosY: number[] = [];
  protected foldedVerticalAppItemEdgePos: Array<Array<number>> = [];
  protected foldedVerticalCircleMap: Map<number, number[]> = new Map();
  protected foldedHorizontalAppItemPosX: number[] = [];
  protected foldedHorizontalAppItemRtlPosX: number[] = [];
  protected foldedHorizontalAppItemPosY: number[] = [];
  protected foldedHorizontalAppItemEdgePos: Array<Array<number>> = [];
  protected foldedHorizontalCircleMap: Map<number, number[]> = new Map();
  protected foldedDefaultAppItemPosX: number[] = [];
  protected foldedDefaultAppItemRtlPosX: number[] = [];
  protected foldedDefaultAppItemPosY: number[] = [];
  protected foldedDefaultAppItemEdgePos: Array<Array<number>> = [];
  protected foldedDefaultCircleMap: Map<number, number[]> = new Map();
  protected foldedAppItemOpacity: number[] = [];

  private constructor() {
    this.mCurrentFoldState = SCBFoldedState.UNKNOWN;
    this.mLastFoldState = SCBFoldedState.UNKNOWN;
    logger.showInfo(`Construct Current state is ${this.mCurrentFoldState}`);
  }

  public static getInstance(screenId: number = 0): FoldedDeviceAcViewModel {
    if (!FoldedDeviceAcViewModel.mInstance.has(screenId)) {
      FoldedDeviceAcViewModel.mInstance.set(screenId, new FoldedDeviceAcViewModel());
      FoldedDeviceAcViewModel.mInstance.get(screenId)?.setScreenId(screenId);
    }
    return FoldedDeviceAcViewModel.mInstance.get(screenId)!;
  }

  public static deleteInstance(screenId: number = 0): void {
    if (FoldedDeviceAcViewModel.mInstance.has(screenId)) {
      logger.showInfo(`mInstance delete: ${screenId}`);
      FoldedDeviceAcViewModel.mInstance.delete(screenId);
    }
  }

  public getCurrentRotation(): number {
    return this.mCurrentRotation;
  }

  public setScreenId(screenId: number): void {
    this.screenId = screenId;
  }

  /**
   * 角度变化设定
   * @param rot
   */
  public setCurrentRotation(rot: number): void {
    logger.showInfo(`Rotation change from ${this.mCurrentRotation} to ${rot} screenId: ${this.screenId}`);
    this.mCurrentRotation = rot;
  }

  public getLastFoldState(): SCBFoldedState {
    return this.mLastFoldState;
  }

  /**
   * 获取大屏幕机状态
   * @returns
   */
  public getCurrentFoldState(): SCBFoldedState {
    return this.mCurrentFoldState;
  }

  /**
   * 设置大屏幕机状态
   * @param cs
   */
  public setFoldState(cs: number): void {
    if (!this.validateFoldStateValue(cs)) {
      logger.showWarn(`Invalid Fold State value ${cs}`);
      return;
    }
    FoldedDeviceAcViewModel.mInstance.forEach((value) => {
      value.mLastFoldState = this.mCurrentFoldState;
      value.mCurrentFoldState = this.convertStateEnum(cs);
    });
    logger.showInfo(`Current status is ${this.mCurrentFoldState} from ${this.mLastFoldState}-${cs}`);
  }

  private validateFoldStateValue(cs: number): boolean {
    return cs >= SCBFoldedState.UNKNOWN && cs <= SCBFoldedState.UNFOLDED_HORIZONTAL;
  }

  private convertStateEnum(cs: number): SCBFoldedState {
    switch (cs) {
      case 0:
        return SCBFoldedState.UNKNOWN;
      case 1:
        return SCBFoldedState.HALF_FOLDED_VIRTUAL_KEYBOARD;
      case 2:
        return SCBFoldedState.HALF_FOLDED_PHYSICAL_KEYBOARD;
      case 3:
        return SCBFoldedState.HALF_FOLDED;
      case 4:
        return SCBFoldedState.UNFOLDED_VERTICAL;
      case 5:
        return SCBFoldedState.UNFOLDED_HORIZONTAL;
    }
    return SCBFoldedState.UNKNOWN;
  }

  /**
   * 是否是大屏幕机-PC
   * @returns 是否是大屏幕机设备
   */
  public isFoldedDevice(): boolean {
    return this.mIsFoldedDevice;
  }

  /**
   * 设置-是否大屏幕机-PC
   * @param fd
   */
  public setIsFoldedDevice(fd: boolean): void {
    logger.showInfo(`Current device is folded: ${fd}`);
    FoldedDeviceAcViewModel.mInstance.forEach((value) => {
      value.mIsFoldedDevice = fd;
    });
  }

  /**
   * 是否是横屏展开态
   *
   * @returns
   */
  public isUnFoldedHorizontal(): boolean {
    return this.mCurrentFoldState === SCBFoldedState.UNFOLDED_HORIZONTAL;
  }

  public isUnFoldedVertical(): boolean {
    return this.mCurrentFoldState === SCBFoldedState.UNFOLDED_VERTICAL;
  }

  public isUnFolded(): boolean {
    return this.mCurrentFoldState === SCBFoldedState.UNFOLDED_VERTICAL ||
      this.mCurrentFoldState === SCBFoldedState.UNFOLDED_HORIZONTAL;
  }

  /**
   * 是否折叠态
   * @returns
   */
  public isHalfFolded(): boolean {
    return this.mCurrentFoldState === SCBFoldedState.HALF_FOLDED;
  }

  /**
   * 是否磁吸态
   * @returns
   */
  public isKeyboardOnCSide(): boolean {
    return this.mCurrentFoldState === SCBFoldedState.HALF_FOLDED_VIRTUAL_KEYBOARD ||
      this.mCurrentFoldState === SCBFoldedState.HALF_FOLDED_PHYSICAL_KEYBOARD;
  }

  /**
   * 是否是虚拟键盘态
   * @returns
   */
  public isHalfFoldedVirtualKeyboard(): boolean {
    return this.mCurrentFoldState === SCBFoldedState.HALF_FOLDED_VIRTUAL_KEYBOARD;
  }

  /**
   * 获取表格间距
   *
   * @returns
   */
  public getSwiperItemSpace(): number {
    return this.swiperItemSpace;
  }

  /**
   * 更新表格间距
   * @param space
   */
  public setSwiperItemSpace(space: number): void {
    logger.showInfo(`setSwiperItemSpace-${this.swiperItemSpace}-${space} screenId: ${this.screenId}`);
    const dif: number = space - this.swiperItemSpace;
    this.swiperItemSpace = space;
    this.mAcCSideTop += dif;
  }

  /**
   * 上一回合的列数
   * @param cols
   */
  public setLastColumns(cols: number): void {
    this.mLastColumns = cols;
  }

  /**
   * 获取上次的表格列数
   * @returns
   */
  public getLastColumns(): number {
    return this.mLastColumns;
  }

  /**
   * 获取表格上间距
   * @returns
   */
  public getAcGridPaddingTop(): number {
    return this.mAcGridPaddingTop;
  }

  /**
   * 设置表格上间距
   * @param top
   */
  public setAcGridPaddingTop(top: number): void {
    logger.showInfo(`setAcGridPaddingTop-${this.mAcGridPaddingTop}-${top} screenId: ${this.screenId}`);
    this.mAcGridPaddingTop = top;
  }

  /**
   *  获取可拖拽区域的底边位置-VP
   * @returns
   */
  public getAcDraggableAreaBottom(): number {
    return this.mAcDraggableAreaBottom;
  }

  public isNearBSideBottom(y: number): boolean {
    logger.showInfo(`isNearBSideBottom-${this.mUnfoldedAcBSideBottom}-${y} screenId: ${this.screenId}`);
    return y >= this.mUnfoldedAcBSideBottom - this.squeezeTriggerYOffsetValue;
  }

  /**
   * 重新计算拖拽区域的底边
   * @param gridStyleConfig
   */
  public recalculateAcDraggableAreaBottom(gridStyleConfig: AppCenterGridStyleConfig): void {
    if (this.mCurrentFoldState === SCBFoldedState.HALF_FOLDED_VIRTUAL_KEYBOARD ||
      this.mCurrentFoldState === SCBFoldedState.HALF_FOLDED_PHYSICAL_KEYBOARD) {
      this.mAcDraggableAreaBottom = gridStyleConfig.mAppCenterMarginTop + gridStyleConfig.mGridHeight;
    } else {
      this.updateDraggableAreaBottom(gridStyleConfig.mAppCenterMarginTop, gridStyleConfig.mGridHeight);
      this.mUnfoldedAcBSideBottom = gridStyleConfig.mAppCenterMarginTop + gridStyleConfig.mGridHeight;
      logger.showInfo(`mAcDraggableAreaBottom-${gridStyleConfig.mAppCenterMarginTop}-${gridStyleConfig.mGridHeight}-${this.swiperItemSpace}`);
    }
    if (this.mCurrentFoldState === SCBFoldedState.HALF_FOLDED) {
      this.mAcBSideBottom = gridStyleConfig.mAppCenterMarginTop + gridStyleConfig.mGridHeight;
      this.mAcCSideTop = gridStyleConfig.mAppCenterMarginTop + gridStyleConfig.mGridHeight + this.swiperItemSpace;
    }

    logger.showInfo(`recalculateAcDraggableAreaBottom-${this.mAcDraggableAreaBottom}-${this.mCurrentFoldState} screenId: ${this.screenId}`);
  }

  public updateDraggableAreaBottom(mrgTop: number, gh: number): void {
    this.mAcDraggableAreaBottom = mrgTop + gh * 2 + this.swiperItemSpace;
    logger.showInfo(`updateDraggableAreaBottom ${this.mAcDraggableAreaBottom} screenId: ${this.screenId}`);
  }

  public isRotating(oldH: number, newH: number): boolean {
    return Math.abs(oldH - newH) > FoldedDeviceAcViewModel.ROTATE_DOOR_VALUE;
  }

  public isDragInMiddleArea(y: number): boolean {
    return y > this.mAcBSideBottom && y < this.mAcCSideTop;
  }
  public getMiddleAreaHeight(): number {
    return this.mAcCSideTop - this.mAcBSideBottom;
  }

  public calculateRectMap(rows: number, cols: number): Map<number, number[]> {
    const map = new Map<number, number[]>();
    let circle = 0;
    let left = 0;
    let right = cols - 1;
    let top = 0;
    let bottom = rows - 1;

    while (left <= right && top <= bottom) {
      const circleElement: number[] = [];

      // 从左到右遍历顶部行
      for (let j = left; j <= right; j++) {
        const index = top * cols + j;
        circleElement.push(index);
      }

      // 从上到下遍历右侧列
      for (let i = top + 1; i < bottom; i++) {
        const index = i * cols + right;
        circleElement.push(index);
      }

      // 从右到左遍历底部行
      if (top < bottom) {
        for (let j = right; j >= left; j--) {
          const index = bottom * cols + j;
          circleElement.push(index);
        }
      }

      // 从下到上遍历左侧列
      if (left < right) {
        for (let i = bottom - 1; i > top; i--) {
          const index = i * cols + left;
          circleElement.push(index);
        }
      }

      map.set(circle, circleElement);
      circle++;
      left++;
      right--;
      top++;
      bottom--;
    }
    let resultMap: Map<number, number[]> = new Map();
    for (let i = 0, j = map.size - 1; j >= 0; i++, j--) {
      const arr: number[] | undefined = map.get(j);
      arr?.sort();
      resultMap.set(i, arr ?? []);
    }
    return resultMap;
  }

  public initFoldedAnimationData(): void {
    if (!FoldedDeviceAcViewModel.getInstance().isFoldedDevice()) {
      return;
    }

    let acRow: number = FoldAcGridLayoutConstants.DEFAULT_HPR_APP_CENTER_HORIZONTAL_GRID_COLUMNS;
    let acColumn: number = FoldAcGridLayoutConstants.DEFAULT_HPR_APP_CENTER_GRID_COLUMNS;

    let centerRow: number = (acRow - 1) / 2;
    if (centerRow === 0) {
      centerRow = 1;
    }
    let centerColumn: number = (acColumn - 1) / 2;
    if (centerColumn === 0) {
      centerColumn = 1;
    }
    logger.showInfo(`Folded init animation data - vertical - [acRow, acColumn]=[${acRow}, ${acColumn}], horizontal - [acRow, acColumn]=[${acColumn}, ${acRow}] screenId: ${this.screenId}`);

    //展开态
    let total = acRow * acColumn;
    for (let index = 0; index < total; index++) {
      this.foldedAppItemOpacity.push(0);

      let rawRow = index / acColumn;
      let rawColumn = index % acColumn;
      let transX = (rawColumn - centerColumn) / centerColumn * 100;
      let rtlTransX = (centerColumn - rawColumn) / centerColumn * 100;
      let transY = (Math.floor(rawRow) - centerRow) / centerRow * 100;

      //竖屏
      this.foldedVerticalAppItemEdgePos.push([transX, transY, rtlTransX]);
      this.foldedVerticalAppItemPosX.push(transX);
      this.foldedVerticalAppItemPosY.push(transY);
      this.foldedVerticalAppItemRtlPosX.push(rtlTransX);

      rawRow = index / acRow;
      rawColumn = index % acRow;
      transX = (rawColumn - centerRow) / centerRow * 100;
      rtlTransX = (centerRow - rawColumn) / centerRow * 100;
      transY = (Math.floor(rawRow) - centerColumn) / centerColumn * 100;

      //横屏
      this.foldedHorizontalAppItemEdgePos.push([transX, transY, rtlTransX]);
      this.foldedHorizontalAppItemPosX.push(transX);
      this.foldedHorizontalAppItemRtlPosX.push(rtlTransX);
      this.foldedHorizontalAppItemPosY.push(transY);

    }

    // 折叠、磁吸
    let halfTotal = total / 2;
    centerRow = (FoldAcGridLayoutConstants.DEFAULT_HPR_APP_CENTER_GRID_ROWS - 1) / 2;
    if (centerRow === 0) {
      centerRow = 1;
    }
    for (let index = 0; index < halfTotal; index++) {
      let rawRow = index / acColumn;
      let rawColumn = index % acColumn;
      let transX = (rawColumn - centerColumn) / centerColumn * 100;
      let rtlTransX = (centerColumn - rawColumn) / centerColumn * 100;
      let transY = (Math.floor(rawRow) - centerRow) / centerRow * 100;

      this.foldedDefaultAppItemEdgePos.push([transX, transY, rtlTransX]);
      this.foldedDefaultAppItemPosX.push(transX);
      this.foldedDefaultAppItemPosY.push(transY);
      this.foldedDefaultAppItemRtlPosX.push(rtlTransX);
    }

    this.foldedVerticalCircleMap =
      this.calculateRectMap(FoldAcGridLayoutConstants.DEFAULT_HPR_APP_CENTER_HORIZONTAL_GRID_COLUMNS,
        FoldAcGridLayoutConstants.DEFAULT_HPR_APP_CENTER_GRID_COLUMNS);
    this.foldedHorizontalCircleMap =
      this.calculateRectMap(FoldAcGridLayoutConstants.DEFAULT_HPR_APP_CENTER_GRID_COLUMNS,
        FoldAcGridLayoutConstants.DEFAULT_HPR_APP_CENTER_HORIZONTAL_GRID_COLUMNS);
    this.foldedDefaultCircleMap = this.calculateRectMap(FoldAcGridLayoutConstants.DEFAULT_HPR_APP_CENTER_GRID_ROWS,
      FoldAcGridLayoutConstants.DEFAULT_HPR_APP_CENTER_GRID_COLUMNS);
  }

  public transformToPortrait(aii: AppGridItemInfo): AppGridItemInfo {
    if (!this.isFoldedDevice) {
      return aii;
    }

    if (this.isUnFoldedHorizontal()) {
      let r = aii.row;
      let c = aii.column;
      let idx = ((r ?? 0) * FoldAcGridLayoutConstants.DEFAULT_HPR_APP_CENTER_HORIZONTAL_GRID_COLUMNS) + (c ?? 0);
      let newMappedRow = Math.floor(idx / FoldAcGridLayoutConstants.DEFAULT_HPR_APP_CENTER_GRID_COLUMNS);
      let newMappedCol = idx % FoldAcGridLayoutConstants.DEFAULT_HPR_APP_CENTER_GRID_COLUMNS;
      aii.row = newMappedRow;
      aii.column = newMappedCol;
      logger.showInfo(`transformToPortrait-${r}-${c}-${idx}-${newMappedRow}-${newMappedCol}-${aii.bundleName}`);
    }

    return aii;
  }

  public getFoldedVerticalAppItemPosX(): number[] {
    return this.foldedVerticalAppItemPosX;
  }

  public getFoldedVerticalAppItemRtlPosX(): number[] {
    return this.foldedVerticalAppItemRtlPosX;
  }

  public getFoldedVerticalAppItemPosY(): number[] {
    return this.foldedVerticalAppItemPosY;
  }

  public getFoldedVerticalAppItemEdgePos(): Array<Array<number>> {
    return this.foldedVerticalAppItemEdgePos;
  }

  public getFoldedVerticalCircleMap(): Map<number, number[]> {
    return this.foldedVerticalCircleMap;
  }

  public getFoldedHorizontalAppItemPosX(): number[] {
    return this.foldedHorizontalAppItemPosX;
  }

  public getFoldedHorizontalAppItemRtlPosX(): number[] {
    return this.foldedHorizontalAppItemRtlPosX;
  }


  public getFoldedHorizontalAppItemPosY(): number[] {
    return this.foldedHorizontalAppItemPosY;
  }

  public getFoldedHorizontalAppItemEdgePos(): Array<Array<number>> {
    return this.foldedHorizontalAppItemEdgePos;
  }

  public getFoldedHorizontalCircleMap(): Map<number, number[]> {
    return this.foldedHorizontalCircleMap;
  }

  public getFoldedDefaultAppItemPosX(): number[] {
    return this.foldedDefaultAppItemPosX;
  }

  public getFoldedDefaultAppItemRtlPosX(): number[] {
    return this.foldedDefaultAppItemRtlPosX;
  }

  public getFoldedDefaultAppItemPosY(): number[] {
    return this.foldedDefaultAppItemPosY;
  }

  public getFoldedDefaultAppItemEdgePos(): Array<Array<number>> {
    return this.foldedDefaultAppItemEdgePos;
  }

  public getFoldedDefaultCircleMap(): Map<number, number[]> {
    return this.foldedDefaultCircleMap;
  }

  public getFoldedAppItemOpacity(): number[] {
    return this.foldedAppItemOpacity;
  }

  public getFoldedTimeAsc(): Array<number> {
    return this.isUnFolded() ? FoldedDeviceAcViewModel.ANIMATION_TIME_UNFOLDED_ASC :
    FoldedDeviceAcViewModel.ANIMATION_TIME_FOLDED_ASC;
  }

  public getFoldedOpacityTimeAsc(): number[] {
    return FoldedDeviceAcViewModel.ANIMATION_TIME_FOLDED_OPACITY_ASC;
  }

  public getUnFoldedOpacityTimeAsc(): number[] {
    return FoldedDeviceAcViewModel.ANIMATION_TIME_UNFOLDED_OPACITY_ASC;
  }
}