#!/usr/bin/env bash
# DESCRIPTION: Verilator: CI script for 'pages.yml', builds the GitHub Pages
#
# SPDX-FileCopyrightText: 2025 Geza Lore
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0

# This scipt build the content of the GitHub Pages for the repository.
# Currently this hosts code coverage reports, and PR RTLMeter detailed reports.

# Developer note: You should be able to run this script in your local checkout
# if you have GitHub CLI (command 'gh') setup, authenticated ('gh auth login'),
# and have set a default repository ('gh repo set-default').

# Create pages root directory. The contents of this directory will be deployed
# and served via GitHubPages
readonly PAGES_ROOT=pages
mkdir -p ${PAGES_ROOT}

# Get the current repo URL - might differ on a fork
readonly REPO_URL=$(gh repo view --json url --jq .url)

# Set GITHUB_OUTPUT when run locally for testing
if [[ -z "$GITHUB_OUTPUT" ]]; then
  GITHUB_OUTPUT=github-output.txt
fi

# Run IDs of PR jobs processed
PR_RUN_IDS=""

# Populates ${PAGES_ROOT}/coverage-reports
compile_coverage_reports() {
  # We will process all runs up to and including this date. This is chosen to be
  # slightly less than the artifact retention period for simplicity.
  local OLDEST=$(date --date="28 days ago" --iso-8601=date)

  # Gather all coverage workflow runs within the time window
  gh run list -w coverage.yml --limit 1000 --created ">=${OLDEST}" --json "databaseId,event,status,conclusion,createdAt,number" > recentRuns.json
  echo @@@ Recent runs:
  jq "." recentRuns.json

  # Select completd runs that were not cancelled or skipped, sort by descending run number
  jq 'sort_by(-.number) | map(select(.status == "completed" and (.conclusion == "success" or .conclusion == "failure")))' recentRuns.json > completedRuns.json
  echo @@@ Completed with success or failure:
  jq "." completedRuns.json

  # Create artifacts root directory
  local ARTIFACTS_ROOT=artifacts-coverage
  mkdir -p ${ARTIFACTS_ROOT}

  # Create coverage reports root directory
  local COVERAGE_ROOT=${PAGES_ROOT}/coverage-reports
  mkdir -p ${COVERAGE_ROOT}

  # Create index page contents fragment
  local CONTENTS=contents.tmp
  echo > ${CONTENTS}

  # Iterate over all unique event types that triggered the workflows
  for EVENT in $(jq -r 'map(.event) | sort | unique | .[]' completedRuns.json); do
    echo "@@@ Processing '${EVENT}' runs"

    # Emit section header if a report exists with this event type
    EMIT_SECTION_HEADER=1

    # For each worfklow run that was triggered by this event type
    for RUN_ID in $(jq ".[] | select(.event == \"${EVENT}\") |.databaseId" completedRuns.json); do
      echo "@@@ Processing run ${RUN_ID}"

      # Extract the info of this run
      jq ".[] | select(.databaseId == $RUN_ID)" completedRuns.json > workflow.json
      jq "." workflow.json

      # Record run ID of PR job
      [[ $EVENT != "pull_request" ]] || PR_RUN_IDS="$PR_RUN_IDS $RUN_ID"

      # Create workflow artifacts directory
      local ARTIFACTS_DIR=${ARTIFACTS_ROOT}/${RUN_ID}
      mkdir -p ${ARTIFACTS_DIR}

      # Download artifacts of this run, if exists
      gh run download ${RUN_ID} --name coverage-report --dir ${ARTIFACTS_DIR} || true
      ls -lsha ${ARTIFACTS_DIR}

      # Move on if no coverage report is available
      if [ ! -d ${ARTIFACTS_DIR}/report ]; then
        echo "No coverage report found"
        continue
      fi
      echo "Coverage report found"

      # Emit section header
      if [[ -n $EMIT_SECTION_HEADER ]]; then
        unset EMIT_SECTION_HEADER
        if [[ $EVENT == "pull_request" ]]; then
          echo "<h4>Patch coverage reports for '${EVENT}' runs:</h4>" >> ${CONTENTS}
        else
          echo "<h4>Code coverage reports for '${EVENT}' runs:</h4>" >> ${CONTENTS}
        fi
      fi

      # Create pages subdirectory
      mv ${ARTIFACTS_DIR}/report ${COVERAGE_ROOT}/${RUN_ID}

      # Add index page content
      local WORKFLOW_CREATED=$(jq -r '.createdAt' workflow.json)
      local WOFKRLOW_NUMBER=$(jq -r '.number' workflow.json)
      cat >> ${CONTENTS} <<CONTENTS_TEMPLATE
        Run <a href="${RUN_ID}/index.html">#${WOFKRLOW_NUMBER}</a>
        | GitHub: <a href="${REPO_URL}/actions/runs/${RUN_ID}">${RUN_ID}</a>
        | started at: ${WORKFLOW_CREATED}
CONTENTS_TEMPLATE
      if [ -e ${ARTIFACTS_DIR}/pr-number.txt ]; then
        local PRNUMBER=$(cat ${ARTIFACTS_DIR}/pr-number.txt)
        echo " | Pull request: <a href=\"${REPO_URL}/pull/${PRNUMBER}\">#${PRNUMBER}</a>" >> ${CONTENTS}
      fi
      echo "<br>" >> ${CONTENTS}
    done

    # Section break
    if [[ -z "$EMIT_SECTION_HEADER" ]]; then
      echo "<hr>" >> ${CONTENTS}
    fi
  done

  # Write coverage report index.html
  cat > ${COVERAGE_ROOT}/index.html  <<INDEX_TEMPLATE
  <html>

  <head>
    <title>Verilator CI coverage reports</title>
    <style>
    body {
      font-family: courier, serif;
      background-color: #f3f3f3;
      a {
        color: #008fd7;
      }
    }
    </style>
  </head>

  <body>
  $(cat ${CONTENTS})
  <h4>Assembled $(date --iso-8601=minutes --utc)</h4>
  <body>

  </html>
INDEX_TEMPLATE

  # Report size
  du -shc ${COVERAGE_ROOT}/*
}

# Populates ${PAGES_ROOT}/rtlmeter-reports
compile_rtlmeter_reports() {
  # We will process all runs up to and including this date. This is chosen to be
  # slightly less than the artifact retention period for simplicity.
  local OLDEST=$(date --date="28 days ago" --iso-8601=date)

  # Gather all RTLMeter workflow runs within the time window
  gh run list -w rtlmeter.yml --limit 1000 --created ">=${OLDEST}" --json "databaseId,event,status,conclusion,createdAt,number" > recentRuns.json
  echo @@@ Recent runs:
  jq "." recentRuns.json

  # Select completd runs that were not cancelled or skipped, sort by descending run number
  jq 'sort_by(-.number) | map(select(.status == "completed" and (.conclusion == "success" or .conclusion == "failure")))' recentRuns.json > completedRuns.json
  echo @@@ Completed with success or failure:
  jq "." completedRuns.json

  # Create artifacts root directory
  local ARTIFACTS_ROOT=artifacts-rtlmeter
  mkdir -p ${ARTIFACTS_ROOT}

  # Create rtlmeter reports root directory
  local RTLMETER_ROOT=${PAGES_ROOT}/rtlmeter-reports
  mkdir -p ${RTLMETER_ROOT}

  # Create index page contents fragment
  local CONTENTS=contents.tmp
  echo > ${CONTENTS}

  # Iterate over all unique event types that triggered the workflows
  for EVENT in $(jq -r 'map(.event) | sort | unique | .[]' completedRuns.json); do
    echo "@@@ Processing '${EVENT}' runs"

    # Emit section header if a report exists with this event type
    EMIT_SECTION_HEADER=1

    # For each worfklow run that was triggered by this event type
    for RUN_ID in $(jq ".[] | select(.event == \"${EVENT}\") |.databaseId" completedRuns.json); do
      echo "@@@ Processing run ${RUN_ID}"

      # Extract the info of this run
      jq ".[] | select(.databaseId == $RUN_ID)" completedRuns.json > workflow.json
      jq "." workflow.json

      # Record run ID of PR job
      [[ $EVENT != "pull_request" ]] || PR_RUN_IDS="$PR_RUN_IDS $RUN_ID"

      # Create workflow artifacts directory
      local ARTIFACTS_DIR=${ARTIFACTS_ROOT}/${RUN_ID}
      mkdir -p ${ARTIFACTS_DIR}

      # Download artifacts of this run, if exists
      gh run download ${RUN_ID} --name rtlmeter-report --dir ${ARTIFACTS_DIR} || true
      ls -lsha ${ARTIFACTS_DIR}

      # Move on if no RTLMeter report is available
      if [ ! -d ${ARTIFACTS_DIR}/report ]; then
        echo "No RTLMeter report found"
        continue
      fi
      echo "RTLMeter report found"

      # Emit section header
      if [[ -n $EMIT_SECTION_HEADER ]]; then
        unset EMIT_SECTION_HEADER
        echo "<h4>RTLMeter reports for '${EVENT}' runs:</h4>" >> ${CONTENTS}
      fi

      # Create pages subdirectory
      mv ${ARTIFACTS_DIR}/report ${RTLMETER_ROOT}/${RUN_ID}

      # Add index page content
      local WORKFLOW_CREATED=$(jq -r '.createdAt' workflow.json)
      local WOFKRLOW_NUMBER=$(jq -r '.number' workflow.json)
      cat >> ${CONTENTS} <<CONTENTS_TEMPLATE
        Run <a href="${RUN_ID}/index.html">#${WOFKRLOW_NUMBER}</a>
        | GitHub: <a href="${REPO_URL}/actions/runs/${RUN_ID}">${RUN_ID}</a>
        | started at: ${WORKFLOW_CREATED}
CONTENTS_TEMPLATE
      if [ -e ${ARTIFACTS_DIR}/pr-number.txt ]; then
        local PRNUMBER=$(cat ${ARTIFACTS_DIR}/pr-number.txt)
        echo " | Pull request: <a href=\"${REPO_URL}/pull/${PRNUMBER}\">#${PRNUMBER}</a>" >> ${CONTENTS}
      fi
      echo "<br>" >> ${CONTENTS}
    done

    # Section break
    if [[ -z "$EMIT_SECTION_HEADER" ]]; then
      echo "<hr>" >> ${CONTENTS}
    fi
  done

  # Write rtlmeter report index.html
  cat > ${RTLMETER_ROOT}/index.html  <<INDEX_TEMPLATE
  <html>

  <head>
    <title>Verilator CI RTLMeter reports</title>
    <style>
    body {
      font-family: courier, serif;
      background-color: #f3f3f3;
      a {
        color: #008fd7;
      }
    }
    </style>
  </head>

  <body>
  $(cat ${CONTENTS})
  <h4>Assembled $(date --iso-8601=minutes --utc)</h4>
  <body>

  </html>
INDEX_TEMPLATE

  # Report size
  du -shc ${RTLMETER_ROOT}/*
}

# Compilie coverage reports
compile_coverage_reports;

# Compile RTLMeter reports
compile_rtlmeter_reports;

# You can build any other content here to be put under ${PAGES_ROOT}

# Set output to all affected unique PR run IDs (comma separated, no trailing comma)
IDS=$(echo ${PR_RUN_IDS} | xargs -n1 | sort -u | paste -sd,)
echo "pr-run-ids=${IDS}" >> $GITHUB_OUTPUT
