import '@material/web/icon/icon.js'
import '@operato/i18n/ox-i18n.js'
import '@operato/input/ox-input-key-values.js'

import gql from 'graphql-tag'
import Clipboard from 'clipboard'

import { css, html, LitElement, PropertyValues } from 'lit'
import { customElement, property, state } from 'lit/decorators.js'

import { client } from '@operato/graphql'
import { ScrollbarStyles } from '@operato/styles'
import { i18next } from '@operato/i18n'

import { hasPrivilege, privileged } from '@things-factory/auth-base/dist-client'

@customElement('link-builder')
export class LinkBuilder extends LitElement {
  static styles = [
    ScrollbarStyles,
    css`
      :host {
        display: flex;
        padding: var(--spacing-large);
        color: var(--md-sys-color-primary);

        /* for narrow mode */
        flex-direction: column;
      }

      div[link] {
        display: grid;
        position: relative;
      }

      label {
        font: var(--label-font);
        text-transform: capitalize;
      }

      input,
      select,
      textarea,
      ox-input-key-values {
        border: var(--border-dim-color);
        border-radius: var(--border-radius);
        margin: var(--input-margin);
        padding: var(--input-padding);
        font: var(--input-font);
        flex: 1 1 0%;
      }

      textarea {
        min-height: 132px;
        resize: none;
      }

      select:focus,
      input:focus,
      textarea:focus,
      button {
        outline: none;
      }

      button:hover {
        border: var(--button-activ-border);
        box-shadow: var(--button-active-box-shadow);
      }

      [button-in-field] {
        position: absolute;
        top: 64px;
        right: 6px;

        background-color: var(--md-sys-color-surface);
        opacity: 0.8;
        color: var(--md-sys-color-primary);
      }

      [warn] {
        color: var(--status-warning-color, red);
      }
    `
  ]

  @property({ type: String, attribute: true }) command?: string
  @property({ type: String, attribute: 'target-id' }) targetId?: string
  @property({ type: String, attribute: 'target-name' }) targetName?: string

  @state() link?: string
  @state() keyvalues: any
  @state() appliances: any[] = []
  @state() targetAppliance: any
  @state() key?: string
  @state() byname: boolean = false

  private clipboard?: Clipboard

  render() {
    return html`
      <div link>
        <h3>
          <ox-title-with-help topic="operato-board/headless-link" msgid="label.headless-link"
            >headless-link</ox-title-with-help
          >
        </h3>
        <textarea id="link" .value=${this.link || ''} readonly></textarea>
        <md-icon button-in-field clipboard-copy>content_copy</md-icon>
        <label for="key">${i18next.t('label.headless-link query-key')}</label>
        <input id="key" type="text" .value=${this.key || ''} @change=${e => (this.key = e.target.value)} />
        <label>${i18next.t('label.headless-link query-parameters')}</label>
        <ox-input-key-values @change=${e => (this.keyvalues = e.detail)}></ox-input-key-values>
        <label>${i18next.t('label.headless-link target-appliance')}</label>

        ${privileged(
          { privilege: 'query', category: 'security', superUserGranted: true, domainOwnerGranted: true },
          html`
            <select
              @change=${e => (this.targetAppliance = this.appliances.find(appliance => appliance.id == e.target.value))}
              placeholder="choose appliance ..."
              .value=${this.targetAppliance?.id}
            >
              <option value=""></option>
              ${this.appliances.map(
                appliance => html`
                  <option .value=${appliance.id} ?selected=${appliance.id == this.targetAppliance?.id}>
                    ${appliance.name}
                  </option>
                `
              )}
            </select>
          `,
          html`
            <span warn>To add an access token, you need to be a domain owner or have security query permissions.</span>
          `
        )}

        <div>
          <input
            type="checkbox"
            id="by-name"
            @change=${(e: Event) => (this.byname = !!(e.target as HTMLInputElement)?.checked)}
          />
          <label for="by-name">${i18next.t('label.headless-link by-name')}</label>
        </div>
      </div>
    `
  }

  firstUpdated() {
    const copybuttons = this.renderRoot.querySelectorAll('[clipboard-copy]')

    this.clipboard = new Clipboard(copybuttons, {
      target: (trigger => trigger.parentElement.querySelector('textarea')) as any
    })

    this.getAppliances()
  }

  updated(changes: PropertyValues<this>) {
    const command = (this.command || '') + (this.byname ? '-by-name' : '')
    const target = encodeURIComponent((this.byname ? this.targetName : this.targetId) || '')

    const baseUrl = document.querySelector('base')?.href
    const fullUrl = new URL(command + '/' + target, baseUrl).href

    const query = {
      ...(this.key ? { [this.key]: JSON.stringify(this.keyvalues) } : this.keyvalues),
      ...(this.targetAppliance ? { access_token: this.targetAppliance?.accessToken } : {})
    }

    const queryString = this.objectToQueryString(query)

    this.link = fullUrl + (queryString ? '?' + queryString : '')
  }

  objectToQueryString(obj) {
    return Object.keys(obj)
      .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(obj[key])}`)
      .join('&')
  }

  async getAppliances() {
    this.appliances = []
    this.targetAppliance = null

    if (
      await hasPrivilege({ privilege: 'query', category: 'security', superUserGranted: true, domainOwnerGranted: true })
    ) {
      var response = (
        await client.query({
          query: gql`
            query {
              appliances {
                items {
                  id
                  name
                  description
                  accessToken
                }
              }
            }
          `
        })
      ).data

      this.appliances = response.appliances.items
    }
  }
}
