<!DOCTYPE html>
<html>

<head>
  <link id="favicon" rel="icon" type="image/x-icon" href="{{{__favicon__}}}" />
  <link type="text/css" rel="stylesheet"
    href="https://cdn.jsdelivr.net/gh/supervisely/js-bundle@{{{js_bundle_version}}}/sly-app-widgets-{{{js_bundle_version}}}.bundle.css" />
  <style>
    #app-global-loading-icon {
      background: white;
      border-radius: 50%;
      width: 75px;
      height: 75px;
      padding: 10px;
      margin: 10px 0;
      position: relative;
    }

    @keyframes app-loading-rotation {
      0% {
        transform: rotate(0deg);
      }

      100% {
        transform: rotate(360deg);
      }
    }

    #app-global-loading-icon::after {
      content: "";
      box-sizing: border-box;
      position: absolute;
      left: 0;
      top: 0;
      transform: translate(-50%, -50%);
      width: 95px;
      height: 95px;
      border-radius: 50%;
      border: 3px solid transparent;
      border-bottom-color: #fb4481;
      animation: app-loading-rotation 1s linear infinite;
    }

    #app-global-loading-icon>img {
      width: 75px;
      border-radius: 50%;
    }

    .extended-app-header .app-session-header-widget>div {
      margin-bottom: 0;
      padding-left: 20px;
    }

    .app-session-header-solid {
      background: white;
      box-shadow: 0 5px 10px #0000000d;
      border-bottom: 1px solid #dfe2e8;
      position: relative;
    }

    .el-input-number--mini .el-input-number__decrease,
    .el-input-number--mini .el-input-number__increase {
      height: 20px !important;
      width: 20px !important;
      line-height: 18px !important;
      font-size: 12px !important;
      min-width: 20px !important;
      padding: 0 !important;
    }

    .el-input-number--mini .el-input-number__decrease {
      right: 20px !important;
    }

    .el-input-number--mini .el-input-number__decrease i,
    .el-input-number--mini .el-input-number__increase i {
      font-size: 10px !important;
      line-height: 18px !important;
    }
  </style>
  <title>{{{app_name}}}</title>
</head>

