class CCPExecutionMonitor extends HTMLElement {
  
  #boot = null;
  #rootdoc = null;
  #serviceurl = null;
  #broadcasturl = null;
  #executions = [];
  #socket = null;
  
  constructor(){
    super()
    this.#boot = document.querySelector("d4s-boot-2")
    this.#rootdoc = this.attachShadow({ "mode" : "open"})
    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.connectBroadcast()
  }
  
  connectedCallback(){
    this.#rootdoc.innerHTML = this.render()
  }
  
  render(){
    return `
      <template id="EXECUTIOM_LIST_TEMPLATE">
        <ol name="ccp_execution_list" class="ccp-execution-list list-group">
          <li class="ccp-execution-item list-group-item" style="border: none">
            <details open>
              <summary>
                <h5 style="display:inline"></h5>
                <span name="status" class="badge"></span>
              </summary>
              <p name="message" class="status-message font-weight-light font-italic" style="margin-top:revert"></span>
              <ul class="list-group">
                <li class="list-group-item" style="border: none"></li>
              </ul>
            </details>
          </li>
        </ol>
      </template>
      <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">
      <ol name="ccp_execution_list" style="display:none"></ol>
    `
  }
  
  addExecution(execution){
    this.#executions.push(execution)
    this.refreshExecution(execution)
  }
  
  refreshExecution(execution){
    this.#boot.secureFetch(`${this.#serviceurl}/executions/${execution.jobID}`).then(reply =>{
      if(reply.status === 200) return reply.json();
      else throw "Unable to load job links"
    }).then(data=>{
      execution.links = data
      BSS.apply(this.execution_list_bss, this.#rootdoc)
    }).catch(err=>{ console.error(err)})
  }
  
  connectBroadcast(){
    this.#socket = new WebSocket(this.#broadcasturl + "/executions");
    this.#socket.onmessage = event=>{
      const data = JSON.parse(event.data)
      let exec = this.#executions.filter(e=>e.jobID === data.jobID)[0]
      if(exec){
        exec.events.push(data)
        if(!exec.self) exec.self = data.links[0].href;
        this.refreshExecution(exec)
      }
    }
    window.setInterval( ()=>this.#socket.send("ping"), 30000)
  }
  
  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))
  }
  
  execution_list_bss = {
    template : "#EXECUTIOM_LIST_TEMPLATE",
    target : "ol[name=ccp_execution_list]",
    in : ()=>{ return {executions : this.#executions} },
    recurse:[
      {
        target : "li",
        in : (e,d)=>d.executions,
        apply: (e,d)=>{
          if(d.events && d.events.length > 0){
            e.alt = e.title = (new Date(d.events[d.events.length - 1].updated)).toLocaleString() 
          }
        },
        recurse : [
          {
            target : "h5",
            apply : (e,d)=>{
              e.textContent = d.method
            }
          },
          {
            target : "span[name=status]",
            apply : (e,d)=>{
              if(d.events && d.events.length > 0){
                const status = d.events[d.events.length - 1].status
                e.textContent = status
                if (status === "running") e.classList.add("badge-primary");
                else if (status === "successful") e.classList.add("badge-success");
                else if (status === "failure") e.classList.add("badge-danger");
                else e.classList.add("badge-secondary");
              }
            }
          },
          {
            target : ".status-message",
            apply : (e,d)=>{
              if(d.events && d.events.length > 0){
                e.textContent = d.events[d.events.length - 1].message 
              }
            }
          },
          {
            target : "ul",
            recurse : [
              {
                target : "li",
                "in" : (e,d)=>{
                  return d.links.map(l=>{ 
                    return { href : this.#serviceurl + "/executions/" + d.jobID + "/" + l.path, path : l.path} 
                  })
                },
                on_click : ev=>{
                  const href = ev.currentTarget.bss_input.data.href
                  const name = ev.currentTarget.bss_input.data.path
                  this.download(href, name)
                },
                apply : (e,d)=>{
                  e.innerHTML = `<a href="${d.href}" onclick="event.preventDefault()">${d.path}</a>`
                }
              }
            ]
          }
        ]
      }
    ]
  }
}
window.customElements.define('d4s-ccp-executionmonitor', CCPExecutionMonitor);
