/* eslint-disable no-case-declarations */
import { Injector } from '@opensumi/di';
import { IEditorDocumentModel, WorkbenchEditorService } from '@opensumi/ide-editor';
import { IWorkspaceService } from '@opensumi/ide-workspace';

import { isDocumentValid } from '../../../../common/utils';
import {
  ICompletionContext,
  MatchSimilarSnippet,
  NeighboringTabsOption,
  ResourceDocument,
  SimilarFileOptions,
} from '../types';

import { MAX_NEIGHBOR_AGGREGATE_LENGTH } from './const';
import { FixedWindowSizeJaccardMatcher } from './jaccardMatcher';

export const getOpenedTabFileList = (documents: IEditorDocumentModel[]) => {
  // 过滤超大文档
  const recentFiles = documents.filter((document) => isDocumentValid(document));
  return recentFiles;
};

export const getRecentEditFileList = () => [];

export const getNeighboringDocument = async (type: NeighboringTabsOption, injector: Injector) => {
  switch (type) {
    case NeighboringTabsOption.openFileHistory:
      const editorService = injector.get(WorkbenchEditorService) as WorkbenchEditorService;
      const documents = await editorService.getAllOpenedDocuments();
      return getOpenedTabFileList(documents);
    case NeighboringTabsOption.editFileHistory:
      // 暂不支持
      return [];
    case NeighboringTabsOption.editFileRecent:
      return [];
    default:
      return [];
  }
};

export const getNeighboringResource = async (
  targetFileName: string,
  languageId: string,
  option: SimilarFileOptions,
  injector: Injector,
) => {
  let documentList: IEditorDocumentModel[] = [];
  for (const type of option.neighboringTabsOption) {
    documentList = documentList.concat(await getNeighboringDocument(type, injector));
  }
  documentList = documentList.filter(
    (document) => document.languageId === languageId && !document.uri.displayName.endsWith(targetFileName),
  );
  // 移除重复项
  documentList = documentList.filter(
    (document, index) => documentList.findIndex((item) => item.uri === document.uri) === index,
  );

  let neighboringTabsMaxNum = 20;
  if (typeof option.neighboringTabsMaxNum === 'number') {
    neighboringTabsMaxNum = option.neighboringTabsMaxNum;
  }
  documentList = documentList.slice(0, neighboringTabsMaxNum);
  const resources: ResourceDocument[] = documentList.map((document) => {
    const content = document.getText();
    return {
      source: content,
      uri: document.uri,
      languageId: document.languageId,
      offset: content.length,
    };
  });
  return resources;
};

export const getSimilarSnippets = async (
  context: ICompletionContext,
  options: SimilarFileOptions,
  injector: Injector,
) => {
  const editorService = injector.get(WorkbenchEditorService) as WorkbenchEditorService;
  const workspaceService = injector.get(IWorkspaceService) as IWorkspaceService;
  // 过滤文件，仅保留相同后缀文件
  // 仅保留 20 项，顺序取决于配置顺序
  const neighboringFiles = await getNeighboringResource(context.filename, context.language, options, injector);
  const snippetLength = (context.prefix + context.suffix).split('\n').length;
  // 窗口大小最大不大于服务端配置的 windowSize 大小
  const windowSize = snippetLength > options.windowSize ? options.windowSize : snippetLength;

  const doMatcher = FixedWindowSizeJaccardMatcher.factory(windowSize);
  const bestMatchSnippets: [string, MatchSimilarSnippet[]][] = [];
  const currentDocument = editorService.currentEditor?.currentDocumentModel;
  if (!currentDocument) {
    return [];
  }
  const content = currentDocument.getText();
  const matcher = doMatcher.to({
    source: content,
    uri: currentDocument.uri,
    languageId: currentDocument.languageId,
    offset: content.length,
  });
  let currentLength = 0;
  const maxPromptTime = options.maxTime ?? 1000;
  const startTime = Date.now();
  for (const file of neighboringFiles) {
    currentLength += file.source.length;
    const snippet = matcher.findMatches(file, options.snippetSelectionMode);
    if (snippet && snippet.length) {
      const relative = await workspaceService.asRelativePath(file.uri);
      if (relative?.path) {
        bestMatchSnippets.push([relative.path, snippet]);
      }
    }
    if (Date.now() - startTime > maxPromptTime) {
      break;
    }
    // 计算相似性片段总长度不能超过 MAX_NEIGHBOR_AGGREGATE_LENGTH
    if (currentLength > MAX_NEIGHBOR_AGGREGATE_LENGTH) {
      break;
    }
  }
  // 对相似片段以 score 降序排序，仅取前 snippetMaxNum 项
  const sortedSnippets = bestMatchSnippets
    .filter((item) => item[1][0] && item[1][0].score > (options.similarityThreshold ?? 0.6))
    .sort((a, b) => b[1][0].score - a[1][0].score)
    .slice(0, options.snippetMaxNum || 4);
  return sortedSnippets;
};
