class CCPInfrastructureList extends HTMLElement{
  
  #boot;
  #socket;
  #infrastructures;
  #runtimes;
  #rootdoc;
  
  #style = `
   <link rel="stylesheet" href="https://cdn.dev.d4science.org/ccp/css/common.css"></link>
   <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
  <style>
    .ccp_infrastructure_controller{
      
    }
    .ccp_toolbar_button {
      padding: .3rem;
      line-height: 1rem;
    }
    .ccp_infrastructure_list{
      list-style:none;
      padding-left: 1rem;
      user-select: none;
    }
    .ccp_infrastructure_item{
      padding: .3rem 0 .3rem 0;
    }
    .ccp_infrastructure_list .lxd{
      background-color: #dd4814;
    }
    .ccp_infrastructure_list .docker{
      background-color: #2496ed;
    }
    .ccp_runtime_list{
      list-style:none;
      padding-left: 1rem;
    }
    .ccp_runtime_item{
      padding: .3rem 0 .3rem 0;
    }
    .ccp_instance_list{
      list-style:none;
    }
    .ccp_instance_item{
      padding: 0.3rem 0 0.3rem 1rem;
      font-style: italic;
      color: 888888;
    }
  </style>
  `;
  
  #serviceurl; 
  #broadcasturl;
  
  constructor(){
    super()
    this.#boot = document.querySelector("d4s-boot-2")
    this.#serviceurl = this.getAttribute("serviceurl")
    this.#broadcasturl = this.getAttribute("broadcasturl")
    if(!this.#broadcasturl){
      this.#broadcasturl = this.#serviceurl.replace(/^http/, "ws")
    }
    this.#broadcasturl = this.#broadcasturl + "/ws/notification"
    this.#rootdoc = this.attachShadow({ "mode" : "open"})
  }

  connectedCallback(){
    this.connectBroadcast()
    this.fetchInfrastructures()  
  }

  fetchInfrastructures(){
    const prom1 = this.#boot.secureFetch(this.#serviceurl + "/infrastructures/cache").
      then(resp=>{
        if(resp.status !== 200) throw "Unable to fetch infrastructure cache";
        return resp.json()
      }).then(data=>{
        this.#infrastructures = data
        this.showList()
      }).catch(err=>{
        alert(err)
      })
    
    /*const prom2 = this.#boot.secureFetch(this.#serviceurl + "/runtimes").
      then(resp=>{
        if(resp.status !== 200) throw "Unable to fetch runtimes";
        return resp.json()
      }).then(data=>{
        this.#runtimes = data
      }).catch(err=>{
        alert(err)
      })
      
    Promise.all([prom1, prom2]).then(results=>{
      this.showList()
    })*/    
  }
  
  refreshInfrastructures(){
    this.#boot.secureFetch(this.#serviceurl + "/infrastructures/cache", { method : "HEAD"})
  }
  
  showList(){
    if(this.getAttribute("render") !== "true") {
      this.#rootdoc.innerHTML = ""
      return;
    }
    this.#rootdoc.innerHTML = `
      <div class="ccp_infrastructure_controller">
        ${this.#style}
        ${this.toolbar()}
        <ul class="ccp_infrastructure_list">
          ${this.showInfrastructures()}
        </ul>
      </div>      
    `
    this.#rootdoc.querySelector(".ccp_infrastructure_toolbar").addEventListener("click", ev=>{
      const evname = ev.target.getAttribute("name")
      switch(evname){
        case "refresh":
          this.refreshInfrastructures();
          break;
      }
    })
    
    const forms = Array.prototype.slice.call(this.#rootdoc.querySelectorAll(".ccp_runtime_builder"))
    forms.forEach(f=>{
      f.addEventListener("submit", ev=>{
        ev.stopPropagation()
        ev.preventDefault()
        const sel = ev.target.querySelector("select")
        let url = ev.target.action + sel.value
        this.#boot.secureFetch(url, { method : ev.target.method})
        return false
      })
    })
  }
  
  toolbar(){
    return `
      <div class="ccp_infrastructure_toolbar">
        <button name="refresh" class="btn btn-primary ccp_toolbar_button" title="Refresh">&#8634;</button>
      </div>
    `
  }
  
  showInfrastructures(){
    return this.#infrastructures.map(i => {
      return `
        <li class="ccp_infrastructure_item" title="${i.description}">
          <details>
            <summary>
              <span>${i.name}</span>
              ${this.showAge(i)}
              ${this.showType(i)}
            </summary>
            ${this.showDeployableRuntimes(i)}
            <ul class="ccp_runtime_list">
              ${this.showRuntimes(i)}
            </ul>
          </details>
        </li>
      `
    }).join("\n")
  }
  
  showDeployableRuntimes(infra){
    const alreadydeployed = infra.runtimes.map(r=>r["descriptor-id"])
    const options = infra.available_runtimes.filter(r=>{
      return infra.type === r.type && alreadydeployed.indexOf(r.id) === -1
    }).map(r=>{
      return `<option value="${r.name}" title="${r.description}">${r.name}</option>`
    }).join("\n")
    return `
      <div style="padding-left:1rem">
        <form class="ccp_runtime_builder" action="${this.#serviceurl}/infrastructures/${infra.id}/runtime/" method="POST">
          <select name="runtime_selector" style="padding:.2rem;margin:5px;border:none">
            ${options}
          </select>
          <button type="submit" class="btn btn-primary ccp_toolbar_button" title="Deploy runtime">+</button>
        </form>
      </div>
    `
  }
  
  showRuntimes(infra){
    return infra.runtimes.map(r =>{
      return `
        <li class="ccp_runtime_item" title="${r.name}">
          <details>
            <summary>${r.name}</summary>
            <ul class="ccp_instance_list">
              ${this.showInstances(r)}
            </ul>
          </details>
        </li>
      `
    }).join("\n")
  }
  
  showInstances(runtime){
    return runtime.instances.map(i =>{
      return `
        <li class="ccp_instance_item">${i.name}</li>
      `
    }).join("\n")
  }
  
  showAge(infra){
    const age = Math.floor(((new Date()) - (new Date(infra.date))) / 3600000)
    var cls = "badge-success"
    var agetext = "fresh"
    if(age > 24){
      cls = "badge-warning";
      agetext = "aged"
    } else if (age > 72){
      cls = "badge-secondary"
      agetext = "old"
    } 
    return `<span class="badge ${cls}" name="age" title="${age} hours">${agetext}</span>`
  }
  
  showType(infra){ 
    return `<span class="badge badge-secondary ${infra.type}" title="${infra.type}">${infra.type}</span>`
  }
  
  connectBroadcast(){
    this.#socket = new WebSocket(this.#broadcasturl + "/infrastructures");
    this.#socket.onmessage = event=>{
      this.fetchInfrastructures()
    }
    window.setInterval( ()=>this.#socket.send("ping"), 30000)
  }
  
  getCompatibleRuntimes(rts){
    const available = Object.keys(this.#infrastructures).reduce((acc, i) => {
      const compatiblerts = this.#infrastructures[i].runtimes.
        filter(r=>rts.indexOf(r["descriptor-id"]) >= 0).
        map(cr=>{ return { runtime : cr, infrastructure : this.#infrastructures[i] } })
      return acc.concat(compatiblerts)
    }, [])
    return available
  }
}

window.customElements.define('d4s-ccp-infrastructurelist', CCPInfrastructureList);
