version: 2.1

commands:
  setup-toolchain:
    parameters:
        toolchain:
            type: string

    steps:
      - run:
          name: Set toolchain url and key
          command: |
            toolchain_url=$(jq -r '."<< parameters.toolchain >>"' .github/actions/setup_toolchain/toolchain.json)
            # only cache if not a github link
            if [[ $toolchain_url != "https://github.com"* ]]; then
              echo "<< parameters.toolchain >>-$toolchain_url" > toolchain_key
            fi
            echo "export toolchain_url=$toolchain_url" >> $BASH_ENV

      - restore_cache:
          name: Restore Toolchain Cache
          key: deps-{{ checksum "toolchain_key" }}
          paths:
            - ~/cache/<< parameters.toolchain >>

      - run:
          name: Install Toolchain
          command: |
            # download if folder does not exist (not cached)
            if [ ! -d ~/cache/<< parameters.toolchain >> ]; then
              mkdir -p ~/cache/<< parameters.toolchain >>
              if [[ << parameters.toolchain >> == rx-gcc ]]; then
                wget --progress=dot:giga $toolchain_url -O toolchain.run
                chmod +x toolchain.run
                ./toolchain.run -p ~/cache/<< parameters.toolchain >>/gnurx -y
              elif [[ << parameters.toolchain >> == arm-iar ]]; then
                wget --progress=dot:giga https://netstorage.iar.com/FileStore/STANDARD/001/003/926/iar-lmsc-tools_1.8_amd64.deb -O ~/cache/<< parameters.toolchain >>/iar-lmsc-tools.deb
                wget --progress=dot:giga $toolchain_url -O ~/cache/<< parameters.toolchain >>/toolchain.deb
              else
                wget --progress=dot:giga $toolchain_url -O toolchain.tar.gz
                tar -C ~/cache/<< parameters.toolchain >> -xaf toolchain.tar.gz
              fi
            fi

            # Add toolchain to PATH
            if [[ << parameters.toolchain >> == arm-iar ]]; then
              # Install IAR since we only cache deb file
              sudo dpkg -i ~/cache/<< parameters.toolchain >>/iar-lmsc-tools.deb
              sudo dpkg --ignore-depends=libusb-1.0-0 -i ~/cache/<< parameters.toolchain >>/toolchain.deb
              echo "export PATH=$PATH:/opt/iar/cxarm/arm/bin" >> $BASH_ENV
            else
              echo "export PATH=$PATH:`echo ~/cache/<< parameters.toolchain >>/*/bin`" >> $BASH_ENV
            fi

      - save_cache:
          name: Save Toolchain Cache
          key: deps-{{ checksum "toolchain_key" }}
          paths:
            - ~/cache/<< parameters.toolchain >>

  build:
    parameters:
      build-system:
        type: string
      toolchain:
        type: string
      family:
        type: string
      build-args:
        type: string
        default: ""

    steps:
      - checkout
      - run:
          name: Get Dependencies
          command: |
            python tools/get_deps.py << parameters.family >>

            # Install ninja  if cmake build system
            if [ << parameters.build-system >> == "cmake" ]; then
              NINJA_URL=https://github.com/ninja-build/ninja/releases/download/v1.12.1/ninja-linux.zip
              wget $NINJA_URL -O ninja-linux.zip
              unzip ninja-linux.zip -d ~/bin
            fi

            # rx-gcc is 32-bit binary
            if [[ << parameters.toolchain >> == rx-gcc ]]; then
              sudo dpkg --add-architecture i386
              sudo apt update
              sudo apt install libc6:i386 libstdc++6:i386 zlib1g:i386
            fi

            # Install Pico SDK
            if [ << parameters.family >> == "rp2040" ]; then
              git clone --depth 1 https://github.com/raspberrypi/pico-sdk.git ~/pico-sdk
              echo "export PICO_SDK_PATH=~/pico-sdk" >> $BASH_ENV
            fi

      - when:
          condition:
            not:
              equal: [esp-idf, << parameters.toolchain >>]
          steps:
            - setup-toolchain:
                toolchain: << parameters.toolchain >>

      - run:
          name: Build
          no_output_timeout: 20m
          command: |
            if [ << parameters.toolchain >> == esp-idf ]; then
              docker run --rm -v $PWD:/project -w /project espressif/idf:v5.3.2 python tools/build.py << parameters.build-args >> << parameters.family >>
            else
              # Toolchain option default is gcc
              if [ << parameters.toolchain >> == arm-clang ]; then
                TOOLCHAIN_OPTION="--toolchain clang"
              elif [ << parameters.toolchain >> == arm-iar ]; then
                TOOLCHAIN_OPTION="--toolchain iar"
                iccarm --version
              elif [ << parameters.toolchain >> == arm-gcc ]; then
                TOOLCHAIN_OPTION="--toolchain gcc"
              fi

              # circleci docker return $nproc as 36 core, limit parallel to 4 (resource-class = large)
              # Required for IAR, also prevent crashed/killed by docker
              python tools/build.py -s << parameters.build-system >> $TOOLCHAIN_OPTION -j 4 << parameters.build-args >> << parameters.family >>
            fi

      # Only collect and persist metrics for cmake builds (excluding esp-idf and --one-random)
      - when:
          condition:
            and:
              - equal: [ cmake, << parameters.build-system >> ]
              - not:
                  equal: [ esp-idf, << parameters.toolchain >> ]
              - not:
                  equal: [ arm-iar, << parameters.toolchain >> ]
          steps:
            - run:
                name: Collect Metrics
                command: |
                  # Create unique directory per toolchain to avoid workspace conflicts
                  METRICS_DIR="/tmp/metrics/<< parameters.toolchain >>"
                  mkdir -p "${METRICS_DIR}"
                  # Copy all metrics.json files
                  for f in cmake-build/cmake-build-*/metrics.json; do
                    if [ -f "$f" ]; then
                      BOARD_DIR=$(dirname "$f" | xargs basename)
                      cp "$f" "${METRICS_DIR}/${BOARD_DIR}.json"
                    fi
                  done

            - persist_to_workspace:
                root: /tmp
                paths:
                  - metrics/<< parameters.toolchain >>

