const html = (v) => { return v[0] };

export const renderer = {
  props: ['stack'],
  setup(props) {

  },
  template: html`
  <Suspense>
    <template v-for="states, i in stack">
      <component @keydown.esc.stop="states[states.length-1].reject(-1)" v-if="states.length > 0" :is="states[states.length-1].component" :stack="stack" v-bind="states[states.length-1].properties" @resolve="(e) => states[states.length-1].resolve(e)" @reject="(e) => states[states.length-1].reject(e)" :active="stack.length-1 == i"></component>
    </template>
  </Suspense>
  `
}

function reGet(stack) {
  return safePromise(new Promise(function(resolve, reject) {
    const lastState = stack[stack.length-1];
    lastState[lastState.length-1].resolve = resolve;
    lastState[lastState.length-1].reject = reject;
  }));
}

export function popLastElem(stack) {
  const elem = stack[stack.length-1].pop();
  if (stack[stack.length-1].length == 0) {
    stack.pop();
  }
  return elem;
}

function safePromise(promise) {
  return promise.then(data => [ data, undefined ]).catch(error => [ null, error != undefined ? error : -1 ]);
}

export function overlayAndGet(component, properties, stack, reGetFlag=false) {
  if (reGetFlag) return reGet(stack);
  properties["stack"] = stack;
  return safePromise(new Promise(function(resolve, reject) {
    stack.push([{
      "component": component,
      "properties": properties,
      "resolve": resolve,
      "reject": reject
    }])
  }));
}

export function replaceAndGet(component, properties, stack, reGetFlag=false) {
  if (reGetFlag) return reGet(stack);
  properties["stack"] = stack;
  return safePromise(new Promise(function(resolve, reject) {
    stack[stack.length-1].push({
      "component": component,
      "properties": properties,
      "resolve": resolve,
      "reject": reject
    })
  }));
}


export async function overlayAndPop(component, properties, stack){
  const ret = await overlayAndGet(component, properties, stack);
  popLastElem(stack);
  return ret;
}

export async function replaceAndPop(component, properties, stack){
  const ret = await replaceAndGet(component, properties, stack);
  popLastElem(stack);
  return ret;
}


export const powerStateMachine = async (stateMachine, stack, initState=0, initInput=undefined) => {
  let stateHistory = [initState];
  let resultHistory = [initInput];
  let reGet = false;
  let newState, newResult;
  while (stateHistory[stateHistory.length-1] != undefined) {
    const state = stateHistory[stateHistory.length-1];
    const result = resultHistory[resultHistory.length-1];
    [newState, newResult] = await stateMachine[state](result, reGet);
    if (newState == -1){
      reGet = true;
      stateHistory.pop();
      resultHistory.pop();
      if (newResult != undefined) {
        resultHistory[resultHistory.length-1] = newResult;
      }
    } else if (newState == state){
      reGet = true;
      resultHistory[resultHistory.length-1] = newResult;
    } else if (newState == undefined) {
      return newResult;
    } else {
      reGet = false;
      stateHistory.push(newState);
      resultHistory.push(newResult);
    }
  }
}