/*
 * 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 { EvtBus, ScreenLockEvent } from '@ohos/frameworkwrapper';
import { AbstractObserverManager } from '../base/AbstractObserverManager';
import { SCBSceneSessionManager } from '@ohos/windowscene/src/main/ets/TsIndex';
import { ScreenLockStatus } from '../interface/ScreenOnOffMediator';
import { AuthState, LockEventType, SlServerHelper } from '../utils/SlServerHelper';
import { AccountHelper, AuthType } from '../utils/AccountHelper';
import { VerifyDataManager, VerifyDataChangeListener, VerifyInfo} from './VerifyDataManager';
import { VerifyStateListener, ScreenLockVerifyService } from '../services/ScreenLockVerifyService';
import { ScreenLockUnlockService } from '../services/ScreenLockUnLockService';
import { SystemSwitchUtils } from '../utils/SystemSwitchUtils';

const TAG = 'ScreenLockStateManager';
const log: LogHelper = LogHelper.getLogHelper(LogDomain.KG, TAG);

/**
 * 页面状态
 */
export enum PageState {
  /**
   * 未初始化
   */
  NONE = 0,

  /**
   * 显示
   */
  SHOW = 1,

  /**
   * 隐藏
   */
  HIDE = 2,
}

/**
 * 锁定状态
 */
export enum LockState {
  /**
   * 未初始化
   */
  NONE = 0,

  /**
   * 锁定
   */
  LOCKED = 1,

  /**
   * 已解锁
   */
  UNLOCKED = 2,
}

/**
 * 锁定状态信息
 */
export class LockStateInfo {
  /**
   * 页面状态
   */
  private _pageState: PageState = PageState.NONE;

  /**
   * 锁定状态
   */
  private _lockState: LockState = LockState.NONE;

  public get pageState(): PageState {
    return this._pageState;
  }

  protected set pageState(pageState: PageState) {
    this._pageState = pageState;
  }

  public get lockState(): LockState {
    return this._lockState;
  }

  protected set lockState(lockState: LockState) {
    this._lockState = lockState;
  }

  public get isPageShow(): boolean {
    return this._pageState === PageState.SHOW;
  }

  public get isLocked(): boolean {
    return this._lockState === LockState.LOCKED;
  }

  public toString(): string {
    return `<PageState: ${PageState[this._pageState]}, LockState: ${LockState[this._lockState]}>`;
  }
}

/**
 * 锁定状态信息
 */
class InnerLockStateInfo extends LockStateInfo {
  public get pageState(): PageState {
    return super.pageState;
  }

  public set pageState(pageState: PageState) {
    super.pageState = pageState;
  }

  public get lockState(): LockState {
    return super.lockState;
  }

  public set lockState(lockState: LockState) {
    super.lockState = lockState;
  }
}

/**
 * 状态信息
 */
export interface StateInfo {
  /**
   * 页面状态
   */
  pageState?: PageState;

  /**
   * 锁定状态
   */
  lockState?: LockState;

  /**
   * 是否在密码页
   */
  isInBouncer?: boolean;

  /**
   * 是否在编辑态
   */
  isInEdite?: boolean;
}

/**
 * 锁定状态变化监听器
 */
export interface ScreenLockStateChangeListener {
  /**
   * 变更函数
   *
   * @param lockStateInfo 锁定状态信息
   */
  onLockStateChange?: (lockStateInfo: LockStateInfo) => void;
}

/**
 * 锁屏状态管理器(注:这里必须有一个清晰的认识,锁屏状态本质是界面状态,状态的更新应该依赖于界面状态机)
 * 仅供锁屏内部模块使用
 */
export class ScreenLockStateManager extends AbstractObserverManager<ScreenLockStateChangeListener> {
  private static sInstance: ScreenLockStateManager;

  public static getInstance(): ScreenLockStateManager {
    if (ScreenLockStateManager.sInstance == null) {
      ScreenLockStateManager.sInstance = new ScreenLockStateManager();
    }
    return ScreenLockStateManager.sInstance;
  }

