#!/usr/bin/env node

/**
 * API Changes Check Script
 * 
 * Checks for unintended API changes and blocks release if API changed
 * without proper commit type (feat/breaking).
 * 
 * @author Matthew Raymer
 * @version 1.0.0
 */

const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');

const API_CHECKSUM_FILE = path.join(__dirname, '..', 'api-checksum.txt');
const DIST_TYPES_DIR = path.join(__dirname, '..', 'dist', 'esm');

/**
 * Generate checksum of API definitions
 * @returns {string} Checksum of API files
 */
function generateApiChecksum() {
  try {
    // Get all .d.ts files in dist/esm
    const typeFiles = execSync(`find "${DIST_TYPES_DIR}" -name "*.d.ts" -type f`, { encoding: 'utf8' })
      .trim()
      .split('\n')
      .filter(file => file.length > 0);

    if (typeFiles.length === 0) {
      console.warn('⚠️  No TypeScript definition files found in dist/esm');
      return '';
    }

    // Generate checksum of all type files
    const checksum = execSync(`cat ${typeFiles.join(' ')} | shasum -a 256`, { encoding: 'utf8' })
      .trim()
      .split(' ')[0];

    return checksum;
  } catch (error) {
    console.error('Error generating API checksum:', error.message);
    return '';
  }
}

/**
 * Get last commit message
 * @returns {string} Last commit message
 */
function getLastCommitMessage() {
  try {
    return execSync('git log -1 --pretty=%B', { encoding: 'utf8' }).trim();
  } catch (error) {
    console.error('Error getting last commit message:', error.message);
    return '';
  }
}

/**
 * Check if commit message indicates API change
 * @param {string} commitMessage - Commit message
 * @returns {boolean} True if API change is allowed
 */
function isApiChangeAllowed(commitMessage) {
  const allowedPatterns = [
    /^feat\(/i,
    /^fix\(/i,
    /BREAKING CHANGE/i,
    /^feat!/i,
    /^fix!/i
  ];

  return allowedPatterns.some(pattern => pattern.test(commitMessage));
}

/**
 * Check API changes and enforce rules
 */
function checkApiChanges() {
  console.log('🔍 Checking API changes...');

  if (!fs.existsSync(DIST_TYPES_DIR)) {
    console.error('❌ Dist types directory not found. Run "npm run build" first.');
    process.exit(1);
  }

  const currentChecksum = generateApiChecksum();
  
  if (!currentChecksum) {
    console.error('❌ Could not generate API checksum');
    process.exit(1);
  }

  let previousChecksum = '';
  if (fs.existsSync(API_CHECKSUM_FILE)) {
    previousChecksum = fs.readFileSync(API_CHECKSUM_FILE, 'utf8').trim();
  }

  if (previousChecksum === currentChecksum) {
    console.log('✅ No API changes detected');
    return;
  }

  console.log('⚠️  API changes detected');
  console.log(`Previous: ${previousChecksum.substring(0, 8)}...`);
  console.log(`Current:  ${currentChecksum.substring(0, 8)}...`);

  const commitMessage = getLastCommitMessage();
  console.log(`Last commit: ${commitMessage}`);

  if (!isApiChangeAllowed(commitMessage)) {
    console.error('\n❌ API changes detected without proper commit type!');
    console.error('🚫 Release blocked. API changes require:');
    console.error('   - feat(scope): description');
    console.error('   - fix(scope): description');
    console.error('   - BREAKING CHANGE in commit message');
    console.error('   - feat!(scope): or fix!(scope): for breaking changes');
    process.exit(1);
  }

  console.log('✅ API changes allowed by commit type');
  
  // Update checksum file
  fs.writeFileSync(API_CHECKSUM_FILE, currentChecksum);
  console.log('📝 Updated API checksum file');
}

// Run the check
checkApiChanges();
