/*
 * Copyright (c) Huawei Technologies 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 { policy } from '@kit.NetworkKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { call } from '@kit.TelephonyKit';
import { PushParam } from '@ohos/settings.common/src/main/ets/core/controller/Controller';
import { EventBus } from '@ohos/settings.common/src/main/ets/framework/common/EventBus';
import { DynamicDataSource } from '@ohos/settings.common/src/main/ets/framework/model/DynamicDataSource';
import {
  CompCtrlParam,
  ComponentControl
} from '@ohos/settings.common/src/main/ets/framework/model/SettingBaseModel';
import { ItemDetailType,
  ItemResultType,
  ItemType,
  SettingItemModel } from '@ohos/settings.common/src/main/ets/framework/model/SettingItemModel';
import { NavEntryKey } from '@ohos/settings.common/src/main/ets/utils/Consts';
import { LogUtil } from '@ohos/settings.common/src/main/ets/utils/LogUtil';
import { CheckEmptyUtils } from '@ohos/settings.common/src/main/ets/utils/CheckEmptyUtils';
import { PageRouter } from '@ohos/settings.common/src/main/ets/framework/common/PageRouter';
import { DeviceUtil } from '@ohos/settings.common/src/main/ets/utils/BaseUtils';
import { notifyCompStateChange,
  SettingBaseState,
  SettingCompState,
  SettingResultState,
  SettingStateType } from '@ohos/settings.common/src/main/ets/framework/model/SettingStateModel';
import { AppDataModel, SettingAppGroupModel } from '../model/SettingAppItemModel';
import { AppEntry } from '../AppModel';

const TAG = 'AppNetworkController';
const ATOMIC_SERVICE: number = 1;

export class AppNetworkController implements ComponentControl {
  private compId: string = '';
  private dataSource: DynamicDataSource = new DynamicDataSource();
  private entry: AppEntry | null = null;
  private networkingState: ResourceStr = '';

  private refreshData = (entry: AppEntry) => {
    /* instrument ignore if*/
    if (!entry) {
      LogUtil.error(`${TAG} appEntry is invalid`);
      return;
    }
    LogUtil.info(`${TAG} receive app change: ${entry.name}`);
    this.entry = entry;
    this.initNetwork();
  }

  private refreshState = () => {
    LogUtil.info(`${TAG} refreshState`);
    this.setAppNetworkingMenu();
  }

  init(compParam: CompCtrlParam): void {
    LogUtil.showInfo(TAG, `onInit`);
    /* instrument ignore if*/
    if (!compParam || !compParam.compId || DeviceUtil.isDevicePc()) {
      LogUtil.error(`${TAG} init fail, compParam is invalid or is pc`);
      return;
    }
    this.compId = compParam.compId;
    this.dataSource = compParam.dataSource as DynamicDataSource;
    let appItem: SettingAppGroupModel = compParam.component as SettingAppGroupModel;
    this.entry = appItem.entry as AppEntry;
    if (this.entry) {
      this.refreshData(this.entry);
    }
    EventBus.getInstance().on('EVENT_ID_APP_DETAIL_PAGE_SHOW', this.refreshState);
  }

  destroy(): void {
    LogUtil.showInfo(TAG, 'onDestroy');
    EventBus.getInstance().detach('EVENT_ID_APP_DETAIL_PAGE_SHOW', this.refreshState);
  }

  private async initNetwork(): Promise<void> {
    /* instrument ignore if*/
    if (!this.entry) {
      LogUtil.error(`${TAG} entry invalid`);
      return;
    }
    let isSystemApp: boolean | undefined = this.entry?.appInfo?.systemApp;
    let isAtomicService: boolean = this.entry?.appInfo?.bundleType === ATOMIC_SERVICE;
    LogUtil.info(`${TAG} entry application_networking_entry: ${isSystemApp} ${isAtomicService}`);
    // 非系统应用,非元服务才展示应用联网入口
    let isEntryVisible: boolean = !isSystemApp && !isAtomicService;
    this.setVisible(isEntryVisible);
    if (isEntryVisible) {
      this.setAppNetworkingMenu();
      this.dataSource.splice(0, this.dataSource.length);
      LogUtil.info(`${TAG} entry application_networking_entry: ${this.entry?.name}`);
      this.dataSource.pushData(this.createItem(() => {
        LogUtil.info(`${TAG} entry application_networking_entry: ${this.entry?.name}`);
        PageRouter.push(NavEntryKey.APPLICATION_NETWORKING_ENTRY, this.parsePushParam());
      }));
    }
  }

  private parsePushParam(): PushParam {
    let pushParam: PushParam = new PushParam();
    pushParam.config = {
      bundleName: this.entry?.name,
      uid: this.entry?.appInfo?.uid,
    } as AppDataModel;
    pushParam.bundleName = this.entry?.name;
    return pushParam;
  }

  private setAppNetworkingMenu(): void {
    let uid: number | undefined = this.entry?.appInfo?.uid;
    if (CheckEmptyUtils.isEmpty(uid)) {
      LogUtil.error(`${TAG} uid is empty or undefined.`);
      return;
    }
    try {
      policy.getNetworkAccessPolicy(uid).then((data: policy.NetworkAccessPolicy) => {
        LogUtil.info(`${TAG} getNetworkAccessPolicy for ${this.entry?.name} success`);
        let isMobileDataAvailable: boolean = call.hasVoiceCapability();
        let wifiAccess = data.allowWiFi as boolean;
        let cellularAccess = data.allowCellular as boolean;
        if (wifiAccess && !cellularAccess) {
          this.networkingState = $r('app.string.app_networking_wlan_only');
        } else if (!wifiAccess && cellularAccess) {
          this.networkingState = isMobileDataAvailable ? $r('app.string.app_networking_cellular_only') : ' ';
        } else if (wifiAccess && cellularAccess) {
          this.networkingState = isMobileDataAvailable ? $r('app.string.app_networking_wlan_and_cellular') : $r('app.string.app_networking_wlan_only');
        } else {
          this.networkingState = ' ';
        }
        notifyCompStateChange('Setting.AppDetail.AppNetworkGroup.AppNetwork',
          new Map<SettingStateType, SettingResultState>([[SettingStateType.STATE_TYPE_ITEM_RESULT,
            {
              type: ItemResultType.RESULT_TYPE_TEXT,
              result: { content: this.networkingState
            } } as SettingResultState]]));
      })
        .catch((err: BusinessError) => {
          LogUtil.error(`${TAG} getNetworkAccessPolicy failed. ${err?.code} ${err?.message}`);
        });
    } catch (error) {
      LogUtil.error(`${TAG} failed to get networking policy, because: ${error?.code} ${error?.message}`);
    }
  }

  private createItem(onItemClick: () => void): SettingItemModel {
    LogUtil.info(`${TAG} createItem for ${this.entry?.name} ${this.networkingState}`);
    return {
      id: 'AppNetwork',
      type: ItemType.ITEM_TYPE_STANDARD,
      title: { content: $r('app.string.app_info_networking') },
      result: {
        type: ItemResultType.RESULT_TYPE_TEXT,
        result: {
          content: this.networkingState,
        }
      },
      detail: {
        type: ItemDetailType.DETAIL_TYPE_CUSTOM,
        icon: $r('sys.symbol.chevron_right'),
        isSymbolIcon: true,
        onItemClick: () => {
          onItemClick();
        }
      }
    }
  }

  private setVisible(isShow: boolean) {
    notifyCompStateChange('Setting.AppDetail.AppNetworkGroup',
      new Map<SettingStateType, SettingBaseState>([[SettingStateType.STATE_TYPE_GROUP_VISIBLE, {
        state: isShow
      } as SettingCompState]]));
  }
}