  private _lockStateInfo: InnerLockStateInfo;
  private _screenLockEvent: ScreenLockEvent = new ScreenLockEvent();

  private _hasBeenUnlocked: boolean = false; // 是否解锁过
  private _isInBouncer: boolean = false; // 是否在密码页
  private _isInEdite: boolean = false; // 是否在编辑态
  private _hasNoPwd: boolean = false; // 是否有设置密码
  private _isDeviceLocked: boolean = true; // 锁头状态,跟随onResult

  private constructor() {
    super();
    this._lockStateInfo = new InnerLockStateInfo();
    if (!SystemSwitchUtils.isUseNewScreenLock()) {
      log.showError('not support');
      return;
    }
    this.updateScreenLockState();
  }

  public get lockStateInfo(): LockStateInfo {
    return this._lockStateInfo;
  }

  public get isPageShow(): boolean {
    return this._lockStateInfo.isPageShow;
  }

  public get isLocked(): boolean {
    return this._lockStateInfo.isLocked;
  }

  public get isInBouncer(): boolean {
    return this._isInBouncer;
  }

  public get isInEdite(): boolean {
    return this._isInEdite;
  }

  public get isDeviceLocked(): boolean {
    return this._isDeviceLocked;
  }

  /**
   * 更新状态
   *
   * @param newStateInfo 新状态
   */
  public updateStateInfo(newStateInfo: StateInfo): void {
    if (newStateInfo.isInBouncer !== undefined && newStateInfo.isInBouncer !== this._isInBouncer) {
      this._isInBouncer = newStateInfo.isInBouncer;
    }
    if (newStateInfo.isInEdite !== undefined && newStateInfo.isInEdite !== this._isInEdite) {
      this._isInEdite = newStateInfo.isInEdite;
    }
    if ((newStateInfo.pageState && newStateInfo.pageState !== this._lockStateInfo.pageState) ||
      (newStateInfo.lockState && newStateInfo.lockState !== this._lockStateInfo.lockState)) {
      let oldState: string = this._lockStateInfo.toString();
      this._lockStateInfo.pageState = newStateInfo.pageState ?? this._lockStateInfo.pageState;
      this._lockStateInfo.lockState = newStateInfo.lockState ?? this._lockStateInfo.lockState;
      log.showWarn(`updateStateInfo oldState: ${oldState}, newState: ${this._lockStateInfo.toString()}`);
      const isUnLocked: boolean = this._lockStateInfo.lockState === LockState.UNLOCKED;
      SCBSceneSessionManager.getInstance().setUserAuthPassed(isUnLocked);
      this.broadcastDataChange(callback => callback.onLockStateChange?.(this._lockStateInfo));
      this.updateScreenLockState(true);
    }
  }

  /**
   * 更新锁头状态
   *
   * @param lockState 新状态
   * @param authType 认证类型
   */
  public updateLockAuthState(lockState: LockState, authType?: AuthType): void {
    if (this._hasNoPwd || SlServerHelper.getInstance().isScreenLockDisabled()) {
      return;
    }

    let oldAuthState = SlServerHelper.getInstance().getScreenLockAuthState();
    if (!this._hasBeenUnlocked && SlServerHelper.getInstance().isPreVerifyState(oldAuthState) &&
      authType === undefined) {
      // 隐私空间冷切首次进锁屏不修改预认证值
      log.showInfo('private space cold swith, no need to setAuthState null');
      return;
    }

    if (lockState === LockState.UNLOCKED && authType !== undefined) {
      this.updateDeviceLockState(authType);
    }

    if (lockState === LockState.LOCKED) {
      this.fileEncryptionStateChange();
    }
  }

  /**
   * 文件加密状态变更
   */
  public fileEncryptionStateChange(): void {
    if (!VerifyDataManager.getInstance().hasNoPwd) {
      // 文件加密
      AccountHelper.getInstance().fileEncryption();
      // 锁头状态变化
      this.updateDeviceLockState(null);
    }
    // onResult标记位重置
    ScreenLockUnlockService.getInstance().hasReceiveResult = false;
  }

