<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Bowtie</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-Zenh87qX5JnK2Jl0vWa8Ck2rdkQ2Bzep5IDxbcnCeuOxjzrPF/et3URy9Bv1WTRi" crossorigin="anonymous">
  </head>

  <body>
    <nav class="navbar navbar-expand-lg sticky-top bg-light mb-4">
      <div class="container-fluid">
        <a class="navbar-brand" href="#">Bowtie</a>
        <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
          <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="navbarNav">
          <ul class="navbar-nav me-auto mb-2 mb-lg-0">
            <li class="nav-item">
              <a class="nav-link" href="#run-info">Run Info</a>
            </li>
            <li class="nav-item">
              <a class="nav-link" href="#summary">Summary</a>
            </li>
            <li class="nav-item">
              <a class="nav-link" href="#cases">Details</a>
            </li>
          </ul>
        </div>

        <a href="https://github.com/bowtie-json-schema/bowtie/" class="link-secondary">
          <span class="navbar-text">
            <small>Bowtie v{{ run_info.bowtie_version }}</small>
          </span>
        </a>
      </div>
    </nav>

    {% macro to_icon(valid) -%}
        {% if valid == True %}
          <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-check-circle-fill" viewBox="0 0 16 16">
            <path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zm-3.97-3.03a.75.75 0 0 0-1.08.022L7.477 9.417 5.384 7.323a.75.75 0 0 0-1.06 1.06L6.97 11.03a.75.75 0 0 0 1.079-.02l3.992-4.99a.75.75 0 0 0-.01-1.05z"/>
          </svg>
        {% elif valid == False %}
          <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-x-circle-fill" viewBox="0 0 16 16">
            <path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM5.354 4.646a.5.5 0 1 0-.708.708L7.293 8l-2.647 2.646a.5.5 0 0 0 .708.708L8 8.707l2.646 2.647a.5.5 0 0 0 .708-.708L8.707 8l2.647-2.646a.5.5 0 0 0-.708-.708L8 7.293 5.354 4.646z"/>
          </svg>
        {% else %}
          <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-exclamation-octagon" viewBox="0 0 16 16">
            <path d="M4.54.146A.5.5 0 0 1 4.893 0h6.214a.5.5 0 0 1 .353.146l4.394 4.394a.5.5 0 0 1 .146.353v6.214a.5.5 0 0 1-.146.353l-4.394 4.394a.5.5 0 0 1-.353.146H4.893a.5.5 0 0 1-.353-.146L.146 11.46A.5.5 0 0 1 0 11.107V4.893a.5.5 0 0 1 .146-.353L4.54.146zM5.1 1 1 5.1v5.8L5.1 15h5.8l4.1-4.1V5.1L10.9 1H5.1z"/>
            <path d="M7.002 11a1 1 0 1 1 2 0 1 1 0 0 1-2 0zM7.1 4.995a.905.905 0 1 1 1.8 0l-.35 3.507a.552.552 0 0 1-1.1 0L7.1 4.995z"/>
          </svg>
        {% endif %}
    {%- endmacro %}

    <div class="container p-4">

      <div class="card mx-auto mb-3 w-75" id="run-info">
        <div class="card-header">Run Info</div>

        <div class="card-body">
          <table class="table table-sm table-hover">
            <tr>
              <td>Dialect</td>
              <td>{{ run_info.dialect }}</td>
            </tr>
            <tr>
              <td>Ran</td>
              <td>
                <time datetime="{{ run_info.started }}" id="runStarted"></time>
              </td>
            </tr>
          </table>
        </div>
      </div>

      <div class="card mx-auto mb-3 w-75" id="summary">
        <div class="card-header">Summary</div>

        <div class="card-body">
          <table class="table table-sm table-hover">
            <thead class="table-light">
              <tr>
                <th colspan=2 rowspan=2 scope="col" class="text-center align-middle">implementation</th>
                <th colspan=1 class="text-center"><span class="text-muted">cases ({{ summary.total_cases }})</span></th>
                <th colspan=3 class="text-center"><span class="text-muted">tests ({{ summary.total_tests }})</span></th>
                <th colspan=1></th>
              </tr>

              <tr>
                <th scope="col" class="text-center">errors</th>

                <th scope="col" class="table-bordered text-center">failed</th>
                <th scope="col" class="table-bordered text-center">skipped</th>
                <th scope="col" class="table-bordered text-center">errors</th>

                <th scope="col"></th>
              </tr>
            </thead>

            <tbody class="table-group-divider">
              {% for implementation in summary.implementations %}
                {% set counts = summary.counts[implementation.image] %}
                <tr>
                  <th scope="row">
                    <a href="{{ implementation.homepage or implementation.issues }}">{{ implementation.name }}</a>
                    <small class="text-muted">{{ implementation.language }}</small>
                  </th>
                  <td>
                    <small class="font-monospace text-muted">{{ implementation.get("version", "") }}</small>
                  </td>

                  <td>{{ counts.errored_cases }}</td>

                  <td>{{ counts.failed_tests }}</td>
                  <td>{{ counts.skipped_tests }}</td>
                  <td>{{ counts.errored_tests }}</td>

                  <td>
                    <button type="button" class="btn btn-sm btn-primary" data-bs-toggle="modal" data-bs-target="#implementation-{{ loop.index }}-details">
                      Details
                    </button>
                  </td>
                </tr>
              {% endfor %}
            </tbody>

            <tfoot>
              <tr>
                <th scope="row" colspan=2>total</th>

                <td>{{ summary.errored_cases }}</td>

                <td>{{ summary.failed_tests }}</td>
                <td>{{ summary.skipped_tests }}</td>
                <td>{{ summary.errored_tests }}</td>
                <td></td>
              </tr>
            </tfoot>
          </table>

          {% if summary.did_fail_fast %}
            <div class="alert alert-warning" role="alert">
              This run failed fast, so some input cases may not have been run.
            </div>
          {% endif %}
        </div>
      </div>

      <div class="accordion pt-5" id="cases">
        {% for seq, description, schema, results in summary.case_results() %}
          <div class="accordion-item">

            <h2 class="accordion-header" id="case-{{ seq }}-heading">
              <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#case-{{ seq }}" aria-expanded="false" aria-controls="case-{{ seq }}">
                <a href="#" data-bs-toggle="tooltip" data-bs-html="true" data-bs-title='<pre>{{ schema | tojson(indent=2) }}</pre>'>
                  {{ description }}
                </a>
              </button>
            </h2>

            <div id="case-{{ seq }}" class="accordion-collapse collapse" aria-labelledby="case-{{ seq }}-heading" data-bs-parent="#cases">
              <div class="accordion-body">
                <table class="table table-hover">
                  <thead>
                    <tr>
                      <td scope="col">test</td>
                      {% for implementation in summary.implementations %}
                        <td class="text-center" scope="col">
                          {{ implementation.name }}
                          <small class="text-muted">{{ implementation.language }}</small>
                        </td>
                      {% endfor %}
                    </tr>
                  </thead>

                  {% for test, test_results in results %}
                    <tr>
                      <td>
                        <a href="#" data-bs-toggle="tooltip" data-bs-html="true" data-bs-title='<pre>{{ test.instance | tojson(indent=2) }}</pre>'>{{ test.description }}</a>
                      </td>
                      {% for implementation in summary.implementations %}
                        {% set implementation_result, incorrect = test_results.get(implementation.image, ({"valid": None}, True)) %}
                        {% if incorrect == "skipped" %}
                          <td class="text-center text-bg-warning">
                            {{ to_icon(False) }}
                          </td>
                        {% else %}
                          <td class="text-center {% if incorrect %}text-bg-danger{% elif implementation_result.valid != True and implementation_result.valid != False %}text-bg-warning{% endif %}">
                            {{ to_icon(implementation_result.valid) }}
                          </td>
                        {% endif %}
                      {% endfor %}
                    </tr>
                  {% endfor %}
                </table>
              </div>
            </div>

          </div>
        {% endfor %}
      </div>

    </div>

    {% for implementation in summary.implementations %}
      <div class="modal fade" id="implementation-{{ loop.index }}-details" tabindex="-1" aria-labelledby="implementation-{{ loop.index }}-details-label" aria-hidden="true">
        <div class="modal-dialog modal-fullscreen">
          <div class="modal-content">
            <div class="modal-header">
              <h1 class="modal-title fs-5" id="implementation-{{ loop.index }}-details-label">
                {{ implementation.name }}
                <small class="text-muted">{{ implementation.language }}</small>
              </h1>
              <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
            </div>
            <div class="modal-body">
              <div class="row row-cols-1 row-cols-md-2 g-4">
                {% for seq, description, schema, results in summary.case_results() %}
                    {% for test, test_results in results %}
                        {% set implementation_result, incorrect = test_results.get(implementation.image, ({"valid": None}, True)) %}
                        {% if incorrect == "skipped" %}
                          <div class="col">
                            <div class="card border-warning mb-3">
                              <div class="card-body">
                                <h5 class="card-title">{{ description }}</h5>
                                <p class="card-text">{{ test.description }}</p>
                              </div>
                              <div class="card-footer text-muted text-center">
                                {{ implementation_result }}
                              </div>
                            </div>
                          </div>
                        {% elif incorrect %}
                          <div class="col">
                            <div class="card border-danger mb-3">
                              <div class="card-body">
                                <h5 class="card-title">{{ description }}</h5>
                                <p class="card-text">{{ test.description }}</p>
                              </div>
                              <div class="card-footer text-muted text-center">
                                Unexpectedly {{
                                  "valid" if implementation_result.valid == True
                                          else "invalid" if implementation_result.valid == False
                                          else "errored" }}
                              </div>
                            </div>
                          </div>
                        {% endif %}
                    {% endfor %}
                {% endfor %}
              </div>
            </div>
            <div class="modal-footer">
              <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
            </div>
          </div>
        </div>
      </div>
    {% endfor %}

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-OERcA2EqjJCMA+/3y+gxIOqMEjwtxJY7qPCqsdltbNJuaOe923+mo//f6V8Qbsw3" crossorigin="anonymous"></script>
    <script>
      const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]')
      const tooltipList = [...tooltipTriggerList].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl))
    </script>

    <script>
      var ago = (Date.now() - Date.parse("{{ run_info.started }}")) / 1000;
      var agoUnits = 'seconds';
      if (ago > 60) {
        ago /= 60; agoUnits = 'minutes';
        if (ago > 60) {
          ago /= 60; agoUnits = 'hours';
          if (ago > 24) {
            ago /= 24; agoUnits = 'days';
            if (ago > 7) { ago /= 7; agoUnits = 'weeks'; }
          }
        }
      };
      document.getElementById('runStarted').textContent = new Intl.RelativeTimeFormat(
        'en', {numeric: 'auto'}
      ).format(-Math.round(ago), agoUnits);
    </script>
  </body>
</html>
