name: Build dev

env:
  DEFAULT_SOURCE_BRANCH: "master"
  DEFAULT_TARGET_BRANCH: "master-dev"
  LFS_URL: 'https://gitlab.com/sunnypilot/public/sunnypilot-new-lfs.git/info/lfs'
  LFS_PUSH_URL: 'ssh://git@gitlab.com/sunnypilot/public/sunnypilot-new-lfs.git'

on:
  push:
    branches:
      - master
  pull_request_target:
    types: [ labeled ]
    branches:
      - 'master'
  workflow_dispatch:
    inputs:
      source_branch:
        description: 'Source branch to reset from'
        required: true
        default: 'master'
        type: string
      target_branch:
        description: 'Target branch to reset and squash into'
        required: true
        default: 'master-dev'
        type: string
      cancel_in_progress:
        description: 'Cancel any in-progress runs of this workflow'
        required: false
        default: true
        type: boolean

concurrency:
  group: ${{ github.workflow }}
  cancel-in-progress: ${{ inputs.cancel_in_progress || github.event_name == 'push' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch) }}

jobs:
  reset-and-squash:
    runs-on: ubuntu-latest
    if: (
      (github.event_name == 'workflow_dispatch')
      || (github.event_name == 'push' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch))
      || (contains(github.event_name, 'pull_request') && ((github.event.action == 'labeled' && (github.event.label.name == vars.PREBUILT_PR_LABEL || github.event.label.name == 'trust-fork-pr') && contains(github.event.pull_request.labels.*.name, vars.PREBUILT_PR_LABEL))))
      )
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0  # Fetch all history for all branches
          token: ${{ secrets.GITHUB_TOKEN }}
          persist-credentials: false

      - name: Wait for Tests
        uses: ./.github/workflows/wait-for-action # Path to where you place the action
        if: (
          (github.event_name == 'push' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch))
          || (contains(github.event_name, 'pull_request') && ((github.event.action == 'labeled' && (github.event.label.name == vars.PREBUILT_PR_LABEL || github.event.label.name == 'trust-fork-pr') && contains(github.event.pull_request.labels.*.name, vars.PREBUILT_PR_LABEL))))
          )
        with:
          workflow: tests.yaml # The workflow file to monitor
          github-token: ${{ secrets.GITHUB_TOKEN }}

      - name: Configure Git
        run: |
          git config --global user.name 'github-actions[bot]'
          git config --global user.email 'github-actions[bot]@users.noreply.github.com'

      - name: Set up SSH
        uses: webfactory/ssh-agent@v0.9.0
        with:
          ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}

      - name: Add GitLab public keys
        run: |
          ssh-keyscan -H gitlab.com >> ~/.ssh/known_hosts

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.10'

      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install PyGithub

      - name: Check branches exist
        run: |
          # Check if source branch exists
          if ! git ls-remote --heads origin ${{ inputs.source_branch || env.DEFAULT_SOURCE_BRANCH }} | grep -q "${{ inputs.source_branch || env.DEFAULT_SOURCE_BRANCH }}"; then
            echo "Source branch ${{ inputs.source_branch || env.DEFAULT_SOURCE_BRANCH }} does not exist!"
            exit 1
          fi

          # Make sure we have the latest source branch
          git fetch origin ${{ inputs.source_branch || env.DEFAULT_SOURCE_BRANCH }}

          # Check if target branch exists
          if ! git ls-remote --heads origin ${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }} | grep -q "${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }}"; then
            echo "Target branch ${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }} does not exist, creating it from ${{ inputs.source_branch || env.DEFAULT_SOURCE_BRANCH }}"
            git checkout -b ${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }} origin/${{ inputs.source_branch || env.DEFAULT_SOURCE_BRANCH }}
            git push origin ${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }}
          else
            # Fetch target branch if it exists
            git fetch origin ${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }}
          fi

      - name: Reset target branch
        run: |
          echo "Resetting ${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }} to match ${{ inputs.source_branch || env.DEFAULT_SOURCE_BRANCH }}"
          # Delete if exists and recreate pointing to source
          git branch -D ${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }} || true
          git branch ${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }} origin/${{ inputs.source_branch || env.DEFAULT_SOURCE_BRANCH }}

      - name: Get PRs to squash
        id: get-prs
        run: |
          # Use GitHub API to get PRs with specific label, ordered by creation date
          PR_LIST=$(gh api graphql -f query='
            query($search_query:String!) {
              search(query: $search_query, type:ISSUE, first:40) {
                nodes {
                  ... on PullRequest {
                    number
                    headRefName
                    title
                    createdAt
                    labels(last:10) {
                      nodes {
                        name
                      }
                    }
                    headRepository {
                      name
                      nameWithOwner
                      url
                      isFork
                    }
                    commits(last: 1) {
                      nodes {
                        commit {
                          statusCheckRollup {
                            state
                          }
                        }
                      }
                    }
                  }
                }
              }
            }' -F search_query="repo:${{ github.repository }} is:pr is:open label:${{ vars.PREBUILT_PR_LABEL }},${{ vars.PREBUILT_PR_LABEL }}-c3 draft:false sort:created-asc")

          PR_LIST=${PR_LIST//\'/}
          echo "PR_LIST=${PR_LIST}" >> $GITHUB_OUTPUT
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Process PRs
        run: |
          cp ${{ github.workspace }}/release/ci/squash_and_merge.py /tmp/squash_and_merge.py && \
          chmod +x /tmp/squash_and_merge.py && \
          python3 ${{ github.workspace }}/release/ci/squash_and_merge_prs.py \
            --pr-data '${{ steps.get-prs.outputs.PR_LIST }}' \
            --target-branch ${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }} \
            --squash-script-path '/tmp/squash_and_merge.py'
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Update LFS Config
        run: |
          echo '[lfs]' > .lfsconfig
          echo '    url = ${{ env.LFS_URL }}' >> .lfsconfig
          echo '    pushurl = ${{ env.LFS_PUSH_URL }}' >> .lfsconfig
          echo '    locksverify = false' >> .lfsconfig

      - name: Restore workflows from source
        run: |
          TARGET_BRANCH="${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }}"
          SOURCE_BRANCH="${{ inputs.source_branch || env.DEFAULT_SOURCE_BRANCH }}"

          # Ensure we are on the target branch
          git checkout $TARGET_BRANCH

          echo "Restoring .github/workflows from $SOURCE_BRANCH"
          git checkout origin/$SOURCE_BRANCH -- .github/workflows

          if ! git diff --cached --quiet; then
            echo "Workflows differ. Committing restoration."
            git commit -m "chore: restore .github/workflows from $SOURCE_BRANCH"
          else
            echo "Workflows match $SOURCE_BRANCH."
          fi

      - uses: actions/create-github-app-token@v2
        id: ci-token
        with:
          app-id: ${{ secrets.CI_GITHUB_ACTIONS_TOKEN_APP_ID }}
          private-key: ${{ secrets.CI_GITHUB_ACTIONS_TOKEN_APP_PRIVATE_KEY }}

      - name: Push changes if there are diffs
        id: push-changes
        run: |
          TARGET_BRANCH="${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }}"

          # Use the App Token to set the remote URL with authentication
          git remote set-url origin "https://x-access-token:${{ steps.ci-token.outputs.token }}@github.com/${{ github.repository }}.git"

          # Fetch the latest from remote
          git fetch origin $TARGET_BRANCH

          # Check for diffs between local and remote
          if git diff $TARGET_BRANCH origin/$TARGET_BRANCH --quiet; then
            echo "No changes to push - local and remote branches are identical"
            echo "has_changes=false" >> $GITHUB_OUTPUT
            exit 0
          fi

          # Push with the authenticated origin
          if ! git push origin $TARGET_BRANCH --force; then
            echo "Failed to push changes to $TARGET_BRANCH"
            exit 1
          fi

          echo "Branch $TARGET_BRANCH has been reset and updated with squashed PRs"
          echo "has_changes=true" >> $GITHUB_OUTPUT

      - name: Trigger and wait for selfdrive tests
        if: steps.push-changes.outputs.has_changes == 'true'
        run: |
          echo "Triggering selfdrive tests..."
          gh workflow run tests.yaml --ref "${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }}"

          echo "Sleeping for 120s to give plenty of time for the action to start and then we wait"
          sleep 120

          echo "Getting latest run ID..."
          RUN_ID=$(gh run list --workflow=tests.yaml --branch="${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }}" --limit=1 --json databaseId --jq '.[0].databaseId')

          echo "Watching run ID: $RUN_ID"
          gh run watch "$RUN_ID"
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
