// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/* eslint-disable rulesdir/no-lit-render-outside-of-view */

import * as Host from '../../../core/host/host.js';
import * as i18n from '../../../core/i18n/i18n.js';
import * as ComponentHelpers from '../../../ui/components/helpers/helpers.js';
import * as Lit from '../../../ui/lit/lit.js';
import * as VisualLogging from '../../../ui/visual_logging/visual_logging.js';
import type * as Extensions from '../extensions/extensions.js';
import type * as Models from '../models/models.js';
import {PlayRecordingSpeed} from '../models/RecordingPlayer.js';
import * as Actions from '../recorder-actions/recorder-actions.js';

import {
  type SelectButtonClickEvent,
  type SelectButtonItem,
  type SelectMenuSelectedEvent,
  Variant as SelectButtonVariant,
} from './SelectButton.js';

const {html} = Lit;

const UIStrings = {
  /**
   * @description Replay button label
   */
  Replay: 'Replay',
  /**
   * @description Button label for the normal speed replay option
   */
  ReplayNormalButtonLabel: 'Normal speed',
  /**
   * @description Item label for the normal speed replay option
   */
  ReplayNormalItemLabel: 'Normal (Default)',
  /**
   * @description Button label for the slow speed replay option
   */
  ReplaySlowButtonLabel: 'Slow speed',
  /**
   * @description Item label for the slow speed replay option
   */
  ReplaySlowItemLabel: 'Slow',
  /**
   * @description Button label for the very slow speed replay option
   */
  ReplayVerySlowButtonLabel: 'Very slow speed',
  /**
   * @description Item label for the very slow speed replay option
   */
  ReplayVerySlowItemLabel: 'Very slow',
  /**
   * @description Button label for the extremely slow speed replay option
   */
  ReplayExtremelySlowButtonLabel: 'Extremely slow speed',
  /**
   * @description Item label for the slow speed replay option
   */
  ReplayExtremelySlowItemLabel: 'Extremely slow',
  /**
   * @description Label for a group of items in the replay menu that indicate various replay speeds (e.g., Normal, Fast, Slow).
   */
  speedGroup: 'Speed',
  /**
   * @description Label for a group of items in the replay menu that indicate various extensions that can be used for replay.
   */
  extensionGroup: 'Extensions',
} as const;

const items: SelectButtonItem[] = [
  {
    value: PlayRecordingSpeed.NORMAL,
    buttonIconName: 'play',
    buttonLabel: () => i18nString(UIStrings.ReplayNormalButtonLabel),
    label: () => i18nString(UIStrings.ReplayNormalItemLabel),
  },
  {
    value: PlayRecordingSpeed.SLOW,
    buttonIconName: 'play',
    buttonLabel: () => i18nString(UIStrings.ReplaySlowButtonLabel),
    label: () => i18nString(UIStrings.ReplaySlowItemLabel),
  },
  {
    value: PlayRecordingSpeed.VERY_SLOW,
    buttonIconName: 'play',
    buttonLabel: () => i18nString(UIStrings.ReplayVerySlowButtonLabel),
    label: () => i18nString(UIStrings.ReplayVerySlowItemLabel),
  },
  {
    value: PlayRecordingSpeed.EXTREMELY_SLOW,
    buttonIconName: 'play',
    buttonLabel: () => i18nString(UIStrings.ReplayExtremelySlowButtonLabel),
    label: () => i18nString(UIStrings.ReplayExtremelySlowItemLabel),
  },
];

const replaySpeedToMetricSpeedMap = {
  [PlayRecordingSpeed.NORMAL]: Host.UserMetrics.RecordingReplaySpeed.NORMAL,
  [PlayRecordingSpeed.SLOW]: Host.UserMetrics.RecordingReplaySpeed.SLOW,
  [PlayRecordingSpeed.VERY_SLOW]: Host.UserMetrics.RecordingReplaySpeed.VERY_SLOW,
  [PlayRecordingSpeed.EXTREMELY_SLOW]: Host.UserMetrics.RecordingReplaySpeed.EXTREMELY_SLOW,
} as const;

const str_ = i18n.i18n.registerUIStrings(
    'panels/recorder/components/ReplaySection.ts',
    UIStrings,
);
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);

export class StartReplayEvent extends Event {
  static readonly eventName = 'startreplay';

