var D4S_STORAGE_SCRIPT = document.currentScript

/**
 * Base class of <d4s-storage-tree> and <d4s-storage-folder>
 */
class D4SStorageHtmlElement extends HTMLElement {

  #d4smissmsg = 'Required d4s-boot-2 component not found'
  #baseurl = 'https://api.d4science.org/workspace'
  //#baseurl = 'https://workspace-repository.dev.d4science.org/storagehub/workspace'
  #boot = null

  constructor() {
    super()
    this.#boot = document.querySelector('d4s-boot-2')
  }

  get boot() {
    if (this.#boot == null) {
      this.#boot = document.querySelector('d4s-boot-2')
      if (!this.#boot) {
        throw this.#d4smissmsg
      }
    }
    return this.#boot
  }

  appendStylesheets(root) {
    const linkElem1 = document.createElement('link')
    linkElem1.setAttribute('rel', 'stylesheet')
    linkElem1.setAttribute('href', 'https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css')
    root.appendChild(linkElem1)
  }

  buildListUrl(id) {
    return this.#baseurl + '/items/' + id + '/children'
  }

  get baseUrl() {
    return this.#baseurl
  }

  set baseUrl(url) {
    this.#baseurl = url
    this.setAttribute("baseurl", url)
  }
}


/**
 * Builds storagehub VREFolder tree
 * <d4s-storage-tree
 *  /@filelist-id: identifier of d4s-storage-folder component
 *  /@base-url: the base endpoint url [defaults to: https://api.d4science.org/workspace]
 */
