/*
 * 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 { ArrayUtils, CheckEmptyUtils, LogDomain, LogHelper } from '@ohos/basicutils';
import { GlobalContext } from '@ohos/frameworkwrapper';
import { AppItemInfo, DesktopUtils, EditModeConstants } from '../../TsIndex';
import ServiceExtensionContext from 'application/ServiceExtensionContext';
import { SmallFoldStyleUtil } from '../../utils/SmallFoldStyleUtil';
import { launcherStatusUtil } from '@ohos/windowscene/src/main/ets/TsIndex';
import lazy { OuterIconCenterViewModel } from '../viewmodel/OutIconCenterViewModel';
import { LazyDataSource } from '../../uicomponents/LazyDataSource';

const TAG = 'EditSearchComponentData';
const log: LogHelper = LogHelper.getLogHelper(LogDomain.HOME, TAG);
const CAMERA_INPUT_MENU_ITEM_ID: TextMenuItemId = TextMenuItemId.of('OH_DEFAULT_CAMERA_INPUT');

@Observed
export class EditSearchComponentData {
  // 搜索栏管理器
  public mSearchStateMgr: EditSearchStateMgr = EditSearchStateMgr.getInstance();
  // 搜索栏内容
  public mSearchValue: string = '';
  // 搜索结果集合
  public mSearchResultList: LazyDataSource<AppItemInfo> = new LazyDataSource();
  // 搜索结果集合长度
  public mResultLen: number = 0;
  // 搜索栏参数
  public mSearchComponentParam: EditSearchComponentParam = new EditSearchComponentParam();
  // 搜索栏控制器
  public mController: SearchController = new SearchController();
  // 全局上下文
  public desktopContext: ServiceExtensionContext = GlobalContext.getContext();
  // 搜索栏字体大小
  public mFontSize: Length = EditModeConstants.OUTER_EDIT_SEARCH_COMPONENT_TEXT_SIZE;
  // 是否是卡片搜索栏
  public isForm: boolean = false;

  /**
   * 初始化数据
   *
   * @param searchComponentParam 搜索栏参数
   * @param isForm 是否是卡片搜索栏
   */
  public initData(searchComponentParam: EditSearchComponentParam, isForm: boolean): void {
    this.mSearchComponentParam = searchComponentParam;
    this.isForm = isForm;
    this.mFontSize = SmallFoldStyleUtil.getScaleSize(EditModeConstants.OUTER_EDIT_SEARCH_COMPONENT_TEXT_SIZE
      , SmallFoldStyleUtil.LEVEL_BIG_3_FONT_SIZE_SCALE);
  }

  /**
   * 重置搜索栏数据
   */
  public resetSearchData(): void {
    this.mSearchStateMgr.setMatchedValue('');
    this.mSearchResultList.clear();
    this.mResultLen = 0;
  }

  /**
   * 搜索栏数据改变事件
   *
   * @param inputValue 搜索栏内容
   */
  public onSearchValueChange(inputValue: string): void {
    this.mSearchValue = inputValue;
    this.setSearchStateWhenValueChange();
    let searchResultList: AppItemInfo[] = [];
    this.searchAppList(searchResultList, this.mSearchComponentParam.fullAppList);
    log.showInfo(`search result length: ${searchResultList.length}`);
    this.handleSearchResult(searchResultList);
  }

  private setSearchStateWhenValueChange(): void {
    if (this.mSearchStateMgr.getState() !== EditSearchState.FOCUSED) {
      this.mSearchStateMgr.setState(CheckEmptyUtils.checkStrIsEmpty(this.mSearchValue) ?
      EditSearchState.NONE : EditSearchState.EDITED);
    }
  }

  private handleSearchResult(resultList: AppItemInfo[]): void {
    if (this.mSearchStateMgr.getShowState() === EditSearchShowState.NOT_SHOW) {
      log.showInfo('search not show, no treatment');
      return;
    }
    // 搜索栏数据为空
    if (CheckEmptyUtils.checkStrIsEmpty(this.mSearchValue)) {
      this.resetSearchData();
      this.mSearchComponentParam.afterSearchCallback(EditModeConstants.OUTER_EDIT_SEARCH_NO_VALUE);
      return;
    }
    // 搜索结果为空
    if (resultList.length === 0) {
      this.resetSearchData();
      // 搜索结果为空, 可能应用已经被添加到外屏
      let searchResultListByAdded: AppItemInfo[] = []
      this.searchAppList(searchResultListByAdded, this.mSearchComponentParam.allAppListByAdded);
      // 不为0表示应用已经被添加到外屏
      if (searchResultListByAdded.length === 0) {
        this.mSearchComponentParam.afterSearchCallback(EditModeConstants.OUTER_EDIT_SEARCH_NO_RESULT);
      } else {
        this.mSearchComponentParam.afterSearchCallback(EditModeConstants.OUTER_EDIT_SEARCH_NO_RESULT_BY_IN_DESKTOP);
      }
      return;
    }
    this.mSearchStateMgr.setMatchedValue(this.mSearchValue.toLocaleLowerCase().trim());
    // 上次搜索的appList
    let preSearchList: AppItemInfo[] = [];
    for (let index = 0; index < this.mSearchResultList.totalCount(); index++) {
      let item: AppItemInfo = this.mSearchResultList.getData(index);
      preSearchList.push(item);
    }
    // 两次搜索结果相同,不处理
    if (ArrayUtils.equalsArr(resultList, preSearchList)) {
      log.showInfo('same result');
      return;
    }
    this.mSearchResultList.clear();
    for (let item of resultList) {
      this.mSearchResultList.pushItem(item);
    }
    this.mResultLen = this.mSearchResultList.totalCount();
    this.mSearchResultList.notifyDataReload();
    this.mSearchComponentParam.afterSearchCallback('', resultList);
  }

  /**
   * 基于string的indexOf方法的匹配查找
   *
   *  @param searchResultList 匹配的结果
   */
  private searchAppList(searchResultList: AppItemInfo[], targetList: AppItemInfo[]): void {
    let searchValueTrim = this.mSearchValue.toLocaleLowerCase().trim();
    if (searchValueTrim.length === 0) {
      return;
    }
    for (let item of targetList) {
      if (!item.applicationName) {
        log.showWarn(`applicationName invalid: ${item.applicationName}`);
        continue;
      }
      let index: number | undefined = OuterIconCenterViewModel.getInstance()
        .getLowerCaseAppNameMap().get(item.bundleName)?.indexOf(searchValueTrim);
      if (index != undefined && index !== -1) {
        searchResultList.push(item);
      }
    }
  }

  /**
   * 过滤拍摄输入菜单
   *
   * @param menuItems 输入框目前所有菜单
   * @returns 过滤后的菜单
   */
  public filterMenu(menuItems: Array<TextMenuItem>): Array<TextMenuItem> {
    // 内屏不受影响
    if (!launcherStatusUtil.getShowOutLauncherStatus()) {
      return menuItems;
    }
    let index: number = menuItems.findIndex((item) => {
      return item.id.equals(CAMERA_INPUT_MENU_ITEM_ID);
    });
    if (index !== -1) {
      menuItems.splice(index, 1);
    }
    return menuItems;
  }
}

