import { uMapAlert as Alert } from '../components/alerts/alert.js'
import { MutatingForm } from './form/builder.js'
import { translate } from './i18n.js'
import * as Utils from './utils.js'
import * as DOMUtils from './domutils.js'

// Dedicated object so we can deal with a separate dirty status, and thus
// call the endpoint only when needed, saving one call at each save.
export class MapPermissions {
  constructor(umap) {
    this.setProperties(umap.properties.permissions)
    this._umap = umap
    this.sync = umap.syncEngine.proxy(this)
  }

  setProperties(properties) {
    this.properties = Object.assign(
      {
        owner: null,
        team: null,
        editors: [],
        share_status: null,
        edit_status: null,
      },
      properties
    )
  }

  getSyncMetadata() {
    return {
      subject: 'mappermissions',
      metadata: {},
    }
  }

  render() {
    this._umap.render(['properties.permissions'])
  }

  isOwner() {
    return Boolean(this._umap.properties.user?.is_owner)
  }

  isAnonymousMap() {
    return !this.properties.owner
  }

  isDraft() {
    return this.properties.share_status === 0
  }

  userIsAuth() {
    return Boolean(this._umap.properties.user?.id)
  }

  _editAnonymous(container) {
    if (this.isOwner()) {
      // We have a user, and this user has come through here, so they can edit the map, so let's allow to own the map.
      // Note: real check is made on the back office anyway.
      const template = `
          <div class="anonymous soft-round aplat">
            <h4><i class="icon icon-16 icon-anonymous"></i> ${translate('Anonymous map')}</h4>
            <div data-ref="copiableInput"></div>
            <p data-ref="p" hidden><button type="button" data-ref="button">${translate('Attach the map to my account')}</button></p>
          </div>
        `
      const [root, { button, copiableInput, p }] = Utils.loadTemplateWithRefs(template)
      container.appendChild(root)
      if (this.properties.anonymous_edit_url) {
        DOMUtils.copiableInput(
          copiableInput,
          translate('Secret edit link:'),
          this.properties.anonymous_edit_url
        )
      }
      if (this.userIsAuth()) {
        button.addEventListener('click', () => this.attach())
        p.hidden = false
      }
      const fields = []
      fields.push([
        'properties.edit_status',
        {
          handler: 'IntSelect',
          label: translate('Who can edit'),
          selectOptions: this._umap.properties.edit_statuses,
        },
      ])
      fields.push([
        'properties.share_status',
        {
          handler: 'IntSelect',
          label: translate('Who can view'),
          selectOptions: this._umap.properties.share_statuses,
        },
      ])
      const builder = new MutatingForm(this, fields)
      const form = builder.build()
      container.appendChild(form)
    }
  }

  _editWithOwner(container) {
    const topFields = []
    const collaboratorsFields = []
    const fieldset = Utils.loadTemplate(
      `<fieldset class="separator"><legend>${translate('Map')}</legend></fieldset>`
    )
    container.appendChild(fieldset)
    if (this.isOwner()) {
      topFields.push([
        'properties.edit_status',
        {
          handler: 'IntSelect',
          label: translate('Who can edit'),
          selectOptions: this._umap.properties.edit_statuses,
        },
      ])
      topFields.push([
        'properties.share_status',
        {
          handler: 'IntSelect',
          label: translate('Who can view'),
          selectOptions: this._umap.properties.share_statuses,
        },
      ])
      collaboratorsFields.push([
        'properties.owner',
        {
          handler: 'ManageOwner',
          label: translate("Map's owner"),
          url: this._umap.properties.urls.agnocomplete,
        },
      ])
      if (this._umap.properties.user?.teams?.length) {
        collaboratorsFields.push([
          'properties.team',
          {
            handler: 'ManageTeam',
            label: translate('Attach map to a team'),
            teams: this._umap.properties.user.teams,
          },
        ])
      }
    }
    collaboratorsFields.push([
      'properties.editors',
      {
        handler: 'ManageEditors',
        label: translate("Map's editors"),
        url: this._umap.properties.urls.agnocomplete,
      },
    ])

    const builder = new MutatingForm(this, topFields)
    const form = builder.build()
    container.appendChild(form)
    if (collaboratorsFields.length) {
      const fieldset = Utils.loadTemplate(
        `<fieldset class="separator"><legend>${translate('Manage collaborators')}</legend></fieldset>`
      )
      container.appendChild(fieldset)
      const builder = new MutatingForm(this, collaboratorsFields)
      const form = builder.build()
      container.appendChild(form)
    }
  }

