#!/usr/bin/env node
/**
 * DSS Git Backup Hook
 * Automatically commits changes when Claude Code session ends.
 * Written from scratch for DSS.
 */

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

// Configuration
const DEFAULT_CONFIG = {
  git_backup: {
    enabled: true,
    require_git_repo: true,
    commit_only_if_changes: true,
    include_timestamp: true,
    commit_prefix: 'auto-backup',
    show_logs: false
  }
};

// Prevent duplicate execution (Claude Code bug workaround)
const STATE_DIR = path.join(__dirname, '..', '.state');
const LOCK_FILE = path.join(STATE_DIR, '.git-backup.lock');
const LOCK_TIMEOUT_MS = 3000;

function loadConfig() {
  const configPath = path.join(process.env.HOME || '', '.dss', 'hooks-config.json');
  try {
    if (fs.existsSync(configPath)) {
      const userConfig = JSON.parse(fs.readFileSync(configPath, 'utf8'));
      return { ...DEFAULT_CONFIG, ...userConfig };
    }
  } catch (e) {
    // Use defaults
  }
  return DEFAULT_CONFIG;
}

function checkLock() {
  try {
    if (!fs.existsSync(STATE_DIR)) {
      fs.mkdirSync(STATE_DIR, { recursive: true });
    }
    
    if (fs.existsSync(LOCK_FILE)) {
      const lastRun = parseInt(fs.readFileSync(LOCK_FILE, 'utf8'));
      if (!isNaN(lastRun) && (Date.now() - lastRun < LOCK_TIMEOUT_MS)) {
        return false; // Already ran recently
      }
    }
    
    fs.writeFileSync(LOCK_FILE, Date.now().toString(), 'utf8');
    return true;
  } catch (e) {
    return true; // Proceed on error
  }
}

function isGitRepo() {
  try {
    execSync('git rev-parse --is-inside-work-tree', { stdio: 'pipe' });
    return true;
  } catch (e) {
    return false;
  }
}

function hasChanges() {
  try {
    const status = execSync('git status --porcelain', { encoding: 'utf8' });
    return status.trim().length > 0;
  } catch (e) {
    return false;
  }
}

function getChangeSummary() {
  try {
    const status = execSync('git status --short', { encoding: 'utf8' });
    const lines = status.trim().split('\n').filter(Boolean);
    
    let added = 0, modified = 0, deleted = 0;
    
    for (const line of lines) {
      const status = line.trim().charAt(0);
      if (status === 'A' || status === '?') added++;
      else if (status === 'M') modified++;
      else if (status === 'D') deleted++;
    }
    
    return { added, modified, deleted, total: lines.length };
  } catch (e) {
    return { added: 0, modified: 0, deleted: 0, total: 0 };
  }
}

function createBackup(config) {
  const backupConfig = config.git_backup || {};
  
  try {
    // Stage all changes
    execSync('git add -A', { stdio: 'pipe' });
    
    // Build commit message
    const parts = [backupConfig.commit_prefix || 'auto-backup'];
    
    if (backupConfig.include_timestamp) {
      const timestamp = new Date().toISOString().replace('T', ' ').replace(/\..+/, '');
      parts.push(timestamp);
    }
    
    const summary = getChangeSummary();
    const summaryText = `(${summary.total} files: +${summary.added} ~${summary.modified} -${summary.deleted})`;
    
    const commitMessage = `${parts.join(': ')} ${summaryText}\n\nGenerated by DSS Git Backup Hook`;
    
    // Create commit
    execSync(`git commit -m "${commitMessage}"`, { stdio: 'pipe' });
    
    // Get commit hash
    const commitHash = execSync('git rev-parse --short HEAD', { encoding: 'utf8' }).trim();
    
    return { success: true, hash: commitHash, files: summary.total };
  } catch (e) {
    return { success: false, error: e.message };
  }
}

function log(config, message) {
  if (config.git_backup?.show_logs) {
    console.log(JSON.stringify({
      systemMessage: message,
      continue: true
    }));
  }
}

function main() {
  // Prevent duplicate execution
  if (!checkLock()) {
    process.exit(0);
  }
  
  // Prevent hook recursion
  if (process.env.STOP_HOOK_ACTIVE === 'true') {
    process.exit(0);
  }
  
  const config = loadConfig();
  
  if (!config.git_backup?.enabled) {
    process.exit(0);
  }
  
  // Check for git repo
  if (config.git_backup.require_git_repo && !isGitRepo()) {
    log(config, 'DSS Git Backup: Not a git repository, skipping');
    process.exit(0);
  }
  
  // Check for changes
  if (config.git_backup.commit_only_if_changes && !hasChanges()) {
    log(config, 'DSS Git Backup: No changes to commit');
    process.exit(0);
  }
  
  // Create backup
  const result = createBackup(config);
  
  if (result.success) {
    log(config, `DSS Git Backup: Committed ${result.files} files (${result.hash})`);
  } else {
    log(config, `DSS Git Backup: Failed - ${result.error}`);
  }
  
  process.exit(0);
}

main();