export class EditSearchComponentParam {
  public afterSearchCallback: (bundleName?: string, searchResultList?: AppItemInfo[]) => void = () => {};
  public fullAppList: AppItemInfo[] = [];
  public allAppListByAdded: AppItemInfo[] = [];
}

export enum EditSearchState {
  // 不获焦,没内容
  NONE,

  // 正在搜索,即搜索框获焦
  FOCUSED,

  // 搜索框没获焦,但是有内容(即不全为空格)
  EDITED
}

export enum EditSearchShowState {
  // 搜索栏显示
  SHOW,

  // 搜索栏未显示
  NOT_SHOW
}

@Observed
export class EditSearchStateMgr {
  private static instance: EditSearchStateMgr;
  private state: EditSearchState = EditSearchState.NONE;
  private showState: EditSearchShowState = EditSearchShowState.NOT_SHOW;
  private matchedValue: string = '';

  /**
   * 单例
   *
   * @returns 搜索栏状态管理器
   */
  public static getInstance(): EditSearchStateMgr {
    if (!EditSearchStateMgr.instance) {
      EditSearchStateMgr.instance = new EditSearchStateMgr();
    }
    return EditSearchStateMgr.instance;
  }

  /**
   * 设置全局搜索栏内容
   *
   * @param matchedValue 搜索栏内容
   */
  public setMatchedValue(matchedValue: string): void {
    this.matchedValue = matchedValue;
  }

  /**
   * 获取全局搜索栏内容
   *
   * @returns 搜索栏内容
   */
  public getMatchedValue(): string {
    return this.matchedValue;
  }

  /**
   * 获取当前搜索栏显示状态
   *
   * @returns 搜索栏显示状态
   */
  public getShowState(): EditSearchShowState {
    return this.showState;
  }

  /**
   * 设置当前搜索栏显示状态
   *
   * @param showState 搜索栏显示状态
   */
  public setShowState(showState: EditSearchShowState): void {
    this.showState = showState;
  }

  /**
   * 获取当前搜索栏状态
   *
   * @returns 搜索栏状态
   */
  public getState(): EditSearchState {
    return this.state;
  }

  /**
   * 设置当前搜索栏状态
   *
   * @param state 搜索栏状态
   */
  public setState(state: EditSearchState): void {
    this.state = state;
  }
}