name: Release

on:
  push:
    tags:
      - "v*.*.*"
  workflow_dispatch:
    inputs:
      version:
        description: "Version to release (e.g., v0.1.0)"
        required: true
        type: string
      dry_run:
        description: "Dry run (skip GitHub release and crates.io publish)"
        required: false
        type: boolean
        default: true
      publish_crate:
        description: "Publish to crates.io (ignored if dry_run is true)"
        required: false
        type: boolean
        default: false

permissions:
  contents: write

env:
  CARGO_TERM_COLOR: always
  BINARY_NAME: tuigram

jobs:
  prepare:
    name: Prepare
    runs-on: ubuntu-latest
    outputs:
      version: ${{ steps.config.outputs.version }}
      dry_run: ${{ steps.config.outputs.dry_run }}
      publish_crate: ${{ steps.config.outputs.publish_crate }}
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

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

      - name: Cache Cargo dependencies
        uses: Swatinem/rust-cache@v2

      - name: Determine version and mode
        id: config
        run: |
          if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
            echo "version=${{ inputs.version }}" >> $GITHUB_OUTPUT
            echo "dry_run=${{ inputs.dry_run }}" >> $GITHUB_OUTPUT
            echo "publish_crate=${{ inputs.publish_crate }}" >> $GITHUB_OUTPUT
          else
            echo "version=${{ github.ref_name }}" >> $GITHUB_OUTPUT
            echo "dry_run=false" >> $GITHUB_OUTPUT
            echo "publish_crate=false" >> $GITHUB_OUTPUT
          fi

      - name: Print configuration
        run: |
          echo "🏷️  Version: ${{ steps.config.outputs.version }}"
          echo "🧪 Dry run: ${{ steps.config.outputs.dry_run }}"
          echo "📦 Publish to crates.io: ${{ steps.config.outputs.publish_crate }}"

      - name: Verify crate version matches tag
        run: |
          TAG="${{ steps.config.outputs.version }}"
          TAG_VERSION="${TAG#v}"
          CARGO_VERSION=$(grep -m1 '^version' Cargo.toml | sed 's/.*"\(.*\)".*/\1/')
          if [[ "$TAG_VERSION" != "$CARGO_VERSION" ]]; then
            echo "❌ Error: Tag version ($TAG_VERSION) does not match Cargo.toml version ($CARGO_VERSION)"
            exit 1
          fi
          echo "✅ Version verified: $CARGO_VERSION"

      - name: Run tests
        run: cargo test --all --verbose

      - name: Run clippy
        run: cargo clippy -- -D warnings

      - name: Dry run cargo publish
        run: cargo publish --dry-run

  build:
    name: Build ${{ matrix.target }}
    needs: prepare
    if: needs.prepare.outputs.dry_run == 'false'
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        include:
          - target: x86_64-unknown-linux-gnu
            os: ubuntu-latest
          - target: x86_64-unknown-linux-musl
            os: ubuntu-latest
          - target: aarch64-unknown-linux-gnu
            os: ubuntu-latest
          - target: x86_64-apple-darwin
            os: macos-latest
          - target: aarch64-apple-darwin
            os: macos-latest
          - target: x86_64-pc-windows-msvc
            os: windows-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Install Rust stable
        uses: dtolnay/rust-toolchain@stable
        with:
          targets: ${{ matrix.target }}

      - name: Install musl-tools (Linux musl)
        if: matrix.target == 'x86_64-unknown-linux-musl'
        run: sudo apt-get update && sudo apt-get install -y musl-tools

      - name: Install cross-compilation tools (Linux ARM)
        if: matrix.target == 'aarch64-unknown-linux-gnu'
        run: |
          sudo apt-get update
          sudo apt-get install -y gcc-aarch64-linux-gnu

      - name: Cache Cargo dependencies
        uses: Swatinem/rust-cache@v2
        with:
          key: ${{ matrix.target }}

      - name: Build binary
        run: cargo build --release --target ${{ matrix.target }}
        env:
          CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc

      - name: Package binary (Unix)
        if: runner.os != 'Windows'
        run: |
          cd target/${{ matrix.target }}/release
          tar czvf ../../../${{ env.BINARY_NAME }}-${{ needs.prepare.outputs.version }}-${{ matrix.target }}.tar.gz ${{ env.BINARY_NAME }}

      - name: Package binary (Windows)
        if: runner.os == 'Windows'
        run: |
          cd target/${{ matrix.target }}/release
          7z a ../../../${{ env.BINARY_NAME }}-${{ needs.prepare.outputs.version }}-${{ matrix.target }}.zip ${{ env.BINARY_NAME }}.exe

      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: ${{ env.BINARY_NAME }}-${{ matrix.target }}
          path: ${{ env.BINARY_NAME }}-${{ needs.prepare.outputs.version }}-${{ matrix.target }}.*

  release:
    name: Release
    needs: [prepare, build]
    if: needs.prepare.outputs.dry_run == 'false'
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Download all artifacts
        uses: actions/download-artifact@v4
        with:
          path: artifacts
          merge-multiple: true

      - name: List artifacts
        run: ls -la artifacts/

      - name: Install git-cliff
        uses: taiki-e/install-action@v2
        with:
          tool: git-cliff

      - name: Generate changelog
        run: |
          TAG="${{ needs.prepare.outputs.version }}"
          git cliff --unreleased --tag "$TAG" --strip all -o RELEASE_CHANGELOG.md
          git cliff --tag "$TAG" -o CHANGELOG.md

      - name: Commit changelog
        run: |
          TAG="${{ needs.prepare.outputs.version }}"
          git config user.name "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"
          git add CHANGELOG.md
          git commit -m "chore(release): update changelog for $TAG" || echo "No changes to commit"
          git push origin HEAD:main

      - name: Update tag
        run: |
          TAG="${{ needs.prepare.outputs.version }}"
          git tag -f "$TAG" -m "Release $TAG"
          git push origin "$TAG" --force

      - name: Create GitHub release
        uses: softprops/action-gh-release@v2
        with:
          tag_name: ${{ needs.prepare.outputs.version }}
          name: ${{ needs.prepare.outputs.version }}
          body_path: RELEASE_CHANGELOG.md
          draft: false
          prerelease: ${{ contains(needs.prepare.outputs.version, '-') }}
          files: artifacts/*
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Summary
        run: |
          echo ""
          echo "========== Release Summary =========="
          echo "Version: ${{ needs.prepare.outputs.version }}"
          echo "GitHub Release: ✅ Created with binaries"
          echo "====================================="

  publish:
    name: Publish to crates.io
    needs: [prepare, release]
    if: needs.prepare.outputs.dry_run == 'false' && needs.prepare.outputs.publish_crate == 'true'
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

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

      - name: Cache Cargo dependencies
        uses: Swatinem/rust-cache@v2

      - name: Publish to crates.io
        run: cargo publish --token ${{ secrets.CARGO_REGISTRY_TOKEN }}
        env:
          CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}

      - name: Summary
        run: |
          echo ""
          echo "========== Publish Summary =========="
          echo "Version: ${{ needs.prepare.outputs.version }}"
          echo "crates.io: ✅ Published"
          echo "====================================="

  dry-run-summary:
    name: Dry Run Summary
    needs: prepare
    if: needs.prepare.outputs.dry_run == 'true'
    runs-on: ubuntu-latest
    steps:
      - name: Summary
        run: |
          echo ""
          echo "========== Dry Run Summary =========="
          echo "Version: ${{ needs.prepare.outputs.version }}"
          echo "Status: ✅ All checks passed"
          echo ""
          echo "To perform an actual release, run again with dry_run: false"
          echo "====================================="