# Standalone npm publish workflow - publishes npm package without full release
# Uses existing GitHub release binaries (downloads on npm install)

name: Release npm

on:
  workflow_dispatch:
  workflow_call:
    inputs:
      version:
        required: false
        type: string

permissions:
  contents: read
  id-token: write

jobs:
  release-npm:
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v6

      - name: Determine version
        id: version
        run: |
          if [ -n "${{ inputs.version }}" ]; then
            VERSION="${{ inputs.version }}"
          else
            VERSION=$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/')
          fi
          echo "version=$VERSION" >> "$GITHUB_OUTPUT"
          echo "Publishing npm package for version: $VERSION"

      - name: Setup Node.js
        uses: actions/setup-node@v6
        with:
          node-version: '24'

      - name: Update npm
        run: npm install -g npm@latest

      - name: Create npm package
        env:
          VERSION: ${{ steps.version.outputs.version }}
        run: |
          mkdir -p npm-package

          # Create package.json
          cat > npm-package/package.json << PKGJSON
          {
            "name": "@fresh-editor/fresh-editor",
            "version": "${VERSION}",
            "description": "A modern terminal-based text editor with plugin support",
            "repository": {
              "type": "git",
              "url": "https://github.com/sinelaw/fresh.git"
            },
            "license": "Apache-2.0",
            "bin": {
              "fresh": "run-fresh.js"
            },
            "scripts": {
              "postinstall": "node install.js"
            },
            "files": [
              "binary.js",
              "binary-install.js",
              "install.js",
              "run-fresh.js",
              "README.md",
              "LICENSE",
              "CHANGELOG.md"
            ],
            "os": ["darwin", "linux", "win32"],
            "cpu": ["x64", "arm64"],
            "keywords": ["editor", "terminal", "cli", "text-editor", "vim"],
            "engines": {
              "node": ">=18"
            }
          }
          PKGJSON

          # Create binary.js - platform detection and download
          cat > npm-package/binary.js << 'BINARYJS'
          const os = require('os');
          const path = require('path');

          function getBinaryInfo() {
            const platform = os.platform();
            const arch = os.arch();

            const targets = {
              'darwin-x64': { target: 'x86_64-apple-darwin', ext: 'tar.xz' },
              'darwin-arm64': { target: 'aarch64-apple-darwin', ext: 'tar.xz' },
              'linux-x64': { target: 'x86_64-unknown-linux-gnu', ext: 'tar.xz' },
              'linux-arm64': { target: 'aarch64-unknown-linux-gnu', ext: 'tar.xz' },
              'win32-x64': { target: 'x86_64-pc-windows-msvc', ext: 'zip' },
              'win32-arm64': { target: 'aarch64-pc-windows-msvc', ext: 'zip' }
            };

            const key = `${platform}-${arch}`;
            const info = targets[key];

            if (!info) {
              throw new Error(`Unsupported platform: ${platform}-${arch}`);
            }

            return {
              ...info,
              binaryName: platform === 'win32' ? 'fresh.exe' : 'fresh'
            };
          }

          module.exports = { getBinaryInfo };
          BINARYJS

          # Create binary-install.js - download and extract logic
          cat > npm-package/binary-install.js << 'INSTALLJS'
          const https = require('https');
          const fs = require('fs');
          const path = require('path');
          const { execSync } = require('child_process');
          const { getBinaryInfo } = require('./binary');

          const VERSION = require('./package.json').version;
          const REPO = 'sinelaw/fresh';

          function download(url, dest) {
            return new Promise((resolve, reject) => {
              const file = fs.createWriteStream(dest);
              file.on('error', (err) => {
                file.close();
                reject(err);
              });
              https.get(url, (response) => {
                if (response.statusCode === 302 || response.statusCode === 301) {
                  file.close(() => {
                    download(response.headers.location, dest).then(resolve).catch(reject);
                  });
                  return;
                }
                if (response.statusCode !== 200) {
                  file.close();
                  reject(new Error(`Failed to download: ${response.statusCode}`));
                  return;
                }
                response.pipe(file);
                file.on('finish', () => { file.close(); resolve(); });
              }).on('error', (err) => {
                file.close();
                reject(err);
              });
            });
          }

          async function install() {
            const info = getBinaryInfo();
            const archiveName = `fresh-editor-${info.target}.${info.ext}`;
            const url = `https://github.com/${REPO}/releases/download/v${VERSION}/${archiveName}`;
            const archivePath = path.join(__dirname, archiveName);
            const binDir = path.join(__dirname, 'bin');
            const binaryPath = path.join(binDir, info.binaryName);

            console.log(`Downloading ${url}...`);
            await download(url, archivePath);

            // Verify download succeeded
            const stats = fs.statSync(archivePath);
            if (stats.size === 0) {
              throw new Error(`Downloaded file is empty: ${archivePath}`);
            }
            console.log(`Downloaded ${stats.size} bytes`);

            fs.mkdirSync(binDir, { recursive: true });

            if (info.ext === 'tar.xz') {
              execSync(`tar -xJf "${archivePath}" -C "${binDir}" --strip-components=1`, { stdio: 'inherit' });
            } else if (info.ext === 'zip') {
              if (process.platform === 'win32') {
                execSync(`powershell -Command "Expand-Archive -Path '${archivePath}' -DestinationPath '${binDir}' -Force"`, { stdio: 'inherit' });
                // Move files from nested directory
                const nested = path.join(binDir, `fresh-editor-${info.target}`);
                if (fs.existsSync(nested)) {
                  fs.readdirSync(nested).forEach(f => {
                    fs.renameSync(path.join(nested, f), path.join(binDir, f));
                  });
                  fs.rmdirSync(nested);
                }
              } else {
                execSync(`unzip -o "${archivePath}" -d "${binDir}"`, { stdio: 'inherit' });
              }
            }

            fs.unlinkSync(archivePath);

            // Verify binary exists
            if (!fs.existsSync(binaryPath)) {
              throw new Error(`Installation failed: binary not found at ${binaryPath}`);
            }

            console.log('fresh-editor installed successfully!');
          }

          module.exports = { install };
          INSTALLJS

          # Create install.js
          cat > npm-package/install.js << 'POSTINSTALL'
          const { install } = require('./binary-install');
          install().catch(err => { console.error(err); process.exit(1); });
          POSTINSTALL

          # Create run-fresh.js
          cat > npm-package/run-fresh.js << 'RUNJS'
          #!/usr/bin/env node
          const { spawn } = require('child_process');
          const path = require('path');
          const { getBinaryInfo } = require('./binary');

          const info = getBinaryInfo();
          const binPath = path.join(__dirname, 'bin', info.binaryName);

          const child = spawn(binPath, process.argv.slice(2), { stdio: 'inherit' });
          child.on('exit', (code) => process.exit(code || 0));
          RUNJS

          # Copy supporting files. Plugins/themes are embedded in the binary.
          cp README.md LICENSE CHANGELOG.md npm-package/ 2>/dev/null || true

          # Create the tarball
          cd npm-package
          npm pack
          mv *.tgz ../fresh-editor-npm-package.tar.gz
          cd ..

          echo "Created npm package:"
          ls -la fresh-editor-npm-package.tar.gz

      - name: Publish to npm with provenance (OIDC)
        env:
          VERSION: ${{ steps.version.outputs.version }}
        run: |
          echo "Publishing npm package for version ${VERSION}"
          npm publish --access public --provenance ./fresh-editor-npm-package.tar.gz