window.customElements.define('d4s-storage-tree', class extends D4SStorageHtmlElement {

  #storageFilelistId = null

  #loadedClass = 'loaded'
  #selectedClass = 'selected'
  #selectedbgcolor = 'lightgray'
  #shadowRoot

  constructor() {
    super()
    this.#shadowRoot = this.attachShadow({mode: 'open'})
  }

  /*
  Notes:
  API docs: https://gcube.wiki.gcube-system.org/gcube/StorageHub_REST_API
  Preprod: https://accounts.pre.d4science.org
  Sample context: %2Fpred4s%2Fpreprod%2FpreVRE
  User workspace: https://storagehub.pre.d4science.net/storagehub/workspace
  vrefolder: https://storagehub.pre.d4science.net/storagehub/workspace/vrefolder
    -> and if "id": "e0cd15d2-0071-43ca-bc42-aef8d80660fe",
      the tree dir of vrefolder: https://storagehub.pre.d4science.net/storagehub/workspace/items/e0cd15d2-0071-43ca-bc42-aef8d80660fe/children
      download of a file (domenica.jpg): https://storagehub.pre.d4science.net/storagehub/workspace/items/a5086811-59d1-4230-99fa-98431e820cf1/download
  */
  connectedCallback() {
    this.appendStylesheets(this.#shadowRoot)

    var div = document.createElement('div')
    const style = `
      <style>
        .selected > *:first-child {
          background-color: ${this.#selectedbgcolor};
        }
        ul, li {
          list-style-type: none;
        }
        li {
          cursor: pointer;
        }
      </style>
    `
    div.innerHTML = style

    this.boot.secureFetch(this.baseUrl + '/vrefolder').then((reply) => {
      if (reply.status !== 200) {
        throw "Unable to load folder"
      }
      return reply.json()

    }).then(data => {
      this.parseResponse(div, data)
      this.#shadowRoot.appendChild(div)

    }).catch(err => console.error(err))
  }

  parseResponse(parentElement, jresp) {
    parentElement.classList.add(this.#loadedClass)
    var ul = document.createElement('ul')
    ul.classList.add('nested')
    if (jresp.item) {
      const itemname = jresp.item.displayName
      const itemid = jresp.item.id
      const path = this.buildListUrl(itemid)
      ul.appendChild(this.createListItem(itemname, itemid))
      parentElement.appendChild(ul)

    } else if (jresp.itemlist) {
      jresp
        .itemlist
        .filter(item => item['@class'].includes('FolderItem'))
        .forEach(item => {
          const itemname = item.name
          const itemid = item.id
          const path = this.buildListUrl(itemid)
          ul.appendChild(this.createListItem(itemname, itemid))
        })
      parentElement.appendChild(ul)

    } else {
      console.error(jresp)
    }
  }

  createListItem(label, id) {
    var li = document.createElement('li')
    li.setAttribute('data-id', id)
    var child = document.createElement('span')
    child.innerHTML = label
    li.appendChild(child)

    li.addEventListener('click', (ev) => {
      ev.stopPropagation()
      this.select(ev.currentTarget.getAttribute('data-id'))
    })
    return li
  }

  select(id) {
    var li = this.shadowRoot.querySelector(`*[data-id='${id}']`)
    this.displayPath(li)

    // if it was already selected then do nothing
    if (li.classList.contains(this.#selectedClass)) {
      this.toggleULDisplay(li)
      return
    }
    // switch selected and lists folder contents
    if (!li.classList.contains(this.#selectedClass)) {
      const selected = this.shadowRoot.querySelector('.' + this.#selectedClass)
      if (selected) {
        selected.classList.remove(this.#selectedClass)
      }
      li.classList.add(this.#selectedClass)
      if (this.#storageFilelistId) {
        var folder = document.getElementById(this.#storageFilelistId)
        folder.join(this)
        folder.list(id)
      }
    }
    if (li.classList.contains(this.#loadedClass)) {
      return
    }

    this.boot.secureFetch(this.buildListUrl(id)).then(reply => {
      if (reply.status !== 200) {
        throw "Unable to load folder"
      }
      return reply.json()

    }).then(data => {
      this.parseResponse(li, data)

    }).catch(err => console.error(err))
  }

  displayPath(li) {
    var curr = li
    while (curr.parentElement != null) {
      if (curr.parentElement.tagName == 'UL') {
        curr.parentElement.style.display = 'block'
      }
      curr = curr.parentElement
    }
  }

  toggleULDisplay(li) {
    const ul = li.querySelector('ul')
    if (ul) {
      ul.style.display = (ul.style.display === 'none') ? 'block' : 'none'
    }
  }

  static get observedAttributes() {
    return ["base-url", "filelist-id"]
  }

  attributeChangedCallback(name, oldValue, newValue) {
    if (oldValue !== newValue) {
      switch (name) {
        case "filelist-id":
          this.#storageFilelistId = newValue
          break
        case "base-url":
          this.baseUrl = newValue
          break
      }
    }
  }

  get filelistId() {
    return this.#storageFilelistId
  }

  set filelistId(id) {
    this.#storageFilelistId = id
    this.setAttribute("filelist-id", id)
  }
})

/**
 * Lists elements in selected folder
 * 
 * <d4s-storage-folder
 *  /@id: specify the id to join this component with storage tree component
 *  /@base-url: the base endpoint url [defaults to: https://api.d4science.org/workspace]
 */
window.customElements.define('d4s-storage-folder', class extends D4SStorageHtmlElement {

  #d4sstorageTree = null
  #selectedbgcolor = 'lightgray'
  #srcbaseurl = null
  
  constructor() {
    super()
    if (D4S_STORAGE_SCRIPT) {
      const d4ssrc = D4S_STORAGE_SCRIPT.src
      this.#srcbaseurl = (d4ssrc) ? d4ssrc.substring(0, d4ssrc.lastIndexOf('/')) : ""
    }
  }

  connectedCallback() {
    const shadowRoot = this.attachShadow({mode: 'open'})
    this.appendStylesheets(shadowRoot)
    const style = document.createElement('style')
    style.innerHTML = `
      span {
        cursor: pointer;
        user-select: none;
        -moz-user-select: none;
        -webkit-user-select: none;
        -ms-user-select: none;
      }
    `
    shadowRoot.appendChild(style)
    this.createContainer()
  }

  createContainer() {
    var div = document.createElement('div')
    div.classList.add('d4s-folder')
    var child = this.shadowRoot.querySelector('.d4s-folder')
    if (child) {
      this.shadowRoot.removeChild(child)
    }
    this.shadowRoot.appendChild(div)
    return div
  }

  join(tree) {
    if (this.#d4sstorageTree == null) {
      this.#d4sstorageTree = tree
    }
  }

  list(folderId) {
    this.boot.secureFetch(this.buildListUrl(folderId)).then(reply => {
      if (reply.status !== 200) {
        throw "Unable to build list url"
      }
      return reply.json()

    }).then(data => {
      this.parseResponse(data)

    }).catch(err => console.error(err))
  }

  parseResponse(jresp) {
    const root = this.createContainer()
    if (jresp.itemlist) {
      jresp.itemlist.forEach(item => root.appendChild(this.createFileRow(item)))
    } else {
      console.error(jresp)
    }
  }

  createFileRow(item) {
    var div = document.createElement('div')
    div.classList.add('row')
    var filename = document.createElement('div')
    filename.classList.add('col')
    var name = `<span>${item.name}</span>`
    filename.innerHTML = this.iconTag(item) + name
    const isFolder = item['@class'].includes('FolderItem')
    filename.addEventListener('click', (ev) => {
      ev.stopPropagation()
      if (isFolder) {
        const span = ev.currentTarget.querySelector(':nth-child(2)')
        if (span) {
            span.style = 'background-color: ' + this.#selectedbgcolor
        }
        if (this.#d4sstorageTree != null) {
          this.#d4sstorageTree.select(item.id)
        }
      } else {
        console.info("Download of " + item.id)
        this.download(this.buildDownloadUrl(item.id), item.name)
      }
    })

    div.appendChild(filename)
    return div
  }

  iconTag(item) {
    var i = `<img src="${this.#srcbaseurl}/img/file-earmark.svg"></img>`
    if (item['@class'].includes('FolderItem')) {
      i = `<img src="${this.#srcbaseurl}/img/folder.svg"></img>`
    } else if (item['@class'].includes('ImageFile')) {
      i = `<img src="${this.#srcbaseurl}/img/image.svg"></img>`
    } else if (item['@class'].includes('PDFFileItem')) {
      i = `<img src="${this.#srcbaseurl}/img/filetype-pdf.svg"></img>`
    }
    return '<span class="px-2">' + i + '</span>'
  }

  buildDownloadUrl(id) {
    return this.baseUrl+ '/items/' + id + '/download'
  }

  download(url, name) {
    this.boot.secureFetch(url).then(reply => {
      if (reply.status !== 200) {
        throw "Unable to download"
      }
      return reply.blob()

    }).then(blob => {
      const objectURL = URL.createObjectURL(blob)
      var tmplnk = document.createElement("a")
      tmplnk.download = name
      tmplnk.href = objectURL
      //tmplnk.target="_blank"
      document.body.appendChild(tmplnk)
      tmplnk.click()
      document.body.removeChild(tmplnk)

    }).catch(err => console.error(err))
  }

  static get observedAttributes() {
    return ["base-url"];
  }

  attributeChangedCallback(name, oldValue, newValue) {
    if (oldValue !== newValue) {
      switch (name) {
        case "base-url":
          this.baseUrl = newValue
          break
      }
    }
  }

})