  /**
   *  锁头状态变化
   */
  public updateDeviceLockState(authType: AuthType | null): void {
    this._isDeviceLocked = !authType;
    SlServerHelper.getInstance().setScreenLockAuthState(authType);
  }

  /**
   * 发布锁屏事件
   */
  public publishScreenLockEvent(): void {
    this.postScreenLockEvent();
  }

  protected doInit(): void {
    log.showInfo('doInit');
    // 注册锁屏状态事件生产者
    EvtBus.produceOn(ScreenLockEvent, this.onProduceScreenLockEvent.bind(this));
    // 监听密码变化
    VerifyDataManager.getInstance().registerObserver(this._verifyDataListener);
    // 监听认证结果
    ScreenLockVerifyService.getInstance().registerObserver(this._verifyResultListener);
  }

  protected doRelease(): void {
    log.showInfo('doRelease');
    // 注销锁屏状态事件生产者
    EvtBus.produceOff(ScreenLockEvent, this.onProduceScreenLockEvent.bind(this));
    // 注销密码变化
    VerifyDataManager.getInstance().unRegisterObserver(this._verifyDataListener);
    // 注销监听认证结果
    ScreenLockVerifyService.getInstance().unRegisterObserver(this._verifyResultListener);
  }

  private onProduceScreenLockEvent(): ScreenLockEvent {
    return this._screenLockEvent;
  }

  private updateScreenLockState(isNeedBroadcast: boolean = false): void {
    if (this._lockStateInfo.pageState === PageState.HIDE) {
      this._screenLockEvent.isLockScreen = false;
      AppStorage.setOrCreate('lockStatus', ScreenLockStatus.UNLOCK);
    } else {
      this._screenLockEvent.isLockScreen = true;
      AppStorage.setOrCreate('lockStatus', ScreenLockStatus.LOCKING);
    }
    if (this._lockStateInfo.lockState === LockState.UNLOCKED) {
      this._screenLockEvent.lockStatus = ScreenLockEvent.LOCK_STATUS_UNLOCK;
      this._hasBeenUnlocked = true;
    } else {
      this._screenLockEvent.lockStatus = ScreenLockEvent.LOCK_STATUS_SECURE;
    }
    // 发送事件
    if (isNeedBroadcast) {
      this.postScreenLockEvent();
    }
  }

  private postScreenLockEvent(): void {
    EvtBus.post(ScreenLockEvent, this._screenLockEvent);
  }

  private readonly _verifyDataListener : VerifyDataChangeListener = {
    onVerifyInfoChange: (authType: AuthType, verifyInfo: VerifyInfo) => {
      if (authType !== AuthType.PIN || VerifyDataManager.getInstance().hasNoPwd === this._hasNoPwd) {
        return;
      }
      if (VerifyDataManager.getInstance().hasNoPwd) {
        // 监听首次无密码,设为PIN解锁
        this.updateDeviceLockState(AuthType.PIN);
        this._hasNoPwd = true;
      } else {
        this._hasNoPwd = false;
      }
    }
  };

  private readonly _verifyResultListener: VerifyStateListener = {
    onAuthSuccessResult: (authType: AuthType): void => {
      if (this._lockStateInfo.pageState === PageState.HIDE && !ScreenLockUnlockService.getInstance().hasReceiveResult) {
        // 锁屏退出且首次onResult执行
        log.showInfo('send unlock screenlockEvent after receive onResult');
        SlServerHelper.getInstance().sendScreenLockEvent(LockEventType.UNLOCK_SCREEN_RESULT);
      }
      if (this._lockStateInfo.lockState !== LockState.LOCKED) {
        this.updateDeviceLockState(authType);
      }
      ScreenLockUnlockService.getInstance().hasReceiveResult = true;
    }
  };
}