import Script from 'src/client/vivide/vividescript.js';
import { scriptFolder, stepFolder, applicationFolder } from 'src/client/vivide/utils.js';

let autoGenerated = /(.*-template\.js(on)?$)|(.md?$)/;
const folders = [scriptFolder, stepFolder, applicationFolder];

export let allFiles = () => Promise.all(folders.map(folderURL => 
     lively.files.statFile(folderURL).then(j => 
      JSON.parse(j).contents
       .filter(({ type }) => type === 'file')
       .filter(({name}) => !autoGenerated.test(name))
       .map(({name}) => folderURL+name))
));

export async function createView(content, createEditor = false, createDependents = false, name){
  const componentWindow = await lively.openComponentInWindow('vivide-view');
  if (!createDependents) componentWindow.input = JSON.parse(content.inputs);
  const script = await Script.fromJSON(content.script,componentWindow);
  componentWindow.myCurrentScript = script;
  const widget = await lively.create(content.widget);
  widget.setView(componentWindow);
  await componentWindow.scriptGotUpdated();
  if(createEditor){
    const scriptEditor = await componentWindow.createScriptEditor();
    scriptEditor.setView(componentWindow);
    await scriptEditor.setScript(script);
  }
  if(createDependents){
    componentWindow.applicationName = name;
    const inputs = await Promise.all(content.inputSources.map(i => createView(i, false, true, name)));
    inputs.forEach(i => i.connectTo(componentWindow));
    const outputs = await Promise.all(content.outputs.map(o => createView(o, false, true, name)));
    outputs.forEach(o => componentWindow.connectTo(o));
    if(content.inputs && content.inputs && content.inputs.length !== 0){
      componentWindow.newDataFromUpstream(content.inputs);
    }
  }
  return componentWindow;
}

export async function setScript(url, view){
  const config = await fetch(url).then(f => f.json());
  const widget = await lively.create(config.widget);
  widget.setView(view)
  const script = await Script.fromJSON(config.script, view);
  view.myCurrentScript = script;
  const scriptEditor = await view.createScriptEditor();
  scriptEditor.setView(view);
  await scriptEditor.setScript(script);
  await view.scriptGotUpdated();
}

export async function openFile(file, createEditor, createDependents){
  const filepath = file.split('/');
  const content = JSON.parse(await lively.files.loadFile(file));
  const name = filepath[filepath.length-1].split('.')[0];
  await createView(content, createEditor, createDependents, name);
}

function replace(obj, key, rep = true){
   return typeof obj[key] === "undefined" ? rep ? `No ${key} provided` : undefined : obj[key]
}

export function getDetails(file, rep = false) {
  return fetch(file)
    .then(r => r.json())
    .then(j => ({
      scheme: replace(j, "inScheme", true),
      description: replace(j, "description", rep)
    }))
}

function calcScore(scheme, toFit){
  if(!(scheme && toFit)) return 0;
  if(scheme === toFit) return 100;
  let score = 0;
  Object.keys(toFit).forEach(key => {
    if(scheme[key]){
      score++;
      if(toFit[key]===scheme[key]){
        score++;
      }
    }
  });
  return score/Object.keys(toFit).length
}

export async function getMatches(scheme, search){
  const all = await allFiles();
  const details  = await Promise.all(all[0].map(f => getDetails(f).then(d => ({name: f, details: d}))));
  return details
          .filter(f => search ? f.name.includes(search) : true)
          .sort((a, b) => calcScore(
              JSON.parse(scheme),
              b.details.scheme
            )-calcScore(
              JSON.parse(scheme),
              a.details.scheme
          ))
          .filter((_, i) => i<3)
          .map(f => ({
            name: f.name.split('/')[f.name.split('/').length-1].split('.')[0],
            url: f.name
          }))
    
}