import '@operato/data-grist'

import { CommonButtonStyles, CommonHeaderStyles, CommonGristStyles, ScrollbarStyles } from '@operato/styles'
import { PageView, store } from '@operato/shell'
import { css, html } from 'lit'
import { customElement, property, query } from 'lit/decorators.js'
import { ScopedElementsMixin } from '@open-wc/scoped-elements'
import { ColumnConfig, DataGrist, FetchOption } from '@operato/data-grist'
import { client } from '@operato/graphql'
import { i18next, localize } from '@operato/i18n'
import { notify, openPopup } from '@operato/layout'
import { isMobileDevice } from '@operato/utils'

import { connect } from 'pwa-helpers/connect-mixin'
import gql from 'graphql-tag'

import { NotificationRuleImporter } from './notification-rule-importer'

@customElement('notification-rule-list-page')
export class NotificationRuleListPage 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;
      }
    `
  ]

  static get scopedElements() {
    return {
      'notification-rule-importer': NotificationRuleImporter
    }
  }

  @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.notification-rule list'),
      search: {
        handler: (search: string) => {
          this.grist.searchText = search
        },
        value: this.grist?.searchText || ''
      },
      filter: {
        handler: () => {
          this.grist.toggleHeadroom()
        }
      },
      help: 'notification/notification-rule',
      actions: [
        {
          title: i18next.t('button.save'),
          action: this._updateNotificationRule.bind(this),
          ...CommonButtonStyles.save
        },
        {
          title: i18next.t('button.delete'),
          action: this._deleteNotificationRule.bind(this),
          ...CommonButtonStyles.delete
        }
      ],
      exportable: {
        name: i18next.t('title.notification-rule list'),
        data: this.exportHandler.bind(this)
      },
      importable: {
        handler: this.importHandler.bind(this)
      }
    }
  }

  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></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: {
        thumbnail: 'thumbnail',
        fields: ['name', 'description'],
        details: ['title', '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: 'string',
          name: 'title',
          header: i18next.t('field.title'),
          record: {
            editable: true
          },
          filter: 'search',
          sortable: true,
          width: 150
        },
        {
          type: 'text',
          name: 'body',
          header: i18next.t('field.body'),
          record: {
            editable: true
          },
          filter: 'search',
          sortable: true,
          width: 150
        },
        {
          type: 'string',
          name: 'url',
          header: i18next.t('field.url'),
          record: {
            editable: true
          },
          sortable: true,
          width: 150
        },
        {
          type: 'image',
          name: 'thumbnail',
          header: i18next.t('field.thumbnail'),
          record: { editable: true },
          width: 120
        },
        {
          type: 'select',
          name: 'state',
          label: true,
          header: i18next.t('field.state'),
          record: {
            options: [
              {},
              {
                display: i18next.t('text.draft'),
                value: 'DRAFT'
              },
              {
                display: i18next.t('text.released'),
                value: 'RELEASED'
              }
            ]
          },
          sortable: true,
          filter: true,
          width: 60
        },
        {
          type: 'recipients',
          name: 'recipients',
          header: i18next.t('field.recipients'),
          record: {
            editable: true
          },
          width: 50
        },
        {
          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: notificationRules(filters: $filters, pagination: $pagination, sortings: $sortings) {
            items {
              id
              name
              description
              title
              body
              url
              thumbnail
              state
              updater {
                id
                name
              }
              updatedAt
            }
            total
          }
        }
      `,
      variables: {
        filters,
        pagination: { page, limit },
        sortings
      }
    })

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

  async _deleteNotificationRule() {
    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 response = await client.mutate({
          mutation: gql`
            mutation ($ids: [String!]!) {
              deleteNotificationRules(ids: $ids)
            }
          `,
          variables: {
            ids
          }
        })

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

  async _updateNotificationRule() {
    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 response = await client.mutate({
        mutation: gql`
          mutation ($patches: [NotificationRulePatch!]!) {
            updateMultipleNotificationRule(patches: $patches) {
              name
            }
          }
        `,
        variables: {
          patches
        }
      })

      if (!response.errors) {
        this.grist.fetch()
      }
    }
  }

  async exportHandler() {
    const exportTargets = this.grist.selected.length ? this.grist.selected : this.grist.dirtyData.records
    const targetFieldSet = new Set(['id', 'name', 'description', 'active'])

    return exportTargets.map(notificationRule => {
      let tempObj = {}
      for (const field of targetFieldSet) {
        tempObj[field] = notificationRule[field]
      }

      return tempObj
    })
  }

  async importHandler(records) {
    const popup = openPopup(
      html`
        <notification-rule-importer
          .notificationRules=${records}
          @imported=${() => {
            history.back()
            this.grist.fetch()
          }}
        ></notification-rule-importer>
      `,
      {
        backdrop: true,
        size: 'large',
        title: i18next.t('title.import notification-rule')
      }
    )

    popup.onclosed = () => {
      this.grist.fetch()
    }
  }
}