  _editDatalayers(container) {
    if (this._umap.hasLayers()) {
      const fieldset = Utils.loadTemplate(
        `<fieldset class="separator"><legend>${translate('Datalayers’ permissions')}</legend></fieldset>`
      )
      container.appendChild(fieldset)
      const appendLayer = (layer, parentContainer) => {
        const [details, { body, icon }] = Utils.loadTemplateWithRefs(
          `<details open class="layer-group">
            <summary><i class="icon icon-16" data-ref="icon"></i>${layer.getName()}</summary>
            <div data-ref="body"></div>
          </details>`
        )
        if (layer.group) {
          icon.classList.add('icon-folder')
        } else {
          icon.hidden = true
        }
        parentContainer.appendChild(details)
        layer.permissions.edit(body)
        for (const child of layer.layers) {
          appendLayer(child, body)
        }
      }
      for (const layer of this._umap.layers.root) {
        appendLayer(layer, fieldset)
      }
    }
  }

  edit() {
    if (this._umap.properties.editMode !== 'advanced') return
    if (!this._umap.id) {
      Alert.info(translate('Please save the map first'))
      return
    }
    const container = DOMUtils.loadTemplate(`
      <div class="umap-edit-permissions">
        <h3><i class="icon icon-16 icon-key"></i> ${translate('Update permissions')}</h3>
      </div>
    `)
    if (this.isAnonymousMap()) this._editAnonymous(container)
    else this._editWithOwner(container)
    this._editDatalayers(container)
    this._umap.editPanel.open({
      content: container,
      className: 'dark',
      highlight: 'permissions',
    })
  }

  async attach() {
    const [data, response, error] = await this._umap.server.post(this.getAttachUrl())
    if (!error) {
      this.properties.owner = this._umap.properties.user
      this._umap.properties.user.is_owner = true
      this.render()
      Alert.success(translate('Map has been attached to your account'))
      this._umap.editPanel.close()
    }
  }

  async save() {
    const formData = new FormData()
    if (!this.isAnonymousMap() && this.properties.editors) {
      const editors = this.properties.editors.map((u) => u.id)
      for (let i = 0; i < this.properties.editors.length; i++)
        formData.append('editors', this.properties.editors[i].id)
    }
    if (this.isOwner() || this.isAnonymousMap()) {
      formData.append('edit_status', this.properties.edit_status)
      formData.append('share_status', this.properties.share_status)
    }
    if (this.isOwner()) {
      formData.append('owner', this.properties.owner?.id)
      formData.append('team', this.properties.team?.id || '')
    }
    const [data, response, error] = await this._umap.server.post(
      this.getUrl(),
      {},
      formData
    )
    if (!error) {
      this.commit()
      return true
    }
  }

  getUrl() {
    return this._umap.urls.get('map_update_permissions', {
      map_id: this._umap.id,
    })
  }

  getAttachUrl() {
    return this._umap.urls.get('map_attach_owner', {
      map_id: this._umap.id,
    })
  }

  commit() {
    this._umap.properties.permissions = Object.assign(
      {},
      this._umap.properties.permissions,
      this.properties
    )
  }

  pull() {
    this.setProperties(this._umap.properties.permissions)
  }

  getShareStatusDisplay() {
    if (this._umap.properties.share_statuses) {
      return Object.fromEntries(this._umap.properties.share_statuses)[
        this.properties.share_status
      ]
    }
  }
}

export class DataLayerPermissions {
  constructor(umap, datalayer, permissions) {
    this._umap = umap
    this.properties = Object.assign(
      {
        edit_status: null,
      },
      permissions
    )

    this.datalayer = datalayer
    this.sync = umap.syncEngine.proxy(this)
  }

  getSyncMetadata() {
    return {
      subject: 'datalayerpermissions',
      metadata: { id: this.datalayer.id },
    }
  }

  edit(container) {
    const label = this.datalayer.group
      ? translate('Group’s permissions')
      : translate('Layer’s permissions')
    const fields = [
      [
        'properties.edit_status',
        {
          handler: 'IntSelect',
          label: label,
          labelClassName: 'sr-only',
          selectOptions: this._umap.properties.datalayer_edit_statuses,
        },
      ],
    ]
    const builder = new MutatingForm(this, fields, {
      className: 'umap-form datalayer-permissions',
    })
    const form = builder.build()
    container.appendChild(form)
  }

  getUrl() {
    return this._umap.urls.get('datalayer_permissions', {
      map_id: this._umap.id,
      pk: this.datalayer.id,
    })
  }

  async save() {
    const formData = new FormData()
    formData.append('edit_status', this.properties.edit_status)
    const [data, response, error] = await this._umap.server.post(
      this.getUrl(),
      {},
      formData
    )
    return !error
  }
}