<body style="background-color: #f4f7fe">
  <center>
    <div id="app-global-loading-icon">
      <img src="https://app.supervisely.com/loading.gif" />
    </div>
  </center>
  {% if __webpy_script__ %}
  <script src="https://cdn.jsdelivr.net/pyodide/{{{pyodide_version}}}/full/pyodide.js"></script>
  {% endif %}
  <script src="https://cdn.jsdelivr.net/npm/socket.io-client@2.0.4/dist/socket.io.js"></script>
  <script
    src="https://cdn.jsdelivr.net/gh/supervisely/js-bundle@{{{js_bundle_version}}}/sly-app-widgets-{{{js_bundle_version}}}.bundle.js"></script>
  <script type="module"
    src="https://cdn.jsdelivr.net/gh/supervisely-ecosystem/supervisely-app-frontend-js@v{{{js_frontend_version}}}/SlyApp.js"></script>
  <script>
    window.parent.postMessage('{ "showHeader": false }', "*");
  </script>

  {% for scripts in __widget_scripts__.values() %} {% if scripts is string %}
  <script src="{{{ scripts }}}"></script>
  {% else %} {% for scripts in scripts %}
  <script src="{{{ scripts }}}"></script>
  {% endfor %} {% endif %} {% endfor %}

  <div id="sly-app">
    <sly-app>
      <template v-slot="{ post, state, data, session, isStaticVersion, publicApiInstance }">
        <div
          :style="{'padding': `${state.app_body_padding} ${state.app_body_padding} 0`, 'display': 'flex', 'flex-direction': 'row', 'place-items': 'center'}"
          {% if __app_session_info_solid__ %} {% if __app_session_info_extra_content__ %}
          class="app-session-header-solid extended-app-header" {% else %} class="app-session-header-solid" {% endif %}
          {% else %} {% if __app_session_info_extra_content__ %} class="extended-app-header" {% endif %} {% endif %}>
          {% if __show_header__ %}
          <sly-app-header v-if="session" :session="session" :data="data" :state="state"></sly-app-header>
          {% endif %}
          {% if __app_session_info_extra_content__ %}
          {{{__app_session_info_extra_content__}}} {% endif %}
        </div>
        <div :style="{'padding': `0 ${state.app_body_padding} ${state.app_body_padding}`}" {% if __webpy_script__
          %}v-loading="state.app_initializing" {% endif %}>
          {% if __no_html_mode__ %} {% include 'no_html_main.html' %} {% else
          %} {% include 'main.html' %} {% endif %} {% include
          'dialog_window.html' %}
        </div>
      </template>
    </sly-app>
  </div>

  <!-- Offline session styles fix -->
  <script>
    let resizeCounter = 0;
    let resizeInterval = setInterval(() => {
      resizeCounter += 1;
      window.dispatchEvent(new Event("resize"));

      if (resizeCounter > 3) {
        clearInterval(resizeInterval);
      }
    }, 2000);

    let pyodide = null;
    let mainScriptTxt = null;

    async function loadDependency(pyodide, url, modulePath) {
      const pythonCode = await fetch(url).then(response => response.text());
      const FS = pyodide.FS;
      FS.writeFile(modulePath, pythonCode);
    }

    async function setupAndImportPythonPackage(url, packageName) {
      const FS = pyodide.FS;

      const response = await fetch(url);
      if (!response.ok) {
        throw new Error(`Failed to fetch TAR file: ${response.statusText}`);
      }
      const tarData = await response.arrayBuffer();

      const tarPath = `${packageName}.tar`;
      FS.writeFile(tarPath, new Uint8Array(tarData));

      const extractTo = `./`;
      const pythonCode = `
import tarfile
import sys
import os

tar_path = "${tarPath}"
extract_to = "${extractTo}"

os.makedirs(extract_to, exist_ok=True)
with tarfile.open(tar_path, "r:") as tar_ref:
    tar_ref.extractall(extract_to)
`;
      await pyodide.runPythonAsync(pythonCode);

      console.log(`Package ${packageName} extracted to ${extractTo}`);
    }

    const allowedActions = new Set([
      {% if events_subscribed %}
    {% for event in events_subscribed %}
    '{{{ event }}}',
      {% endfor %}
    {% endif %}
    ]);
    let unSubStoreAction = null;

    function subToStoreAction() {
      if (unSubStoreAction) {
        unSubStoreAction();
      }

      const store = window.slyApp.store;

      unSubStoreAction = store.subscribeAction((action) => {
        if (!allowedActions.has(action.type)) return;
        runPythonScript(action);
      });

      console.log("Subscribed to store actions");
    }

    async function loadMainPythonScript() {
      pyodide = await loadPyodide();
      await pyodide.loadPackage("micropip");
      const micropip = pyodide.pyimport("micropip");
      await micropip.install(["typing_extensions == 4.8"]) // needed for fastapi
      await micropip.install(["ssl"]) // needed for fastapi
      await micropip.install(["fastapi"]) // needed for sdk

      {% if pyodide_requirements %}
      {% for req in pyodide_requirements %}
      await micropip.install(["{{{ req | safe }}}"])
      {% endfor %}
      {% endif %}

      await setupAndImportPythonPackage("./sly_sdk.tar", "sly_sdk") // temporary solution
      await setupAndImportPythonPackage("./src.tar", "src")
      {% if src_modules %}
      {% for module in src_modules %}
      await loadDependency(pyodide, "./{{{ module }}}", "{{{ module }}}")
      {% endfor %}
      {% endif %}

      mainScriptTxt = await fetch("./{{{ __webpy_script__ }}}").then((response) => response.text());
      python_code = `
from sly_sdk.webpy import WebPyApplication
app = WebPyApplication()
state = app.state
if state.get("app_initializing", False) == True:
    state["app_initializing"] = False
    state.send_changes()
`
      const fn = pyodide.runPython(python_code);
      if (typeof fn === "function") {
        const newParams = params.map(p => pyodide.toPy(p));
        result = fn(...newParams);
      } else {
        result = fn;
      }
      {% if events_subscribed %}

      subToStoreAction();

      {% endif %}
    }

    let initPromise = null;

    async function runPythonScript(...params) {
      if (initPromise) {
        await initPromise;
        initPromise = null;
      }

      let result;
      const timeStart = performance.now();

      const fn = pyodide.runPython(mainScriptTxt);
      if (typeof fn === "function") {
        const newParams = params.map(p => pyodide.toPy(p));
        result = fn(...newParams);
      } else {
        result = fn;
      }

      const timeEnd = performance.now();
      console.log("Web Python script executed in", timeEnd - timeStart, "ms");

      return result;
    }

    const runPythonScriptThrottled = _.throttle(runPythonScript, 50);
    {% if __webpy_script__ %}
    initPromise = loadMainPythonScript();
    {% endif %}
  </script>
  <!-- Hot reload script -->
  {% if HOTRELOAD %} {{{ hot_reload.script(url_for('hot-reload')) | safe }}}
  {% endif %}
</body>

</html>