name: Update lists

on:
  schedule:
    # Каждый день в 03:00 UTC (06:00 МСК)
    - cron: "0 3 * * *"

  workflow_dispatch:

  push:
    branches: [main]
    paths:
      - "src/**"
      - "config/**"
      - "package.json"
      - "package-lock.json"
      - ".github/workflows/update.yml"

concurrency:
  group: update
  cancel-in-progress: false

permissions:
  contents: write
  pages: write
  id-token: write

env:
  RELEASE_TAG: latest
  RELEASE_BRANCH: release

jobs:
  update:
    name: Build and publish
    runs-on: ubuntu-latest
    timeout-minutes: 30

    steps:
      - name: Checkout
        uses: actions/checkout@v7

      - name: Setup Node.js
        uses: actions/setup-node@v7
        with:
          node-version-file: .nvmrc
          cache: npm

      - name: Install dependencies
        run: npm ci

      - name: Typecheck
        run: npm run test:typecheck

      - name: Restore network cache
        uses: actions/cache@v6
        with:
          path: cache/
          key: network-cache-${{ github.run_id }}
          restore-keys: network-cache-

      - name: Restore tools
        uses: actions/cache@v6
        with:
          path: .tools/
          key: tools-${{ runner.os }}-${{ hashFiles('src/contracts/sources/sources.contract.ts') }}

      - name: Download sing-box and mihomo
        run: npm run tools
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Build all lists
        run: npm run update

      - name: Check for changes
        id: diff
        run: |
          set -euo pipefail
          # Сравниваем только данные: подсети и домены. Заголовки с датой меняются каждый день
          CHANGED=true
          if git ls-remote --exit-code --heads origin "$RELEASE_BRANCH" >/dev/null 2>&1; then
            git fetch --depth=1 origin "$RELEASE_BRANCH"
            git show "origin/$RELEASE_BRANCH:SHA256SUMS" 2>/dev/null | grep -E '\.(ipv4|ipv6|domains)\.txt$' > /tmp/prev.sums || true
            grep -E '\.(ipv4|ipv6|domains)\.txt$' dist/SHA256SUMS > /tmp/next.sums
            if [ -s /tmp/prev.sums ] && cmp -s /tmp/prev.sums /tmp/next.sums; then
              CHANGED=false
            fi
          fi
          if [ "${{ github.event_name }}" != "schedule" ]; then
            CHANGED=true
          fi
          echo "changed=$CHANGED" >> "$GITHUB_OUTPUT"
          echo "Изменения: $CHANGED"

      - name: Publish release branch
        if: steps.diff.outputs.changed == 'true'
        run: |
          set -euo pipefail
          TODAY=$(date -u '+%Y-%m-%d')
          LITE=$(jq -r '.tiers["ru-lite"].ipv4' dist/manifest.json)
          STANDARD=$(jq -r '.tiers["ru-standard"].ipv4' dist/manifest.json)
          FULL=$(jq -r '.tiers["ru-full"].ipv4' dist/manifest.json)
          WORKTREE=$(mktemp -d)
          git worktree add --detach "$WORKTREE"
          cd "$WORKTREE"
          git checkout --orphan "$RELEASE_BRANCH"
          git rm -rfq . >/dev/null 2>&1 || true
          cp -R "$GITHUB_WORKSPACE/dist/." .
          printf '# Ветка release\n\nГотовые файлы последней сборки. Обновляется ботом, править вручную бессмысленно.\n' > README.md
          git config user.name "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"
          git add -A
          git commit -qm "chore(lists): ${TODAY} · lite ${LITE} · standard ${STANDARD} · full ${FULL}"
          git push --force origin "$RELEASE_BRANCH"
          cd "$GITHUB_WORKSPACE"
          git worktree remove --force "$WORKTREE"

      - name: Publish rolling release
        if: steps.diff.outputs.changed == 'true'
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          set -euo pipefail
          TODAY=$(date -u '+%Y-%m-%d')
          if ! gh release view "$RELEASE_TAG" >/dev/null 2>&1; then
            gh release create "$RELEASE_TAG" --title "Списки от ${TODAY}" --notes-file RELEASE_NOTES.md --latest
          fi
          gh release upload "$RELEASE_TAG" dist/* --clobber
          gh release edit "$RELEASE_TAG" --title "Списки от ${TODAY}" --notes-file RELEASE_NOTES.md --latest
          git push --force origin "HEAD:refs/tags/$RELEASE_TAG"

      - name: Purge jsDelivr cache
        if: steps.diff.outputs.changed == 'true'
        run: |
          for file in $(ls dist); do
            curl -fsS -m 20 "https://purge.jsdelivr.net/gh/${GITHUB_REPOSITORY}@${RELEASE_BRANCH}/${file}" >/dev/null || true
          done

      - name: Upload manifest for pages
        if: steps.diff.outputs.changed == 'true'
        uses: actions/upload-artifact@v7
        with:
          name: manifest
          path: dist/manifest.json
          retention-days: 1

    outputs:
      changed: ${{ steps.diff.outputs.changed }}

  pages:
    name: Deploy site
    needs: update
    if: needs.update.outputs.changed == 'true'
    uses: ./.github/workflows/pages.yml
    secrets: inherit
