<!DOCTYPE html>
<html lang="en">
<head>
  <title>GraphiQL</title>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <meta name="robots" content={% block robots %}"noindex"{% endblock %} />
  <link rel="shortcut icon" type="image/png" href="data:image/png;base64,iVBORw0KGgo=" />

  <link rel="stylesheet" href="{{ graphiql_css }}" integrity="{{ graphiql_css_integrity }}" crossorigin="anonymous" />
  <link rel="stylesheet" href="{{ explorer_css }}" integrity="{{ explorer_css_integrity }}" crossorigin="anonymous" />

{% block style %}
  <style>
    body {
      margin: 0;

      @media (prefers-color-scheme: dark) {
        background-color: hsl(219, 28%, 18%);
      }
      @media (prefers-color-scheme: light) {
        background-color: hsl(0, 0%, 100%);
      }
    }
    #graphiql {
      height: 100dvh;
    }
  </style>
{% endblock %}

  <script type="importmap">
{{ importmap | safe }}
  </script>

{% block js %}
  <script type="module">
    /*
    * Based on this example: https://github.com/graphql/graphiql/blob/54ed55cbb75c1dd5b38f7afa6a1a14c2b58ed0ab/examples/graphiql-cdn/index.html
    * To update, see the latest version: https://github.com/graphql/graphiql/blob/main/examples/graphiql-cdn/index.html
    * */

    import React from 'react';
    import ReactDOM from 'react-dom/client';
    import { GraphiQL, HISTORY_PLUGIN } from 'graphiql';
    import { createGraphiQLFetcher, StorageAPI } from '@graphiql/toolkit';
    import { explorerPlugin } from '@graphiql/plugin-explorer';
    import 'graphiql/setup-workers/esm.sh';

    const storage = new StorageAPI();

    const currentURL = new URL(window.location.href)
    const params = new URLSearchParams(currentURL.search);

    if (!params.has("document")) {
      const val = storage.get("query");
      if (val) {
        params.set("document", val);
      }
    }

    if (!params.has("variables")) {
      const val = storage.get("variables");
      if (val) {
        params.set("variables", val);
      }
    }

    if (!params.has("headers")) {
      const val = storage.get("headers");
      if (val) {
        params.set("headers", val);
      }
    }

    function updateHistory() {
      params.sort();
      const search = params.toString();
      if (search === "") {
        history.replaceState(null, null, currentURL.pathname);
      } else {
        history.replaceState(null, null, "?" + search);
      }
    }

    /**
     * @param {string|null} data
     * @returns {Record<string, string> | null}
     * */
    function parseStringRecord(data) {
      if (data === null) {
        return null;
      }

      let obj;
      try {
        obj = JSON.parse(data);
      } catch (e) {
        return null;
      }

      if (
        typeof obj !== "object"
        || Array.isArray(obj)
        || Object.getOwnPropertySymbols(obj).length > 0
        || !Object.getOwnPropertyNames(obj).every(prop => typeof obj[prop] === "string")
      ) {
        return null;
      }

      return obj;
    }

    /**
     * @param {Record<string, string>} obj
     * @param {boolean} compact
     * @returns {string}
     * */
    function formatStringRecord(obj, compact = false) {
      return JSON.stringify(obj, null, compact ? 0 : 2);
    }

    /**
     * @param {string} key
     * @param {string} value
     * @param {string[]} emptyValues
     * */
    function updateParam(key, value, emptyValues) {
      if (emptyValues.includes(value)) {
        params.delete(key);
      } else {
        params.set(key, value);
      }
    }

    updateHistory();

    currentURL.pathname = "/{{ http_path }}"
    const url = currentURL.href;

    currentURL.protocol = location.protocol.replace(/^http/, 'ws');
    currentURL.pathname = "/{{ ws_path }}";
    const subscriptionUrl = currentURL.href;

    const defaultHeaders = {}
    const csrftoken = document.querySelector("[name=csrfmiddlewaretoken]").value;
    if (csrftoken) defaultHeaders['X-CSRFToken'] = csrftoken;

    function App() {
      const initialGraphQLDocument = params.get("document")
      const initialVariables = parseStringRecord(params.get("variables"))
      const initialHeaders = parseStringRecord(params.get("headers"))

      const [graphQLDocument, setGraphQLDocument] = React.useState(initialGraphQLDocument);
      const [variables, setVariables] = React.useState(initialVariables ? formatStringRecord(initialVariables) : null);
      const [headers, setHeaders] = React.useState(initialHeaders ? formatStringRecord(initialHeaders) : null);

      /**
       * @param {string} newGraphQLDocument
       * */
      function onEditQuery(newGraphQLDocument) {
        const value = newGraphQLDocument.trim();

        setGraphQLDocument(value);
        updateParam("document", value, [""]);
        updateHistory();
      }

      /**
       * @param {string} newVariables
       * */
      function onEditVariables(newVariables) {
        if (newVariables.trim() === "") {
          setVariables(null);
          updateParam("variables", "", [""]);
          updateHistory();
        }

        const value = parseStringRecord(newVariables);
        if (value === null) {
          return;
        }

        setVariables(formatStringRecord(value));
        updateParam("variables", formatStringRecord(value, true), ["{}"]);
        updateHistory();
      }

      /**
       * @param {string} newHeaders
       * */
      function onEditHeaders(newHeaders) {
        if (newHeaders.trim() === "") {
          setHeaders(null);
          updateParam("headers", "", [""]);
          updateHistory();
        }

        const value = parseStringRecord(newHeaders);
        if (value === null) {
          return;
        }

        setHeaders(formatStringRecord(value));
        updateParam("headers", formatStringRecord(value, true), ["{}"]);
        updateHistory();
      }

      return React.createElement(GraphiQL, {
        fetcher: createGraphiQLFetcher({ url, subscriptionUrl, headers: defaultHeaders }),
        plugins: [HISTORY_PLUGIN, explorerPlugin()],
        initialQuery: graphQLDocument,
        initialVariables: variables,
        initialHeaders: headers,
        onEditQuery: onEditQuery,
        onEditVariables: onEditVariables,
        onEditHeaders: onEditHeaders,
        defaultEditorToolsVisibility: true,
        inputValueDeprecation: true,
        isHeadersEditorEnabled: true,
        shouldPersistHeaders: true,
      });
    }

    const container = document.getElementById('graphiql');
    const root = ReactDOM.createRoot(container);
    root.render(React.createElement(App));
  </script>
{% endblock %}

</head>
<body>
  <div id="graphiql"></div>
  {% csrf_token %}
</body>
</html>