  constructor(
      public speed: PlayRecordingSpeed,
      public extension?: Extensions.ExtensionManager.Extension,
  ) {
    super(StartReplayEvent.eventName, {bubbles: true, composed: true});
  }
}

export interface ReplaySectionProps {
  disabled: boolean;
}

export interface ReplaySectionData {
  settings: Models.RecorderSettings.RecorderSettings;
  replayExtensions: Extensions.ExtensionManager.Extension[];
}

const REPLAY_EXTENSION_PREFIX = 'extension';

export class ReplaySection extends HTMLElement {
  readonly #shadow = this.attachShadow({mode: 'open'});
  readonly #props: ReplaySectionProps = {disabled: false};
  #settings?: Models.RecorderSettings.RecorderSettings;
  #replayExtensions: Extensions.ExtensionManager.Extension[] = [];

  set data(data: ReplaySectionData) {
    this.#settings = data.settings;
    this.#replayExtensions = data.replayExtensions;
  }

  get disabled(): boolean {
    return this.#props.disabled;
  }

  set disabled(disabled: boolean) {
    this.#props.disabled = disabled;
    void ComponentHelpers.ScheduledRender.scheduleRender(
        this,
        this.#render,
    );
  }

  connectedCallback(): void {
    void ComponentHelpers.ScheduledRender.scheduleRender(
        this,
        this.#render,
    );
  }

  #handleSelectMenuSelected(event: SelectMenuSelectedEvent): void {
    const speed = event.value as PlayRecordingSpeed;
    if (this.#settings && event.value) {
      this.#settings.speed = speed;
      this.#settings.replayExtension = '';
    }

    if (replaySpeedToMetricSpeedMap[speed]) {
      Host.userMetrics.recordingReplaySpeed(replaySpeedToMetricSpeedMap[speed]);
    }
    void ComponentHelpers.ScheduledRender.scheduleRender(
        this,
        this.#render,
    );
  }

  #handleSelectButtonClick(event: SelectButtonClickEvent): void {
    event.stopPropagation();

    if (event.value?.startsWith(REPLAY_EXTENSION_PREFIX)) {
      if (this.#settings) {
        this.#settings.replayExtension = event.value;
      }
      const extensionIdx = Number(
          event.value.substring(REPLAY_EXTENSION_PREFIX.length),
      );
      this.dispatchEvent(
          new StartReplayEvent(
              PlayRecordingSpeed.NORMAL,
              this.#replayExtensions[extensionIdx],
              ),
      );
      void ComponentHelpers.ScheduledRender.scheduleRender(
          this,
          this.#render,
      );
      return;
    }

    this.dispatchEvent(new StartReplayEvent(this.#settings ? this.#settings.speed : PlayRecordingSpeed.NORMAL));
    void ComponentHelpers.ScheduledRender.scheduleRender(
        this,
        this.#render,
    );
  }

  #render(): void {
    const groups = [{name: i18nString(UIStrings.speedGroup), items}];

    if (this.#replayExtensions.length) {
      groups.push({
        name: i18nString(UIStrings.extensionGroup),
        items: this.#replayExtensions.map((extension, idx) => {
          return {
            value: REPLAY_EXTENSION_PREFIX + idx,
            buttonIconName: 'play',
            buttonLabel: () => extension.getName(),
            label: () => extension.getName(),
          };
        }),
      });
    }

    // clang-format off
    Lit.render(
      html`
    <devtools-select-button
      @selectmenuselected=${this.#handleSelectMenuSelected}
      @selectbuttonclick=${this.#handleSelectButtonClick}
      .variant=${SelectButtonVariant.PRIMARY}
      .showItemDivider=${false}
      .disabled=${this.#props.disabled}
      .action=${Actions.RecorderActions.REPLAY_RECORDING}
      .value=${this.#settings?.replayExtension || this.#settings?.speed || ''}
      .buttonLabel=${i18nString(UIStrings.Replay)}
      .groups=${groups}
      jslog=${VisualLogging.action(Actions.RecorderActions.REPLAY_RECORDING).track({click: true})}
    ></devtools-select-button>`,
      this.#shadow,
      { host: this },
    );
    // clang-format on
  }
}

customElements.define(
    'devtools-replay-section',
    ReplaySection,
);

declare global {
  interface HTMLElementEventMap {
    startreplay: StartReplayEvent;
  }

  interface HTMLElementTagNameMap {
    'devtools-replay-section': ReplaySection;
  }
}
