import { html, nothing, TemplateResult } from 'lit'
import { property, query } from 'lit/decorators.js'
import { classMap } from 'lit/directives/class-map.js'
import type { IRequestAuthorization } from '@api-client/core/models/RequestAuthorization.js'
import ApiElement from '../../ApiElement.js'
import { authTypeToLabel } from '../AuthLabels.js'
import Input from '../../../md/input/Input.js'
import '../../../md/icon-button/ui-icon-button.js'
import '../../../md/switch/ui-switch.js'
import '../../../md/icons/ui-icon.js'

/**
 * An authorization element renders an UI allowing the user to provide client credentials.
 *
 * @fires delete - When the user requests to delete this authorization.
 * @fires change - When authorization values have changed via a user interaction.
 */
export class Authorization extends ApiElement {
  /**
   * The form element in the UI.
   */
  @query('form', true) protected accessor form!: HTMLFormElement

  /**
   * The request authorization object keeping the config.
   * @attribute
   */
  @property({ type: Object }) accessor authorization: IRequestAuthorization | undefined

  /**
   * Whether the UI is in the disabled state.
   * @attribute
   */
  @property({ type: Boolean, reflect: true }) accessor disabled = false

  /**
   * Whether the UI is in the read only state.
   * @attribute
   */
  @property({ type: Boolean, reflect: true }) accessor readOnly = false

  /**
   * Whether the element is currently authorizing the user.
   * @attribute
   */
  @property({ type: Boolean, reflect: true }) accessor authorizing = false

  /**
   * Whether the UI should render the toggle button to toggle the enabled state of the security scheme
   * @attribute
   */
  @property({ type: Boolean }) accessor canToggle: boolean | undefined

  /**
   * Whether the UI should render the delete button
   * @attribute
   */
  @property({ type: Boolean }) accessor canDelete: boolean | undefined

  /**
   * Toggles this authorization method enabled state.
   * This does noting when `authorization` is not set.
   */
  toggleEnabled(): void {
    const { authorization } = this
    if (!authorization) {
      return
    }
    authorization.enabled = !authorization.enabled
    this.requestUpdate()
    this.notifyChange()
  }

  protected handleDelete(): void {
    this.dispatchEvent(new Event('delete'))
  }

  /**
   * Performs the authorization.
   * This only applies to methods that have any authorization to perform
   * like Oauth 2.
   */
  async authorize(): Promise<unknown> {
    return null
  }

  /**
   * @returns True when the element is valid.
   */
  checkValidity(): boolean {
    const { elements } = this.form
    return !Array.from(elements).some((node) => !(node as Input).checkValidity())
  }

  protected renderHeader(): TemplateResult | typeof nothing {
    const { authorization } = this
    if (!authorization) {
      return nothing
    }
    const classes = {
      'auth-header': true,
      'centered': !this.canDelete && !this.canToggle,
    }
    return html`
      <div class="${classMap(classes)}">
        ${this.renderToggleSwitch(authorization)} ${this.renderTitle(authorization)} ${this.renderDeleteButton()}
      </div>
    `
  }

  protected renderAuthInfo(): TemplateResult {
    return html`
      <p class="auth-info">
        Note that the authorization header will be added when the request is sent. We encourage you to use variables to
        insert sensitive data.
      </p>
    `
  }

  protected renderToggleSwitch(authorization: IRequestAuthorization): TemplateResult | typeof nothing {
    const { canToggle } = this
    if (!canToggle) {
      return nothing
    }
    return html`
      <ui-switch
        .checked="${!!authorization.enabled}"
        @change="${this.toggleEnabled}"
        aria-label="Toggle this authorization"
        ?disabled="${this.readOnly || this.disabled}"
      ></ui-switch>
    `
  }

  protected renderTitle(authorization: IRequestAuthorization): TemplateResult {
    const { type } = authorization
    const label = authTypeToLabel(type || '')
    return html` <span class="auth-title">${label}</span> `
  }

  protected renderDeleteButton(): TemplateResult | typeof nothing {
    const { canDelete } = this
    if (!canDelete) {
      return nothing
    }
    return html`
      <ui-icon-button
        aria-label="Delete this authorization"
        title="Removes this authorization definition"
        @click="${this.handleDelete}"
        ?disabled="${this.readOnly}"
      >
        <ui-icon icon="deleteOutline" role="presentation"></ui-icon>
      </ui-icon-button>
    `
  }
}