jobs:
  # Build using docker
  build:
    parameters:
      resource_class:
        type: string
        default: large
      build-system:
        type: string
      toolchain:
        type: string
      family:
        type: string
      build-args:
        type: string
        default: ""

    docker:
      - image: cimg/base:current
    working_directory: ~/project/tinyusb
    resource_class: << parameters.resource_class >>

    steps:
      - build:
          build-system: << parameters.build-system >>
          toolchain: << parameters.toolchain >>
          family: << parameters.family >>
          build-args: << parameters.build-args >>

  # Build using VM
  build-vm:
    parameters:
      resource_class:
        type: string
        default: large
      build-system:
        type: string
      toolchain:
        type: string
      family:
        type: string
      build-args:
        type: string
        default: ""

    machine:
      image: ubuntu-2404:current
    working_directory: ~/project/tinyusb
    resource_class: << parameters.resource_class >>

    steps:
      - build:
          build-system: << parameters.build-system >>
          toolchain: << parameters.toolchain >>
          family: << parameters.family >>
          build-args: << parameters.build-args >>

  # Aggregate code metrics from all builds
  code-metrics:
    docker:
      - image: cimg/python:3.12
    resource_class: large
    steps:
      - checkout
      - attach_workspace:
          at: /tmp

      - run:
          name: Aggregate Code Metrics
          command: |
            python tools/get_deps.py
            # Combine all metrics files from all toolchain subdirectories
            ls -R /tmp/metrics
            if ls /tmp/metrics/*/*.json 1> /dev/null 2>&1; then
              python tools/metrics.py combine -j -m -f tinyusb/src /tmp/metrics/*/*.json
            else
              echo "No metrics files found"
              exit 1
            fi

      - store_artifacts:
          path: metrics.json
          destination: metrics.json

      # Compare with base master metrics on PR branches
      - when:
          condition:
            not:
              equal: [ master, << pipeline.git.branch >> ]
          steps:
            - run:
                name: Download Base Branch Metrics
                command: |
                  # Download metrics.json artifact from the latest successful build on master branch
                  mkdir -p base-metrics
                  # Use CircleCI API to get the latest artifact
                  curl -s -L "https://dl.circleci.com/api/v2/project/gh/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}/latest/artifacts?branch=master&filter=successful" \
                    -H "Circle-Token: ${CIRCLE_TOKEN:-}" | \
                    jq -r '.items[] | select(.path == "metrics.json") | .url' | \
                    head -1 | xargs -I {} curl -s -L -o base-metrics/metrics.json {} || true

            - run:
                name: Compare with Base Branch
                command: |
                  if [ -f base-metrics/metrics.json ]; then
                    python tools/metrics.py compare -f tinyusb/src base-metrics/metrics.json metrics.json
                    cat metrics_compare.md
                  else
                    echo "No base metrics found, skipping comparison"
                    cp metrics.md metrics_compare.md
                  fi

            - store_artifacts:
                path: metrics_compare.md
                destination: metrics_compare.md

workflows:
  build:
    jobs:
# The jobs below are populated dynamically by config.yml set-matrix job
# Example entries that will be generated:
#      - build:
#          matrix:
#            alias: build-cmake-arm-gcc
#            parameters:
#              toolchain: [ 'arm-gcc' ]
#              build-system: [ 'cmake' ]
#              family: [ 'nrf' ]
#              resource_class: ['large']
#      - code-metrics:
#          requires:
#            - build-cmake-arm-gcc
