name: CI

on:
  push:
  pull_request:

permissions:
  contents: write

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Shellcheck
        uses: ludeeus/action-shellcheck@master
        with:
          scandir: scripts

      - name: Install Rust (stable)
        uses: dtolnay/rust-toolchain@stable
        with:
          components: rustfmt, clippy

      - name: Format
        run: cargo fmt --all -- --check

      - name: Clippy (all features)
        run: cargo clippy --all-targets --all-features -- -D warnings

      - name: Tests (all features)
        run: cargo test --all-features

      - name: Build (no default features)
        run: cargo build --no-default-features

      - name: Build (no_std + alloc)
        run: cargo build --no-default-features --features alloc

      - name: Build (no_std + alloc + sha2)
        run: cargo build --no-default-features --features alloc,sha2

      - name: Docs
        run: cargo doc --no-deps --all-features

  release:
    needs: test
    runs-on: ubuntu-latest
    if: github.event_name == 'push' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Install Rust (stable)
        uses: dtolnay/rust-toolchain@stable

      - name: Publish to crates.io and tag
        env:
          CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
        shell: bash
        run: |
          set -euo pipefail
          meta="$(python3 -c 'import tomllib, pathlib; data=tomllib.loads(pathlib.Path("Cargo.toml").read_text()); pkg=data.get("package", {}); name=pkg.get("name"); version=pkg.get("version"); print("MISSING" if not name or not version else f"{name} {version}")')"

          if [ "$meta" = "MISSING" ] || [ -z "${meta:-}" ]; then
            echo "Failed to parse package name/version from Cargo.toml" >&2
            exit 1
          fi
          crate="${meta%% *}"
          version="${meta#* }"
          if [ -z "${crate:-}" ] || [ -z "${version:-}" ] || [ "$crate" = "$version" ]; then
            echo "Malformed package metadata: '${meta}'" >&2
            exit 1
          fi

          tag="v${version}"
          if git rev-parse -q --verify "refs/tags/${tag}" >/dev/null; then
            echo "Tag ${tag} already exists."
            tag_exists=1
          else
            tag_exists=0
          fi

          is_published() {
            CRATE="$1" VERSION="$2" python3 -c $'import json, os, sys, urllib.request, urllib.error\ncrate=os.environ[\"CRATE\"]\nversion=os.environ[\"VERSION\"]\nurl=f\"https://crates.io/api/v1/crates/{crate}\"\ntry:\n    with urllib.request.urlopen(url, timeout=10) as resp:\n        data=json.load(resp)\nexcept urllib.error.HTTPError as exc:\n    if exc.code == 404:\n        sys.exit(1)\n    print(f\"Failed to query crates.io: {exc}\", file=sys.stderr)\n    sys.exit(2)\nexcept Exception as exc:\n    print(f\"Failed to query crates.io: {exc}\", file=sys.stderr)\n    sys.exit(2)\nversions={v.get(\"num\") for v in data.get(\"versions\", [])}\nsys.exit(0 if version in versions else 1)\n'
          }

          derive_version="$(python3 -c 'import tomllib, pathlib; data=tomllib.loads(pathlib.Path("sacp-cbor-derive/Cargo.toml").read_text()); print(data["package"]["version"])')"

          set +e
          is_published "sacp-cbor-derive" "$derive_version"
          derive_published=$?
          is_published "$crate" "$version"
          published=$?
          set -e
          if [ "$derive_published" -gt 1 ] || [ "$published" -gt 1 ]; then
            exit 1
          fi

          if [ "$derive_published" -eq 0 ]; then
            echo "sacp-cbor-derive ${derive_version} already on crates.io; skipping publish."
          else
            if [ -z "${CARGO_REGISTRY_TOKEN:-}" ]; then
              echo "CARGO_REGISTRY_TOKEN is not set; cannot publish." >&2
              exit 1
            fi
            cargo publish -p sacp-cbor-derive --locked
          fi

          if [ "$published" -eq 0 ]; then
            echo "Version ${version} is already on crates.io; skipping publish."
          else
            if [ -z "${CARGO_REGISTRY_TOKEN:-}" ]; then
              echo "CARGO_REGISTRY_TOKEN is not set; cannot publish." >&2
              exit 1
            fi
            cargo publish --locked
          fi

          if [ "$tag_exists" -eq 0 ]; then
            git config user.name "github-actions[bot]"
            git config user.email "github-actions[bot]@users.noreply.github.com"
            git tag "${tag}"
            git push origin "refs/tags/${tag}"
          fi
