import '@operato/data-grist'

import { CommonButtonStyles, CommonGristStyles, CommonHeaderStyles, ScrollbarStyles } from '@operato/styles'
import { PageView, store } from '@operato/shell'
import { css, html } from 'lit'
import { useMutation } from '@apollo/client'

import { customElement, property, query } from 'lit/decorators.js'
import { connect } from 'pwa-helpers/connect-mixin'
import gql from 'graphql-tag'
import { ScopedElementsMixin } from '@open-wc/scoped-elements'
import { DataGrist, FetchOption, getEditor, getRenderer } from '@operato/data-grist'

import { client } from '@operato/graphql'
import { i18next, localize } from '@operato/i18n'
import { notify } from '@operato/layout'
import { isMobileDevice } from '@operato/utils'

// export interface ThemeType {
//   name: string
//   propType: string
// }

// var ThemeTypes: { [name: string]: ThemeType } = {
//   Legend: {
//     name: 'Legend',
//     propType: 'legend'
//   }
// }

@customElement('theme-list-page')
export class ThemeListPage extends connect(store)(localize(i18next)(ScopedElementsMixin(PageView))) {
  static styles = [
    ScrollbarStyles,
    CommonGristStyles,
    CommonHeaderStyles,
    css`
      :host {
        display: flex;

        width: 100%;

        --grid-record-emphasized-background-color: #8b0000;
        --grid-record-emphasized-color: #ff6b6b;
      }

      ox-grist {
        overflow-y: auto;
        flex: 1;
      }

      ox-filters-form {
        flex: 1;
      }
    `
  ]

  @property({ type: Object }) gristConfig: any
  @property({ type: String }) mode: 'CARD' | 'GRID' | 'LIST' = isMobileDevice() ? 'CARD' : 'GRID'

  @query('ox-grist') private grist!: DataGrist

  get context() {
    return {
      title: i18next.t('title.theme list'),
      search: {
        handler: (search: string) => {
          this.grist.searchText = search
        },
        value: this.grist?.searchText || ''
      },
      filter: {
        handler: () => {
          this.grist.toggleHeadroom()
        }
      },
      help: 'board-service/theme',
      actions: [
        {
          title: i18next.t('button.save'),
          action: this._updateTheme.bind(this),
          ...CommonButtonStyles.save
        },
        {
          title: i18next.t('button.delete'),
          action: this._deleteTheme.bind(this),
          ...CommonButtonStyles.delete
        }
      ]
    }
  }

  render() {
    const mode = this.mode || (isMobileDevice() ? 'CARD' : 'GRID')

    return html`
      <ox-grist .mode=${mode} .config=${this.gristConfig} .fetchHandler=${this.fetchHandler.bind(this)}>
        <div slot="headroom" class="header">
          <div class="filters">
            <ox-filters-form autofocus without-search></ox-filters-form>

            <div id="modes">
              <md-icon @click=${() => (this.mode = 'GRID')} ?active=${mode == 'GRID'}>grid_on</md-icon>
              <md-icon @click=${() => (this.mode = 'LIST')} ?active=${mode == 'LIST'}>format_list_bulleted</md-icon>
              <md-icon @click=${() => (this.mode = 'CARD')} ?active=${mode == 'CARD'}>apps</md-icon>
            </div>
          </div>
        </div>
      </ox-grist>
    `
  }

  async pageInitialized(lifecycle: any) {
    this.gristConfig = {
      list: {
        fields: ['name', 'description'],
        details: ['type', 'updatedAt']
      },
      columns: [
        { type: 'gutter', gutterName: 'sequence' },
        { type: 'gutter', gutterName: 'row-selector', multiple: true },
        {
          type: 'string',
          name: 'name',
          header: i18next.t('field.name'),
          record: {
            editable: true
          },
          filter: 'search',
          sortable: true,
          width: 150
        },
        {
          type: 'string',
          name: 'description',
          header: i18next.t('field.description'),
          record: {
            editable: true
          },
          filter: 'search',
          width: 200
        },
        {
          type: 'checkbox',
          name: 'active',
          header: i18next.t('field.active'),
          record: {
            editable: true
          },
          width: 60
        },
        {
          type: 'select',
          name: 'type',
          header: i18next.t('field.type'),
          record: {
            options: ['', 'color-map', 'color-ranges', 'color', 'text'],
            editable: true
          },
          width: 120
        },
        {
          type: 'object',
          name: 'value',
          header: i18next.t('field.value'),
          record: {
            editor: function (value, column, record, rowIndex, field) {
              return getEditor(record.type || 'text')(value, column, record, rowIndex, field)
            },
            renderer: function (value, column, record, rowIndex, field) {
              return getRenderer(record.type || 'text')(value, column, record, rowIndex, field)
            },
            editable: true,
            options: {
              objectified: true
            }
          },
          sortable: true,
          width: 180
        },
        {
          type: 'resource-object',
          name: 'updater',
          header: i18next.t('field.updater'),
          record: {
            editable: false
          },
          sortable: true,
          width: 120
        },
        {
          type: 'datetime',
          name: 'updatedAt',
          header: i18next.t('field.updated_at'),
          record: {
            editable: false
          },
          sortable: true,
          width: 180
        }
      ],
      rows: {
        selectable: {
          multiple: true
        }
      },
      sorters: [
        {
          name: 'name'
        }
      ]
    }
  }

  async pageUpdated(changes: any, lifecycle: any) {
    if (this.active) {
      // do something here when this page just became as active
    }
  }

  async fetchHandler({ page = 1, limit = 100, sortings = [], filters = [] }: FetchOption) {
    const response = await client.query({
      query: gql`
        query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {
          responses: themes(filters: $filters, pagination: $pagination, sortings: $sortings) {
            items {
              id
              name
              description
              active
              type
              value
              updater {
                id
                name
              }
              updatedAt
            }
            total
          }
        }
      `,
      variables: {
        filters,
        pagination: { page, limit },
        sortings
      }
    })

    return {
      total: response.data.responses.total || 0,
      records: response.data.responses.items || []
    }
  }

  async _deleteTheme() {
    if (confirm(i18next.t('text.sure_to_x', { x: i18next.t('text.delete') }))) {
      const ids = this.grist.selected.map(record => record.id)
      if (ids && ids.length > 0) {
        const [mutateFunction, { error }] = useMutation(`
mutation ($ids: [String!]!) {
  deleteThemes(ids: $ids)
}`)

        useMutation({
          variables: {
            ids
          }
        })

        if (!error) {
          this.grist.fetch()
          notify({
            message: i18next.t('text.info_x_successfully', { x: i18next.t('text.delete') })
          })
        }
      }
    }
  }

  async _updateTheme() {
    let patches = this.grist.dirtyRecords
    if (patches && patches.length) {
      patches = patches.map(patch => {
        let patchField: any = patch.id ? { id: patch.id } : {}
        const dirtyFields = patch.__dirtyfields__
        for (let key in dirtyFields) {
          patchField[key] = dirtyFields[key].after
        }
        patchField.cuFlag = patch.__dirty__

        return patchField
      })

      const [mutateFunction, { error }] = useMutation(`
mutation ($patches: [ThemePatch!]!) {
  updateMultipleTheme(patches: $patches) {
    name
  }
}`)

      mutateFunction({
        variables: {
          patches
        }
      })

      if (!error) {
        this.grist.fetch()
      }
    }
  }
}
