/*
 * 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 sceneSessionManager from '@ohos.sceneSessionManager';
import { LogHelper, LogDomain } from '@ohos/basicutils';
import {
  SCBScreenProperty,
  SCBSceneInfo,
  SCBSceneSession,
  SCBSceneSessionManager,
  SCBEventId,
  SCBSceneSessionArray
} from '@ohos/windowscene';
import { CastScene } from './CastScene';
import screen from '@ohos.screen';
import { StyleConstants } from '@ohos/launchercommon/src/main/ets/constants/StyleConstants';
import { bundleManager } from '@kit.AbilityKit';

const log: LogHelper = LogHelper.getLogHelper(LogDomain.WINDOW, 'CastScenePanel');

@Component
export struct CastScenePanel {
  @State scbSceneSessionArray: SCBSceneSessionArray = new SCBSceneSessionArray();
  @Link screenProperty: SCBScreenProperty; // current screen property;
  private onStartSceneFromIcon = (sceneInfo: SCBSceneInfo): void => {
    log.info(`onStartSceneFromIcon sceneInfo: ${sceneInfo.bundleName}`);
    for (let i = this.scbSceneSessionArray.length - 1; i >= 0; i--) {
      if (sceneInfo.persistentId === this.scbSceneSessionArray[i].sceneInfo.persistentId) {
        log.info(`update sceneInfo: ${sceneInfo.persistentId}`);
        continue;
      }
      const launchType = this.findLaunchType(this.scbSceneSessionArray[i].sceneInfo);
      if (launchType === bundleManager.LaunchType.SINGLETON) {
        this.sessionBackground(this.scbSceneSessionArray[i]);
      } else {
        log.info(`terminateSession: ${launchType}`);
        this.terminateSessionByPersistentId(this.scbSceneSessionArray[i].sceneInfo.persistentId);
      }
    }
    let oldSession = this.findSceneSessionByPersistentId(sceneInfo.persistentId);
    if (oldSession) {
      log.info('onStartSceneFromIcon found session');
      oldSession.updateSceneInfo(sceneInfo);
      this.sessionActive(oldSession, false);
      return;
    }
    let sceneSession: sceneSessionManager.SceneSession = this.createSceneSession(sceneInfo);
    if (!sceneSession) {
      log.warn('Failed to request scene session!');
      return;
    }
    let scbSceneSession = new SCBSceneSession(sceneSession, sceneInfo);
    this.sessionActive(scbSceneSession);
    this.scbSceneSessionArray.push(scbSceneSession);
  }

  private findLaunchType(sceneInfo: SCBSceneInfo): bundleManager.LaunchType {
    const queryKey = `${sceneInfo.bundleName}${sceneInfo.moduleName}${sceneInfo.abilityName}`;
    return SCBSceneSessionManager.getInstance().getAbilityLaunchType(queryKey);
  }

  private findSceneSessionIndexByPersistentId(persistentId?: number): number {
    if (!persistentId) {
      return -1;
    }
    let index = this.scbSceneSessionArray.findIndex((value: SCBSceneSession) => {
      if (value.session.persistentId && value.session.persistentId === persistentId) {
        return true;
      }
      return false;
    });
    return index;
  }

  private findSceneSessionByPersistentId(persistentId?: number): SCBSceneSession | undefined {
    let index = this.findSceneSessionIndexByPersistentId(persistentId);
    if (index >= 0) {
      return this.scbSceneSessionArray[index];
    }
    return undefined;
  }

  private sessionBackground(session: SCBSceneSession) {
    session.visibility = false;
    session.requestSessionBackground();
  }

  private sessionActive(session: SCBSceneSession, isNewActive?: boolean) {
    session.visibility = true;
    session.requestSessionActivation(isNewActive);
  }

  private createSceneSession(sceneInfo: SCBSceneInfo): sceneSessionManager.SceneSession {
    let sceneSession: sceneSessionManager.SceneSession = sceneSessionManager.requestSceneSession({
      bundleName: sceneInfo.bundleName,
      moduleName: sceneInfo.moduleName,
      abilityName: sceneInfo.abilityName,
      appIndex: sceneInfo.appIndex,
      persistentId: sceneInfo.persistentId,
      screenId: sceneInfo.screenId
    }, sceneInfo.want);
    return sceneSession;
  }

  private terminateSessionByPersistentId(persistentId?: number): void {
    let index = this.findSceneSessionIndexByPersistentId(persistentId);
    log.info(`TerminateScene ${index} ${persistentId}`);
    if (index >= 0) {
      this.scbSceneSessionArray[index]?.requestSessionDestruction(true);
      this.scbSceneSessionArray.splice(index, 1);
    }
  }

  private onTerminateScene = (persistentId?: number, containerId?: number): void => {
    log.info(`onTerminateScene persistentId: ${persistentId}`);
    this.terminateSessionByPersistentId(persistentId);
    if (this.scbSceneSessionArray.length > 0) {
      let activeIndex = this.scbSceneSessionArray.findIndex((value: SCBSceneSession) => {
        if (value.isActive && value.visibility) {
          return true;
        }
        return false;
      });
      if (activeIndex < 0) {
        this.sessionActive(this.scbSceneSessionArray[this.scbSceneSessionArray.length - 1], false);
      }
    } else {
      screen.makeMirror(0, [this.screenProperty.screenId]).then(() => {
        log.info(`MakeMirror current window count: ${this.scbSceneSessionArray.length}`);
      });
    }
  }

  private registerCallback(): void {
    SCBSceneSessionManager.getInstance()
      .registerVirtualScreenStartScene(this.onStartSceneFromIcon, this.screenProperty.screenId);
  }

  private registerSessionEvent(): void {
    SCBSceneSessionManager.getInstance().on(SCBEventId.TERMINATE_SCENE, this.screenProperty.screenId,
      this.onTerminateScene);
  }

  private unRegisterSessionEvent(): void {
    SCBSceneSessionManager.getInstance().off(SCBEventId.TERMINATE_SCENE, this.screenProperty.screenId,
      this.onTerminateScene);
  }

  aboutToAppear() {
    log.info(`aboutToAppear screenId: ${this.screenProperty.screenId}`);
    this.registerCallback();
    this.registerSessionEvent();
    SCBSceneSessionManager.getInstance().runCastTaskIfNeed();
  }

  aboutToDisappear(): void {
    log.info('aboutToDisappear onTerminateScene');
    this.scbSceneSessionArray.forEach((session: SCBSceneSession) => {
      log.info(`onTerminateScene for ${session.session.persistentId}`);
      session.requestSessionDestruction(true);
    });
    this.scbSceneSessionArray.splice(0);
    SCBSceneSessionManager.getInstance()
      .unregisterVirtualScreenStartScene(this.screenProperty.screenId);
    this.unRegisterSessionEvent();
  }

  build() {
    Stack({ alignContent: Alignment.TopStart }) {
      ForEach(this.scbSceneSessionArray, (scbSceneSession: SCBSceneSession) => {
        CastScene({
          sceneSession: scbSceneSession
        })
      }, (scbSceneSession: SCBSceneSession) => `cast_engine_session_${scbSceneSession.session.persistentId}`)
    }
    .backgroundColor('sys.color.ohos_id_color_background')
    .width(StyleConstants.PERCENTAGE_100)
    .height(StyleConstants.PERCENTAGE_100)
    .hitTestBehavior(HitTestMode.None)
  }
}