// Copyright (c) 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import * as Common from '../../common/common.js';
import * as Host from '../../host/host.js';  // eslint-disable-line no-unused-vars
import * as LitHtml from '../../third_party/lit-html/lit-html.js';

import type {IconData} from './Icon.js';

const ls = Common.ls;

export type CanShowSurveyCallback = (result: Host.InspectorFrontendHostAPI.CanShowSurveyResult) => void;
export type ShowSurveyCallback = (result: Host.InspectorFrontendHostAPI.ShowSurveyResult) => void;

export interface SurveyLinkData {
  trigger: string;
  promptText: Common.UIString.LocalizedString;
  canShowSurvey: (trigger: string, callback: CanShowSurveyCallback) => void;
  showSurvey: (trigger: string, callback: ShowSurveyCallback) => void;
}

const enum State {
  Checking = 'Checking',  // (begin state) -> ShowLink | DontShowLink
  ShowLink = 'ShowLink',  // -> Sending
  Sending = 'Sending',    // -> SurveyShown | Failed
  SurveyShown = 'SurveyShown',
  Failed = 'Failed',
  DontShowLink = 'DontShowLink',
}

// A link to a survey. The link is rendered aysnchronously because we need to first check if
// canShowSurvey succeeds.
export class SurveyLink extends HTMLElement {
  private readonly shadow = this.attachShadow({mode: 'open'});
  private trigger = '';
  private promptText = Common.UIString.LocalizedEmptyString;
  private canShowSurvey: (trigger: string, callback: CanShowSurveyCallback) => void = () => {};
  private showSurvey: (trigger: string, callback: ShowSurveyCallback) => void = () => {};
  private state: State = State.Checking;

  // Re-setting data will cause the state to go back to 'Checking' which hides the link.
  set data(data: SurveyLinkData) {
    this.trigger = data.trigger;
    this.promptText = data.promptText;
    this.canShowSurvey = data.canShowSurvey;
    this.showSurvey = data.showSurvey;

    this.checkSurvey();
  }

  private checkSurvey(): void {
    this.state = State.Checking;
    this.canShowSurvey(this.trigger, ({canShowSurvey}) => {
      if (!canShowSurvey) {
        this.state = State.DontShowLink;
      } else {
        this.state = State.ShowLink;
      }
      this.render();
    });
  }

  private sendSurvey(): void {
    this.state = State.Sending;
    this.render();
    this.showSurvey(this.trigger, ({surveyShown}) => {
      if (!surveyShown) {
        this.state = State.Failed;
      } else {
        this.state = State.SurveyShown;
      }
      this.render();
    });
  }

  private render(): void {
    if (this.state === State.Checking || this.state === State.DontShowLink) {
      return;
    }

    let linkText = this.promptText;
    if (this.state === State.Sending) {
      linkText = ls`Opening survey …`;
    } else if (this.state === State.SurveyShown) {
      linkText = ls`Thank you for your feedback`;
    } else if (this.state === State.Failed) {
      linkText = ls`An error occurred with the survey`;
    }

    let linkState = '';
    if (this.state === State.Sending) {
      linkState = 'pending-link';
    } else if (this.state === State.Failed || this.state === State.SurveyShown) {
      linkState = 'disabled-link';
    }

    const ariaDisabled = this.state !== State.ShowLink;

    // clang-format off
    const output = LitHtml.html`
      <style>
        .link-icon {
          vertical-align: sub;
          margin-right: 0.5ch;
        }

        .link {
          padding: var(--issue-link-padding, 4px 0 0 0);
          text-decoration: var(--issue-link-text-decoration, underline);
          cursor: pointer;
          font-size: var(--issue-link-font-size, 14px);
          color: var(--issue-link); /* stylelint-disable-line plugin/use_theme_colors */
          /* See: crbug.com/1152736 for color variable migration. */
          border: none;
          background: none;
          font-family: inherit;
        }

        .link:focus:not(:focus-visible) {
          outline: none;
        }

        .pending-link {
          opacity: 75%;
          pointer-events: none;
          cursor: default;
          text-decoration: none;
        }

        .disabled-link {
          pointer-events: none;
          cursor: default;
          text-decoration: none;
        }
      </style>
      <button class="link ${linkState}" tabindex=${ariaDisabled ? '-1' : '0'} aria-disabled=${ariaDisabled} @click=${this.sendSurvey}>
        <devtools-icon class="link-icon" .data=${{iconName: 'feedback_thin_16x16_icon', color: 'var(--issue-link)', width: 'var(--issue-link-icon-size, 16px)', height: 'var(--issue-link-icon-size, 16px)'} as IconData}></devtools-icon><!--
      -->${linkText}
      </button>
    `;
    // clang-format on
    LitHtml.render(output, this.shadow, {eventContext: this});
  }
}

customElements.define('devtools-survey-link', SurveyLink);

declare global {
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  interface HTMLElementTagNameMap {
    'devtools-survey-link': SurveyLink;
  }
}
