/**
 * @license
 * Copyright 2017 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
import '../../shared/gr-list-view/gr-list-view';
import {PluginInfo} from '../../../types/common';
import {firePageError, fireTitleChange} from '../../../utils/event-util';
import {getAppContext} from '../../../services/app-context';
import {ErrorCallback} from '../../../api/rest';
import {encodeURL, getBaseUrl} from '../../../utils/url-util';
import {SHOWN_ITEMS_COUNT} from '../../../constants/constants';
import {tableStyles} from '../../../styles/gr-table-styles';
import {sharedStyles} from '../../../styles/shared-styles';
import {LitElement, PropertyValues, css, html} from 'lit';
import {customElement, property, state} from 'lit/decorators.js';
import {AdminViewState} from '../../../models/views/admin';

// Exported for tests
export interface PluginInfoWithName extends PluginInfo {
  name: string;
}

@customElement('gr-plugin-list')
export class GrPluginList extends LitElement {
  readonly path = '/admin/plugins';

  /**
   * URL params passed from the router.
   */
  @property({type: Object})
  params?: AdminViewState;

  /**
   * Offset of currently visible query results.
   */
  @state() private offset = 0;

  // private but used in test
  @state() plugins?: PluginInfoWithName[];

  @state() private pluginsPerPage = 25;

  // private but used in test
  @state() loading = true;

  @state() private filter = '';

  private readonly restApiService = getAppContext().restApiService;

  override connectedCallback() {
    super.connectedCallback();
    fireTitleChange(this, 'Plugins');
  }

  static override get styles() {
    return [
      tableStyles,
      sharedStyles,
      css`
        .placeholder {
          color: var(--deemphasized-text-color);
        }
      `,
    ];
  }

  override render() {
    return html`
      <gr-list-view
        .filter=${this.filter}
        .itemsPerPage=${this.pluginsPerPage}
        .items=${this.plugins}
        .loading=${this.loading}
        .offset=${this.offset}
        .path=${this.path}
      >
        <table id="list" class="genericList">
          <tbody>
            <tr class="headerRow">
              <th class="name topHeader">Plugin Name</th>
              <th class="version topHeader">Version</th>
              <th class="apiVersion topHeader">API Version</th>
              <th class="status topHeader">Status</th>
            </tr>
            ${this.renderLoading()}
          </tbody>
          ${this.renderPluginListsTable()}
        </table>
      </gr-list-view>
    `;
  }

  private renderLoading() {
    if (!this.loading) return;

    return html`
      <tr id="loading" class="loadingMsg loading">
        <td>Loading...</td>
      </tr>
    `;
  }

  private renderPluginListsTable() {
    if (this.loading) return;

    return html`
      <tbody>
        ${this.plugins
          ?.slice(0, SHOWN_ITEMS_COUNT)
          .map(plugin => this.renderPluginList(plugin))}
      </tbody>
    `;
  }

  private renderPluginList(plugin: PluginInfoWithName) {
    return html`
      <tr class="table">
        <td class="name">
          ${plugin.index_url
            ? html`<a href=${this.computePluginUrl(plugin.index_url)}
                >${plugin.id}</a
              >`
            : plugin.id}
        </td>
        <td class="version">
          ${plugin.version
            ? plugin.version
            : html`<span class="placeholder">--</span>`}
        </td>
        <td class="apiVersion">
          ${plugin.api_version
            ? plugin.api_version
            : html`<span class="placeholder">--</span>`}
        </td>
        <td class="status">
          ${plugin.disabled === true ? 'Disabled' : 'Enabled'}
        </td>
      </tr>
    `;
  }

  override willUpdate(changedProperties: PropertyValues) {
    if (changedProperties.has('params')) {
      this.paramsChanged();
    }
  }

  // private but used in test
  paramsChanged() {
    this.loading = true;
    this.filter = this.params?.filter ?? '';
    this.offset = Number(this.params?.offset ?? 0);

    return this.getPlugins(this.filter, this.pluginsPerPage, this.offset);
  }

  private getPlugins(filter: string, pluginsPerPage: number, offset?: number) {
    const errFn: ErrorCallback = response => {
      firePageError(response);
    };
    return this.restApiService
      .getPlugins(filter, pluginsPerPage, offset, errFn)
      .then(plugins => {
        if (!plugins) {
          this.plugins = [];
          return;
        }
        this.plugins = Object.keys(plugins).map(key => {
          return {...plugins[key], name: key};
        });
      })
      .finally(() => {
        this.loading = false;
      });
  }

  private computePluginUrl(id: string) {
    return getBaseUrl() + '/' + encodeURL(id, true);
  }
}

declare global {
  interface HTMLElementTagNameMap {
    'gr-plugin-list': GrPluginList;
  }
}
