/*
 * 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,
  Trace,
  TraceUtil,
  DomainName,
  LogHelper,
} from '@ohos/basicutils';
import { sEventManager, ViewType } from '@ohos/frameworkwrapper';
import lazy { ResUtils } from '@ohos/windowscene/src/main/ets/utils/ResourceUtils';
import { RTLUtil } from '@ohos/componenthelper';
import {
  SliderButtonBaseViewModel
} from '@ohos/controlcentercommon/src/main/ets/sliderButton/SliderButtonBaseViewModel';
import {
  SliderButtonAnimViewData,
  SliderButtonViewData,
  SliderIconViewData
} from '@ohos/controlcentercommon/src/main/ets/sliderButton/SliderButtonViewData';
import { VolumeConstants, VolumeController } from './VolumnController';
import audio from '@ohos.multimedia.audio';
import { AudioHelper } from '../utils/AudioHelper';
import { IconMap } from '../utils/IconMap';
import SoundReporterController from './SoundReporterController';
import { soundSubPageController } from './SoundSubPageLayoutController';
import { AccessibilityUtil } from '@ohos/screenlockcommon/src/main/ets/utils/AccessibilityUtil';
import { AnimationSegment } from '@ohos/lottie';
import { ConfigurationConstant } from '@kit.AbilityKit';
import { DropDownAdapter } from '@ohos/systemuicommon/src/main/ets/adapter/DropDownAdapter';

const TAG = 'Ctrl.VolumeButtonViewModel';
const log: LogHelper = LogHelper.getLogHelper(LogDomain.CC, TAG);

export class VolumeButtonViewModel extends SliderButtonBaseViewModel {
  // 媒体喇叭各个等级关键帧
  public mediaLottieKeyFrames: number[][] = [[0, 29], [104, 140], [179, 214]];
  private readonly speakerWaveZero: number = 0;
  private readonly speakerWaveOne: number = 1;
  private readonly speakerWaveTwo: number = 2;
  private readonly speakerWaveThree: number = 3;
  private readonly accessTextType: string = 'text';
  private readonly accessDesType: string = 'description';
  // 音量ui的等级值,用于喇叭图标切换
  private volumeLevelOne: number = 0;
  private volumeLevelTwo: number = 0;
  private preVolumeValueLevel: number = -1;
  private outputDevice?: audio.AudioDeviceDescriptor;
  // 当前正在生效的音频流类型
  private currentVolumeType: audio.AudioVolumeType = audio.AudioVolumeType.MEDIA;
  // 当前音频流可以调整到的最小值
  private canAdjustMinValue: number = 0;
  private appearTimestamp: number = Date.now();
  public modelTag: string = TAG;

  constructor(viewData: SliderButtonViewData, animData: SliderButtonAnimViewData,
    iconViewData: SliderIconViewData, logTag: string) {
    iconViewData.startFrameIndex = 1;
    iconViewData.endFrameIndex = 270;
    iconViewData.totalFrames = 270;
    super(viewData, animData, iconViewData, logTag);
    this.modelTag = logTag;
  }

  /**
   * 更新viewModel标识
   */
  public updateTag(newTag: string): void {
    this.modelTag = newTag;
    this.updateLogTag(newTag);
  }

  public aboutToAppear() {
    this.currentVolumeType = VolumeController.getInstance().getCurrentVolumeType();
    const sliderLength: number =
      this.getViewData().isHorizontal ? this.getViewData().sliderWidth : this.getViewData().sliderHeight;
    this.canAdjustMinValue = this.getMaxValue() !== 0 ? sliderLength / this.getMaxValue() : 0;
    super.aboutToAppear();
    this.updateVolumeLevel();
    this.loadLottieData();
    // 如果lottie需要重新刷新和加载,监听lottie加载完毕事件
    sEventManager.subscribe('volumeLottieReady', this.lottieDataReady);
    if (this.getViewData().isExpand) {
      this.getLottieAnimMode().getIconViewData().iconName = $r('app.string.sound_title');
      this.getLottieAnimMode().getIconViewData().subPageIcon = $r('sys.symbol.speaker_wave_3_fill');
      this.executeSubpageAnim(true);
      sEventManager.subscribe('ControlCenterState', this.onControlCenterStateChange);
    }
    let volumePercentage = VolumeController.getInstance().getVolumePercentage();
    if (volumePercentage !== VolumeConstants.DEFAULT_VOLUME_INVALID) {
      // 从二级页回到button刷新ui进度值,防止ui值比例跳变
      const sliderLength: number =
        this.getViewData().isHorizontal ? this.getViewData().sliderWidth : this.getViewData().sliderHeight;
      this.getAnimData().uiValue = volumePercentage * sliderLength;
      log.showInfo(`button reUpdateUiValue: ${this.getAnimData().uiValue} percentage: ${volumePercentage}`);
    }
    try {
      this.outputDevice = AudioHelper.getInstance().getOutputDevice();
      this.updateVolumeIcon(true);
      // 监听音量变化
      VolumeController.getInstance().setVolumeChangeCallback(this.modelTag +
        this.appearTimestamp, this.volumeChangeCallback);
      // 监听设备类型变化
      AudioHelper.getInstance().addOutputDeviceChangeListener(this.modelTag + this.appearTimestamp, {
        onEvent: (outputDevice: audio.AudioDeviceDescriptor) => {
          log.showInfo(`outputDeviceChange: ${outputDevice.displayName}`);
          this.outputDevice = outputDevice;
          // 先刷新进度条
          VolumeController.getInstance().initAllVolumeInfo();
          this.updateVolumeValue();
          // 后刷新图标
          this.updateVolumeIcon(false);
          if (this.getAnimData().useLottieData) {
            this.refreshIcon();
          }
        }
      });
      log.showInfo(`aboutToAppear ${this.modelTag}`);
    } catch (err) {
      log.error(`fail init VolumeController ,err: ${err}`);
    }
  }

  private updateVolumeLevel(): void {
    this.volumeLevelOne = this.getMaxValue() / 3;
    this.volumeLevelTwo = this.getMaxValue() * 2 / 3;
  }

  private volumeChangeCallback = async (value: number, volumeType: audio.AudioVolumeType, needChangeTye: boolean) => {
    // 如果下拉面板不可见,不用更新ui值
    if (!DropDownAdapter.isDropDownShow()) {
      log.showInfo(`volumeChange DROPDOWN not show return, value:${value}`);
      return;
    }
    // 如果出声通道改变更新音量值
    if (this.currentVolumeType !== volumeType && !needChangeTye) {
      log.showInfo(`currentVolumeType is not same, volumeType:${volumeType}`);
      return;
    }
    this.currentVolumeType = volumeType;
    this.onPhysicsValueChange(value);
    if (this.physValUpdateUI) {
      this.saveVolumeUIPercentage();
    }
    // 更新图标
    if (needChangeTye) {
      this.updateVolumeIcon(false);
    }
  }

  /**
   * 进度条拖拽场景改变图标颜色(lottie改色暂时屏蔽)
   *
   * @param isChosen 是否是拖动进度条的高亮状态
   */
  public changeIconColor(isChosen: boolean): void {
    log.showInfo(`changeIconColor volume isChosen: ${isChosen}`)
    // 换肤场景的深色模式在拖动进图条时需要改变颜色
    let isSysColor = AppStorage.get('isSysColor') as boolean;
    let darkColorMode = this.currentColorMode === ConfigurationConstant.ColorMode.COLOR_MODE_DARK;
    if (isSysColor || !darkColorMode) {
      return;
    }
    let changeColor = isChosen ? $r('app.color.control_center_brightness_sun_black') :
      $r('app.color.control_center_brightness_sun_write');
    if (!this.getAnimData().useLottieData) {
      this.getAnimData().iconColor = changeColor;
    }
  }

  private lottieDataReady = () => {
    log.showInfo(`subscribe volumeLottieReady ${this.modelTag}`);
    this.loadLottieData();
    this.getLottieAnimMode().onCanvasReady();
  }

  private onControlCenterStateChange = (state: number) => {
    if (state === 0) {
      log.showInfo(`onControlCenterStateChange state ${state}`);
      this.executeSubpageAnim(false);
    }
  }

  public aboutToDisappear() {
    log.showInfo(`aboutToDisappear ${this.modelTag}`);
    super.aboutToDisAppear();
    sEventManager.off('volumeLottieReady', this.lottieDataReady);
    sEventManager.off('ControlCenterState', this.onControlCenterStateChange);
    VolumeController.getInstance().setVolumeChangeCallback(this.modelTag + this.appearTimestamp, undefined);
    AudioHelper.getInstance().removeOutputDeviceChangeListener(this.modelTag + this.appearTimestamp);
  }

  /**
   * 无障碍模式下语音播报内容
   * @param type
   * @returns
   */
  public getAccessibility(type: string): string {
    if (type === this.accessTextType) {
      return ResUtils.getInnerStringNumS($r('app.string.cc_accessibility_str_volume'),
        `${this.getAccessibilityPhysicsValue()}%`);
    } else if (type === this.accessDesType) {
      let announceDesc = ResUtils.getInnerString(this.getViewData().isHorizontal ?
      $r('app.string.cc_accessibility_str_change_volume_desc') :
      $r('app.string.cc_accessibility_str_change_vertical_volume_desc'));
      if (!this.getViewData().isExpand && !this.getViewData().isSingleFoldStyle) {
        announceDesc += ' ' + ResUtils.getInnerString($r('app.string.cc_accessibility_str_long_click'));
      }
      return announceDesc;
    } else {
      return '';
    }
  }

  /**
   * 加载lottie动画数据
   * @returns 是否加载成功
   */
  public loadLottieData(): boolean {
    let lottieData = VolumeController.getInstance().lottieData;
    log.showInfo(`loadLottieData, lottieData is null: ${lottieData === null}, modelTag:${this.modelTag}`);
    if (lottieData !== null) {
      let curFrame: number = this.getCurrentFrame() <= 0 ? 1 : this.getCurrentFrame();
      this.getLottieAnimMode().getIconViewData().initialSegment = [curFrame - 1, curFrame] as AnimationSegment;
      this.getLottieAnimMode().setLottieData(lottieData);
      this.getLottieAnimMode().needUpdateIconByAnim(true);
      this.getLottieAnimMode().setCurrentFrame(this.getCurrentFrame());
      return true;
    } else if (!DropDownAdapter.isDropDownShow()) {
      log.showInfo('clear resource, setLottieData null');
      this.getLottieAnimMode().setLottieData(null);
    }
    return false;
  }

  /**
   * CanvasReady回调
   */
  public onCanvasReady(): void {
    if (this.loadLottieData()) {
      this.getLottieAnimMode().onCanvasReady();
    }
  }

  /**
   * 更新当前真实音量值
   */
  public getPhysicsValue(): number {
    return VolumeController.getInstance().getVolume() as number;
  }

  /**
   * 最大音量值
   */
  public getMaxValue(): number {
    return VolumeController.getInstance().getMaxVolume() as number;
  }

  /**
   * 最小音量值
   */
  public getMinValue(): number {
    return VolumeController.getInstance().getMinVolume() as number;
  }

  /**
   * 将真实物理值写入数据库
   */
  public setPhysicsValue(continuous: boolean): void {
    VolumeController.getInstance().setVolume(this.physicsValue);
  }

  /**
   * 滑动条点击行为打点上报
   */
  public reportSliderClickEvent(): void {
    log.showInfo(`reportVolumeSlideEvent start:${this.startPhysicsValue}  to:${this.physicsValue}`)
    if (this.outputDevice !== undefined) {
      SoundReporterController.changeVoicePageVolumeReport(this.outputDevice.deviceType, this.outputDevice.address,
        this.physicsValue);
    }
  }

  /**
   * 滑动条滑动行为打点上报
   */
  public reportSliderSlideEvent(): void {
    log.showInfo(`reportVolumeSlideEvent start:${this.startPhysicsValue}  to:${this.physicsValue}`)
    if (this.outputDevice !== undefined) {
      SoundReporterController.changeVoicePageVolumeReport(this.outputDevice.deviceType, this.outputDevice.address,
        this.physicsValue);
    }
  }

  public onLongPressAction(event: GestureEvent, isHorizontal: boolean = true): void {
    super.onLongPressAction(event);
    soundSubPageController.showWindow(isHorizontal);
  }

  /**
   * 主动更新一次ui
   */
  private updateVolumeValue(): void {
    this.physicsValue = this.getPhysicsValue();
    this.getAnimData().uiValue = this.countUIValue();
    this.saveVolumeUIPercentage();
    log.showInfo(`updateVolumeValue ${this.physicsValue}  uiValue ${this.getAnimData().uiValue}`);
  }

  /**
   * 更新音量条图标
   */
  private updateVolumeIcon(needIconTransitionEffect: boolean): void {
    if (!needIconTransitionEffect) {
      this.getLottieAnimMode().getIconViewData().iconTransitionEffect = false;
      log.showInfo('iconTransitionEffect false')
    }
    log.showInfo(`updateVolumeIcon deviceType ${this.outputDevice?.deviceType}, currentVolumeType ${this.currentVolumeType}`);
    switch (this.currentVolumeType) {
      case audio.AudioVolumeType.RINGTONE:
        this.updateRingIcon();
        break;
      case audio.AudioVolumeType.ALARM:
        this.updateIconWithSymbol($r('sys.symbol.alarm_fill_1'));
        log.showInfo(`updateVolumeIcon use alarm icon`);
        break;
      case audio.AudioVolumeType.VOICE_CALL:
        AudioHelper.getInstance().isWirelessDevice(this.outputDevice?.deviceType) ?
        this.updateIconWithSymbol(
          IconMap.getFillEarphoneIcon(this.outputDevice?.address as string, this.outputDevice?.deviceType),
          SymbolRenderingStrategy.MULTIPLE_OPACITY) : this.updateIconWithSymbol($r('sys.symbol.phone_fill'));
        log.showInfo(`updateVolumeIcon use phone icon`);
        break;
      case audio.AudioVolumeType.MEDIA:
        this.updateMediaIcon();
        break;
      default:
        this.getAnimData().useLottieData = true;
        break;
    }
    if (!needIconTransitionEffect) {
      setTimeout(() => {
        this.getLottieAnimMode().getIconViewData().iconTransitionEffect = true;
        log.showInfo('iconTransitionEffect true')
      }, 100)
    }
  }

  /**
   * 更新媒体流图标
   * 规则:蓝牙设备和有线设备获取图片资源,其他默认lottie资源
   */
  private updateMediaIcon(): void {
    if (AudioHelper.getInstance().isWirelessDevice(this.outputDevice?.deviceType)) {
      this.updateIconWithSymbol(IconMap.getFillEarphoneIcon(
        this.outputDevice?.address as string, this.outputDevice?.deviceType),
        SymbolRenderingStrategy.MULTIPLE_OPACITY);
      log.showInfo(`updateMediaIcon use earphone icon`);
    } else if (AudioHelper.getInstance().isUsbHeadset(this.outputDevice?.deviceType)) {
      this.updateIconWithSymbol(IconMap.getUsbHeadsetIcon(), SymbolRenderingStrategy.MULTIPLE_OPACITY);
      log.showInfo(`updateMediaIcon use headset icon`);
    } else if (this.outputDevice?.deviceType === audio.DeviceType.NEARLINK) {
      this.updateIconWithSymbol(IconMap.getFillEarphoneIcon(
        this.outputDevice?.address as string, audio.DeviceType.NEARLINK),
        SymbolRenderingStrategy.MULTIPLE_OPACITY);
      log.showInfo('updateMediaIcon use NEARLINK icon');
    } else {
      log.showInfo(`updateMediaIcon use speaker lottie`);
      this.getAnimData().useLottieData = true;
    }
  }

  /**
   * 更新响铃图标
   * 规则:如果音量不为0则显示响铃图标,如果音量为0,需要判断是震动还是静音
   */
  private updateRingIcon(): void {
    if (this.getAnimData().uiValue > 0) {
      this.updateIconWithSymbol($r('sys.symbol.bell_fill'));
      log.showInfo(`updateRingIcon bell`)
    } else if (VolumeController.getInstance().ringMode === audio.AudioRingMode.RINGER_MODE_SILENT) {
      log.showInfo(`updateRingIcon slash`)
      this.updateIconWithSymbol($r('sys.symbol.bell_slash_fill'));
    } else {
      log.showInfo(`updateRingIcon vibrate`)
      this.updateIconWithImg($r('app.media.icon_volume_vibrate'));
    }
  }

  /**
   * 替换音量条图标-使用symbol
   *
   * @param sliderIcon 图标资源
   * @param symbolRendering  渲染策略
   */
  private updateIconWithSymbol(sliderIcon: Resource,
    symbolRendering: SymbolRenderingStrategy = SymbolRenderingStrategy.SINGLE): void {
    this.getAnimData().sliderIcon = sliderIcon;
    this.getAnimData().symbolRendering = symbolRendering;
    this.getAnimData().useSymbol = true;
    this.getAnimData().useLottieData = false;
    // 释放lottie资源
    this.getLottieAnimMode().onCanvasDisappear();
  }

  /**
   * 替换音量条图标-使用image
   * @param sliderIcon 图标资源
   */
  private updateIconWithImg(sliderIcon: Resource): void {
    this.getAnimData().sliderIcon = sliderIcon;
    this.getAnimData().useSymbol = false;
    this.getAnimData().useLottieData = false;
    // 释放lottie资源
    this.getLottieAnimMode().onCanvasDisappear();
  }

  /**
   * 开始拖动动效
   */
  public startDraggingAnimation(): void {
    super.startDraggingAnimation();
    TraceUtil.startTrace(DomainName.CC, Trace.CORE_METHOD_SLIDING_VOLUME);
  }

  /**
   * 滑动调整音量值,获取ui
   * @returns 点击对应的ui值
   */
  public getUIValueOfPanAction(): number {
    const sliderLength: number =
      this.getViewData().isHorizontal ? this.getViewData().sliderWidth : this.getViewData().sliderHeight;
    let uiValue = Math.min(Math.max(this.currentEndPosition, 0), sliderLength);
    if (this.currentVolumeType !== audio.AudioVolumeType.ALARM &&
      this.currentVolumeType !== audio.AudioVolumeType.VOICE_CALL) {
      return uiValue;
    }
    return Math.max(uiValue, this.canAdjustMinValue);
  }

  /**
   * 拖动结束动效后记录ui值
   */
  public endDraggingAnimation(): void {
    super.endDraggingAnimation();
    TraceUtil.endTrace(DomainName.CC, Trace.CORE_METHOD_SLIDING_VOLUME);
    this.saveVolumeUIPercentage();
    AccessibilityUtil.sendAccessibility(ResUtils.getInnerStringNumS($r('app.string.cc_accessibility_str_change_volume'),
      `${this.getAccessibilityPhysicsValue()}%}`));
  }

  /**
   * 点击开始
   */
  public onTapAction(event: GestureEvent): void {
    TraceUtil.startTrace(DomainName.CC, Trace.CORE_METHOD_TAP_VOLUME);
    super.onTapAction(event);
  }


  /**
   * 点击调整音量值,获取ui
   * @param event
   * @returns
   */
  getUIValueOfTapAction(event: GestureEvent): number {
    let uiValue: number = 0;
    if (this.getViewData().isHorizontal) {
      uiValue =
        RTLUtil.isRTL() ? this.getViewData().sliderWidth - event.fingerList[0].localX : event.fingerList[0].localX;
    } else {
      uiValue = this.getViewData().sliderHeight - event.fingerList[0].localY;
    }
    if (this.currentVolumeType !== audio.AudioVolumeType.ALARM &&
      this.currentVolumeType !== audio.AudioVolumeType.VOICE_CALL) {
      return uiValue;
    }
    return Math.max(uiValue, this.canAdjustMinValue);
  }

  /**
   * 点击进度值播放动画
   */
  public refreshIcon() {
    this.refreshIconWithAnim();
  }

  /**
   * 拖动进度值播放动画
   */
  public playCurrentFrame(currentEndPosition: number): void {
    this.refreshIconWithAnim();
  }

  /**
   * 刷新icon,根据音量值变化播放指定段的动效
   */
  public refreshIconWithAnim() {
    let frameSegments: number[] = this.getFrameSegments();
    if (frameSegments === undefined || frameSegments.length === 0) {
      return;
    }
    this.getLottieAnimMode().refreshIconAnim(frameSegments);
  }

  /**
   * 音量变化获取对应的音量等级区间,相同区间内不需要动画过过渡
   * @returns
   */
  private getFrameSegments(): number[] {
    log.showInfo(`volume value: ${this.physicsValue}`);
    let frameSegments: number[] = [];
    let currentValueLevel = this.getVolumeValueLevel(this.physicsValue);
    if (currentValueLevel === this.preVolumeValueLevel) {
      log.showInfo(`volume level not change ${currentValueLevel}`);
      return frameSegments;
    }
    if (currentValueLevel > this.preVolumeValueLevel) {
      frameSegments = this.mediaLottieKeyFrames[currentValueLevel - 1];
    } else {
      frameSegments = this.mediaLottieKeyFrames[currentValueLevel].slice().reverse();
    }
    this.preVolumeValueLevel = currentValueLevel;
    log.showInfo(`frameSegments :${frameSegments}`);
    return frameSegments;
  }

  /**
   * 根据音量等级变化,获取播放动画区间帧
   * @param currentValueLevel
   * @returns
   */
  getFrameSegmentsByLevel(currentValueLevel: number): number[] {
    if (currentValueLevel > this.preVolumeValueLevel) {
      return this.mediaLottieKeyFrames[currentValueLevel - 1];
    } else {
      return Array.from(this.mediaLottieKeyFrames[this.preVolumeValueLevel]).reverse();
    }
  }

  /**
   * 将音量值分为4个区间
   * [0,0]、[1,5]、[6,10]、[11,15]
   * @param value
   * @returns 对应的区间等级
   */
  private getVolumeValueLevel(value: number): number {
    if (value > this.volumeLevelTwo) {
      return this.speakerWaveThree;
    } else if (value > this.volumeLevelOne) {
      return this.speakerWaveTwo;
    } else if (value > 0) {
      return this.speakerWaveOne;
    }
    return this.speakerWaveZero;
  }

  /**
   * 获取当前音量值对应的动效帧
   * @returns
   */
  private getCurrentFrame(): number {
    if (this.physicsValue > this.volumeLevelTwo) {
      this.preVolumeValueLevel = this.speakerWaveThree;
      return this.mediaLottieKeyFrames[2][1];
    } else if (this.physicsValue > this.volumeLevelOne) {
      this.preVolumeValueLevel = this.speakerWaveTwo;
      return this.mediaLottieKeyFrames[1][1];
    } else if (this.physicsValue > 0) {
      this.preVolumeValueLevel = this.speakerWaveOne;
      return this.mediaLottieKeyFrames[0][1];
    }
    this.preVolumeValueLevel = this.speakerWaveZero;
    return this.mediaLottieKeyFrames[0][0];
  }

  /**
   * 点击动效结束后记录ui值
   */
  public onTapActionEnd(): void {
    TraceUtil.endTrace(DomainName.CC, Trace.CORE_METHOD_TAP_VOLUME);
    this.saveVolumeUIPercentage();
  }

  private saveVolumeUIPercentage(): void {
    const sliderLength: number =
      this.getViewData().isHorizontal ? this.getViewData().sliderWidth : this.getViewData().sliderHeight;
    if (sliderLength !== 0) {
      VolumeController.getInstance().setVolumePercentage(this.getAnimData().uiValue / sliderLength);
      log.showInfo(`subpage savePercentageOfUI: ${VolumeController.getInstance().getVolumePercentage()}`);
    }
  }
}