/*
 * Copyright (c) 2026 Huawei Device Co., Ltd.
 * 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 type { common, Want } from '@kit.AbilityKit';
import { wantAgent } from '@kit.AbilityKit';
import { backgroundTaskManager } from '@kit.BackgroundTasksKit';
import Logger from '../utils/Logger';

const TAG = '[ContinueTaskController]';

function callbackAuth(authResult: backgroundTaskManager.UserAuthResult): void {
  Logger.info(TAG, `Operation requestAuthFromUser success. auth result: ${JSON.stringify(authResult)}`);
}

export class ContinueTaskController {
  private continuousTaskId?: number = -1;
  private context?: common.UIAbilityContext = undefined;
  private wantAgentCache?: Want = undefined;
  private static instance: ContinueTaskController;

  constructor(context: common.UIAbilityContext) {
    this.context = context;
  }

  public static getInstance(context: common.UIAbilityContext): ContinueTaskController {
    if (!ContinueTaskController.instance) {
      ContinueTaskController.instance = new ContinueTaskController(context);
    }
    return ContinueTaskController.instance;
  }

  // [Start task_get_task]
  private static getTask(): backgroundTaskManager.ContinuousTaskRequest {
    let continuousTaskRequest = new backgroundTaskManager.ContinuousTaskRequest();
    let modeList: number[] = [backgroundTaskManager.BackgroundTaskMode.MODE_SPECIAL_SCENARIO_PROCESSING];
    continuousTaskRequest.backgroundTaskModes = modeList;
    let subModeList: number[] =
      [backgroundTaskManager.BackgroundTaskSubmode.SUBMODE_MEDIA_PROCESS_NORMAL_NOTIFICATION];
    continuousTaskRequest.backgroundTaskSubmodes = subModeList;
    return continuousTaskRequest;
  }
  // [End task_get_task]

  public requestPermit(callback: (authResult: backgroundTaskManager.UserAuthResult) => void = callbackAuth): void {
    let continuousTaskRequest = ContinueTaskController.getTask();
    try {
      continuousTaskRequest.requestAuthFromUser(this.context, callback);
      Logger.info(TAG, `Operation requestAuthFromUser success.`);
    } catch (error) {
      Logger.error(TAG, `Operation requestAUthFromUser failed, code is ${error.code}, message is ${error.message}`);
    }
  }

  public checkSpecialScenarioAuth(): Promise<backgroundTaskManager.UserAuthResult> {
    return new Promise((resolve) => {
      let continuousTaskRequest = ContinueTaskController.getTask();
      continuousTaskRequest.checkSpecialScenarioAuth(this.context)
        .then((authResult: backgroundTaskManager.UserAuthResult) => {
          Logger.info(TAG, `Operation checkSpecialScenarioAuth success. result is ${authResult}`);
          resolve(authResult);
        })
        .catch((error: BusinessError) => {
          resolve(backgroundTaskManager.UserAuthResult.NOT_DETERMINED);
          Logger.error(TAG, `Operation checkSpecialScenarioAuth error, code is ${error.code},
           message is ${error.message}`);
        });
    });
  }

  private async buildWantAgent(): Promise<Want | undefined> {
    if (!this.context) {
      Logger.error(TAG, `invalid context`);
      return undefined;
    }
    let wantAgentInfo: wantAgent.WantAgentInfo = {
      wants: [
        {
          bundleName: this.context.abilityInfo.bundleName,
          abilityName: 'EntryAbility'
        }
      ],
      actionType: wantAgent.OperationType.START_ABILITY,
      requestCode: 0,
      wantAgentFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
    };
    try {
      this.wantAgentCache = await wantAgent.getWantAgent(wantAgentInfo);
      return this.wantAgentCache;
    } catch (e) {
      Logger.error(TAG,
        `getWantAgent error, code is ${e.code}, message is ${e.message}`);
      return undefined;
    }
  }

  // [Start task_start]
  public isRunning(): boolean {
    // Prevent duplicate start of background continuous task
    return this.continuousTaskId !== undefined && this.continuousTaskId > 0;
  }

  public async start(): Promise<void> {
    if (this.isRunning()) {
      Logger.warn(TAG, `continuous task already running, id=${this.continuousTaskId}`);
      return;
    }
    if (!this.context) {
      Logger.error(TAG, `invalid context`);
      return;
    }
    try {
      let wantAgentObj = this.wantAgentCache ?? await this.buildWantAgent();
      if (!wantAgentObj) {
        Logger.error(TAG, `wantAgent is undefined`);
        return;
      }
      // Build continuousTaskRequest object
      let continuousTaskRequest: backgroundTaskManager.ContinuousTaskRequest = ContinueTaskController.getTask();
      if (continuousTaskRequest === undefined) {
        Logger.info(TAG, `continuousTaskRequest is undefined`);
        return;
      }
      continuousTaskRequest.wantAgent = wantAgentObj;
      continuousTaskRequest.combinedTaskNotification = false;
      continuousTaskRequest.continuousTaskId = -1;

      let res: backgroundTaskManager.ContinuousTaskNotification =
        await backgroundTaskManager.startBackgroundRunning(this.context, continuousTaskRequest);
      Logger.info(TAG,
        `Operation startBackgroundRunning succeeded.
         notificationId=${res.notificationId} continuousTaskId=${res.continuousTaskId}`);
      this.continuousTaskId = res.continuousTaskId;
    } catch (error) {
      Logger.error(TAG, `Operation startBackgroundRunning failed, code is ${error.code}, message is ${error.message}`);
    }

  }
  // [End task_start]

  public async stop(): Promise<void> {
    try {
      await backgroundTaskManager.stopBackgroundRunning(this.context, this.continuousTaskId);
      this.continuousTaskId = -1;
      Logger.info(TAG, `Operation stopBackgroundRunnning succ`);
    } catch (error) {
      Logger.error(TAG, `Operation stopBackgroundRunnning failed, code is ${error.code}, message is ${error.message}`);
    }
  }
}