// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import * as i18n from '../../../../core/i18n/i18n.js';
import type * as UI from '../../legacy.js';

import {
  FilteredListWidget,
  getRegisteredProviders,
  type Provider,
  type ProviderRegistration
} from './FilteredListWidget.js';

const UIStrings = {
  /**
   * @description Text of the hint shows under Quick Open input box
   */
  typeToSeeAvailableCommands: 'Type ? to see available commands',
} as const;
const str_ = i18n.i18n.registerUIStrings('ui/legacy/components/quick_open/QuickOpen.ts', UIStrings);
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);

export const history: string[] = [];

export class QuickOpenImpl {
  private prefix: string|null = null;
  private readonly prefixes: string[] = [];
  private providers = new Map<string, {
    provider: () => Promise<Provider>,
    titlePrefix: (() => string),
    titleSuggestion?: (() => string),
  }>();
  private filteredListWidget: FilteredListWidget|null = null;

  constructor() {
    getRegisteredProviders().forEach(this.addProvider.bind(this));
    this.prefixes.sort((a, b) => b.length - a.length);
  }

  static show(query: string): void {
    const quickOpen = new this();
    const filteredListWidget = new FilteredListWidget(null, history, quickOpen.queryChanged.bind(quickOpen));
    quickOpen.filteredListWidget = filteredListWidget;
    filteredListWidget.setHintElement(i18nString(UIStrings.typeToSeeAvailableCommands));
    filteredListWidget.showAsDialog();
    filteredListWidget.setQuery(query);
  }

  private addProvider(extension: ProviderRegistration): void {
    const prefix = extension.prefix;
    if (prefix === null) {
      return;
    }
    this.prefixes.push(prefix);
    this.providers.set(prefix, {
      provider: async () => {
        const provider = await extension.provider();
        provider.jslogContext = extension.jslogContext;
        return provider;
      },
      titlePrefix: extension.titlePrefix,
      titleSuggestion: extension.titleSuggestion,
    });
  }

  private async queryChanged(query: string): Promise<void> {
    const prefix = this.prefixes.find(prefix => query.startsWith(prefix));
    if (typeof prefix !== 'string') {
      return;
    }

    if (!this.filteredListWidget) {
      return;
    }
    this.filteredListWidget.setPrefix(prefix);
    const titlePrefixFunction = this.providers.get(prefix)?.titlePrefix;
    this.filteredListWidget.setCommandPrefix(titlePrefixFunction ? titlePrefixFunction() : '');
    const titleSuggestionFunction = (query === prefix) && this.providers.get(prefix)?.titleSuggestion;
    this.filteredListWidget.setCommandSuggestion(titleSuggestionFunction ? prefix + titleSuggestionFunction() : '');

    if (this.prefix === prefix) {
      return;
    }
    this.prefix = prefix;
    this.filteredListWidget.setProvider(null);
    const providerFunction = this.providers.get(prefix)?.provider;
    if (!providerFunction) {
      return;
    }

    const provider = await providerFunction();
    if (this.prefix !== prefix || !this.filteredListWidget) {
      return;
    }
    this.filteredListWidget.setProvider(provider);
    this.providerLoadedForTest(provider);
  }

  private providerLoadedForTest(_provider: Provider): void {
  }
}

export class ShowActionDelegate implements UI.ActionRegistration.ActionDelegate {
  handleAction(_context: UI.Context.Context, actionId: string): boolean {
    switch (actionId) {
      case 'quick-open.show':
        QuickOpenImpl.show('');
        return true;
    }
    return false;
  }
}
