name: Main Release

on:
  push:
    branches: [main]
  workflow_dispatch:

concurrency:
  group: release-main
  cancel-in-progress: false

env:
  CI_GIT_EMAIL: 'git-ci@hiabuto.net'
  CI_GIT_NAME:  'Git-CI'
  GITEA_API_BASE: 'https://git.hiabuto.net/api/v1'
  GITEA_REPO: ${{ github.repository }}

jobs:
  compute:
    runs-on: linux-amd64
    if: ${{ github.ref == 'refs/heads/main' || github.event_name == 'workflow_dispatch' }}
    outputs:
      program_version: ${{ steps.ver.outputs.program_version }}
      did_release: ${{ steps.ver.outputs.did_release }}
      release_tag: ${{ steps.ver.outputs.release_tag }}
      release_kind: ${{ steps.ver.outputs.release_kind }}
      head_sha: ${{ steps.meta.outputs.head_sha }}
      head_msg: ${{ steps.meta.outputs.head_msg }}
    steps:
      - name: Checkout repository
        shell: bash
        env:
          CI_MATCHA_GITEA_TOKEN: ${{ secrets.CI_MATCHA_GITEA_TOKEN }}
        run: |
          set -euo pipefail
          git init .
          git remote add origin "https://git.hiabuto.net/${{ github.repository }}.git"
          if [ -n "${CI_MATCHA_GITEA_TOKEN:-}" ]; then
            basic=$(python3 -c 'import base64, os; print(base64.b64encode(("matcha:" + os.environ["CI_MATCHA_GITEA_TOKEN"]).encode()).decode())')
            git config --global http.https://git.hiabuto.net/.extraheader "AUTHORIZATION: basic ${basic}"
          else
            echo "CI_MATCHA_GITEA_TOKEN not set; trying unauthenticated checkout."
          fi
          git fetch --depth=50 origin "${{ github.ref_name }}"
          git checkout --force "${{ github.sha }}"

      - name: Load central CI templates
        shell: bash
        env:
          CI_MATCHA_GITEA_TOKEN: ${{ secrets.CI_MATCHA_GITEA_TOKEN }}
        run: |
          set -euo pipefail
          if [ -z "${CI_MATCHA_GITEA_TOKEN:-}" ]; then
            echo "Missing secrets.CI_MATCHA_GITEA_TOKEN" >&2
            exit 1
          fi
          basic=$(python3 -c 'import base64, os; print(base64.b64encode(("matcha:" + os.environ["CI_MATCHA_GITEA_TOKEN"]).encode()).decode())')
          git config --global http.https://git.hiabuto.net/.extraheader "AUTHORIZATION: basic ${basic}"
          git submodule sync --recursive
          git submodule update --init --remote ci-templates
          git -C ci-templates rev-parse --short HEAD

      - id: meta
        shell: bash
        run: |
          set -euo pipefail
          echo "head_sha=${{ github.sha }}" >> "$GITHUB_OUTPUT"
          echo "head_msg=$(git log -1 --pretty=format:%s)" >> "$GITHUB_OUTPUT"

      - id: ver
        name: Compute version
        uses: ./ci-templates/.gitea/actions/actions-versioning
        with:
          config_file: ci-config.yaml
          ref_name: ${{ github.ref_name }}

  package:
    needs: [compute]
    if: ${{ needs.compute.outputs.did_release == 'true' && !contains(needs.compute.outputs.head_msg, '[nobuild]') }}
    strategy:
      fail-fast: false
      matrix:
        include:
          - os_label: linux-amd64
            os: linux
            arch: amd64
          - os_label: linux-arm64
            os: linux
            arch: arm64
          - os_label: windows-amd64
            os: windows
            arch: amd64
    runs-on: ${{ matrix.os_label }}
    steps:
      - name: Checkout repository
        shell: bash
        env:
          CI_MATCHA_GITEA_TOKEN: ${{ secrets.CI_MATCHA_GITEA_TOKEN }}
        run: |
          set -euo pipefail
          git init .
          git remote add origin "https://git.hiabuto.net/${{ github.repository }}.git"
          if [ -n "${CI_MATCHA_GITEA_TOKEN:-}" ]; then
            basic=$(python3 -c 'import base64, os; print(base64.b64encode(("matcha:" + os.environ["CI_MATCHA_GITEA_TOKEN"]).encode()).decode())')
            git config --global http.https://git.hiabuto.net/.extraheader "AUTHORIZATION: basic ${basic}"
          else
            echo "CI_MATCHA_GITEA_TOKEN not set; trying unauthenticated checkout."
          fi
          git fetch --depth=50 origin "${{ github.ref_name }}"
          git checkout --force "${{ needs.compute.outputs.head_sha }}"

      - name: Load central CI templates
        shell: bash
        env:
          CI_MATCHA_GITEA_TOKEN: ${{ secrets.CI_MATCHA_GITEA_TOKEN }}
        run: |
          set -euo pipefail
          if [ -z "${CI_MATCHA_GITEA_TOKEN:-}" ]; then
            echo "Missing secrets.CI_MATCHA_GITEA_TOKEN" >&2
            exit 1
          fi
          basic=$(python3 -c 'import base64, os; print(base64.b64encode(("matcha:" + os.environ["CI_MATCHA_GITEA_TOKEN"]).encode()).decode())')
          git config --global http.https://git.hiabuto.net/.extraheader "AUTHORIZATION: basic ${basic}"
          git submodule sync --recursive
          git submodule update --init --remote ci-templates
          git -C ci-templates rev-parse --short HEAD

      - name: Package release via central CI templates
        uses: ./ci-templates/actions/ci-runner
        env:
          CI_ARCH: ${{ matrix.arch }}
        with:
          command: package-release
          config: ci-config.yaml
          version: ${{ needs.compute.outputs.program_version }}

      - name: Upload dist
        uses: actions/upload-artifact@v3
        with:
          name: dist-${{ matrix.os }}-${{ matrix.arch }}
          path: dist/

  finalize_and_publish:
    needs: [compute, package]
    if: ${{ needs.compute.outputs.did_release == 'true' && needs.package.result == 'success' }}
    runs-on: linux-amd64
    steps:
      - name: Checkout repository
        shell: bash
        env:
          CI_MATCHA_GITEA_TOKEN: ${{ secrets.CI_MATCHA_GITEA_TOKEN }}
        run: |
          set -euo pipefail
          git init .
          git remote add origin "https://git.hiabuto.net/${{ github.repository }}.git"
          if [ -n "${CI_MATCHA_GITEA_TOKEN:-}" ]; then
            basic=$(python3 -c 'import base64, os; print(base64.b64encode(("matcha:" + os.environ["CI_MATCHA_GITEA_TOKEN"]).encode()).decode())')
            git config --global http.https://git.hiabuto.net/.extraheader "AUTHORIZATION: basic ${basic}"
          else
            echo "CI_MATCHA_GITEA_TOKEN not set; trying unauthenticated checkout."
          fi
          git fetch --depth=50 origin "${{ github.ref_name }}"
          git checkout --force "${{ needs.compute.outputs.head_sha }}"

      - name: Download artifacts
        uses: actions/download-artifact@v3
        with:
          path: release-artifacts

      - name: Prepare upload dir
        shell: bash
        run: |
          set -euo pipefail
          mkdir -p upload
          find release-artifacts -maxdepth 4 -type f -print -exec cp -f {} upload/ \;
          ls -la upload

      - name: Commit VERSION + tag + push (only now)
        shell: bash
        env:
          CI_MATCHA_GITEA_TOKEN: ${{ secrets.CI_MATCHA_GITEA_TOKEN }}
        run: |
          set -euo pipefail
          if [ -z "${CI_MATCHA_GITEA_TOKEN:-}" ]; then
            echo "Missing secrets.CI_MATCHA_GITEA_TOKEN" >&2
            exit 1
          fi

          version="${{ needs.compute.outputs.program_version }}"
          tag="${{ needs.compute.outputs.release_tag }}"
          version_file=$(python3 - <<'PY'
          import re
          p='VERSION'
          for line in open('ci-config.yaml', encoding='utf-8'):
              if re.match(r'^\s*file\s*:', line):
                  p=line.split(':',1)[1].strip().strip('"\'')
                  break
          print(p)
          PY
          )

          git config user.email "${CI_GIT_EMAIL}"
          git config user.name  "${CI_GIT_NAME}"

          echo "$version" > "$version_file"
          git add "$version_file"
          if git diff --cached --quiet; then
            echo "VERSION already set in repo; continuing"
          else
            git commit -m "ci: release version ${version} [skip ci]"
          fi

          git config --local --unset-all http.https://git.hiabuto.net/.extraheader || true
          git config --global --unset-all http.https://git.hiabuto.net/.extraheader || true
          git remote set-url origin "https://matcha:${CI_MATCHA_GITEA_TOKEN}@git.hiabuto.net/${GITEA_REPO}.git"
          git fetch --tags origin
          git push origin "HEAD:main"

          if git ls-remote --exit-code --tags origin "refs/tags/${tag}" >/dev/null 2>&1; then
            echo "Tag already exists on origin: ${tag} (will reuse)"
          else
            git tag "${tag}"
            git push origin "${tag}"
          fi

      - name: Publish release + upload assets
        shell: bash
        env:
          GITEA_TOKEN: ${{ secrets.CI_MATCHA_GITEA_TOKEN }}
          TAG: ${{ needs.compute.outputs.release_tag }}
        run: |
          set -euo pipefail
          if [ -z "${GITEA_TOKEN:-}" ]; then
            echo "Missing secrets.CI_MATCHA_GITEA_TOKEN" >&2
            exit 1
          fi

          python3 - <<'PY'
          import json, os, pathlib, urllib.parse, urllib.request, urllib.error
          api_base = os.environ['GITEA_API_BASE'].rstrip('/')
          repo = os.environ['GITEA_REPO']
          token = os.environ['GITEA_TOKEN'].strip()
          tag = os.environ['TAG'].strip()
          artifacts = sorted(p for p in pathlib.Path('upload').glob('*') if p.is_file())
          headers = {'Authorization': f'token {token}', 'Accept': 'application/json'}
          def request_json(method, url, data=None):
              payload=None
              h=dict(headers)
              if data is not None:
                  payload=json.dumps(data).encode('utf-8'); h['Content-Type']='application/json'
              req=urllib.request.Request(url, data=payload, method=method, headers=h)
              try:
                  with urllib.request.urlopen(req) as resp:
                      txt=resp.read().decode('utf-8'); return resp.getcode(), json.loads(txt) if txt else None
              except urllib.error.HTTPError as exc:
                  return exc.code, {'error': exc.read().decode('utf-8', errors='replace')}
          def request_binary_post(url, payload, content_type):
              h=dict(headers); h['Content-Type']=content_type
              req=urllib.request.Request(url, data=payload, method='POST', headers=h)
              with urllib.request.urlopen(req) as resp:
                  txt=resp.read().decode('utf-8'); return resp.getcode(), json.loads(txt) if txt else None
          tag_url=f"{api_base}/repos/{repo}/releases/tags/{urllib.parse.quote(tag, safe='')}"
          status, release = request_json('GET', tag_url)
          if status==200 and isinstance(release, dict):
              release_id=release.get('id')
          else:
              status, release = request_json('POST', f"{api_base}/repos/{repo}/releases", {
                  'tag_name': tag, 'name': tag, 'body': f'Automated release for {tag}', 'draft': False, 'prerelease': False,
              })
              if status not in (200,201):
                  raise SystemExit(f"create release failed {status} {release}")
              release_id=release.get('id')
          assets_url=f"{api_base}/repos/{repo}/releases/{release_id}/assets"
          status, existing = request_json('GET', assets_url)
          existing = existing if isinstance(existing, list) else []
          by_name={e.get('name'):e for e in existing if isinstance(e, dict) and e.get('name')}
          for a in artifacts:
              name=a.name
              prev=by_name.get(name)
              if prev and prev.get('id'):
                  ds,_=request_json('DELETE', f"{assets_url}/{prev['id']}")
                  if ds!=204: raise SystemExit(f"delete asset failed {name} {ds}")
              code,_=request_binary_post(f"{assets_url}?name={urllib.parse.quote(name, safe='')}", a.read_bytes(), 'application/octet-stream')
              if code not in (200,201): raise SystemExit(f"upload failed {name} {code}")
              print('Uploaded', name)
          print('Release done', tag)
          PY

  sync_main_to_dev:
    needs: [finalize_and_publish]
    if: ${{ needs.finalize_and_publish.result == 'success' }}
    runs-on: linux-amd64
    steps:
      - name: Checkout repository
        shell: bash
        env:
          CI_MATCHA_GITEA_TOKEN: ${{ secrets.CI_MATCHA_GITEA_TOKEN }}
        run: |
          set -euo pipefail
          git init .
          git remote add origin "https://git.hiabuto.net/${{ github.repository }}.git"
          if [ -n "${CI_MATCHA_GITEA_TOKEN:-}" ]; then
            basic=$(python3 -c 'import base64, os; print(base64.b64encode(("matcha:" + os.environ["CI_MATCHA_GITEA_TOKEN"]).encode()).decode())')
            git config --global http.https://git.hiabuto.net/.extraheader "AUTHORIZATION: basic ${basic}"
          else
            echo "CI_MATCHA_GITEA_TOKEN not set; trying unauthenticated checkout."
          fi
          git fetch --depth=50 origin "${{ github.ref_name }}"
          git checkout --force "${{ github.sha }}"

      - name: Merge main into dev + bump dev0
        shell: bash
        env:
          CI_MATCHA_GITEA_TOKEN: ${{ secrets.CI_MATCHA_GITEA_TOKEN }}
        run: |
          set -euo pipefail
          if [ -z "${CI_MATCHA_GITEA_TOKEN:-}" ]; then
            echo "Missing secrets.CI_MATCHA_GITEA_TOKEN" >&2
            exit 1
          fi

          git config user.email "${CI_GIT_EMAIL}"
          git config user.name  "${CI_GIT_NAME}"

          git config --local --unset-all http.https://git.hiabuto.net/.extraheader || true
          git config --global --unset-all http.https://git.hiabuto.net/.extraheader || true
          git remote set-url origin "https://matcha:${CI_MATCHA_GITEA_TOKEN}@git.hiabuto.net/${GITEA_REPO}.git"
          git fetch origin main dev
          git checkout -B dev origin/dev
          git merge origin/main -m "ci: merge main into dev [skip ci]"

          version_file=$(python3 - <<'PY'
          import re
          p='VERSION'
          for line in open('ci-config.yaml', encoding='utf-8'):
              if re.match(r'^\s*file\s*:', line):
                  p=line.split(':',1)[1].strip().strip('"\'')
                  break
          print(p)
          PY
          )
          main_version=$(git show origin/main:"$version_file" | head -n1 | tr -d '\r\n' | xargs)
          python3 -c "import re,sys; v=sys.argv[1].strip(); m=re.search(r'(\\d+)\\.(\\d+)\\.(\\d+)', v); (m is not None) or (_ for _ in ()).throw(SystemExit(f'Bad VERSION on main: {v!r}')); print(f'{m.group(1)}.{m.group(2)}.{m.group(3)}-dev0')" "$main_version" > "$version_file"

          git add "$version_file"
          if git diff --cached --quiet; then
            echo "No VERSION changes after sync.";
          else
            git commit -m "ci: bump dev version to $(cat "$version_file") [skip ci]"
          fi

          git push origin HEAD:dev
