/**
 * Setup Node - Clone repositories and initialize git baseline
 * Used by: analysisGraph, implementationGraph
 */

import { spawn } from 'child_process';
import { join } from 'path';
import { z } from 'zod';

const SetupOutputSchema = z.object({
  success: z.boolean(),
  clonedRepos: z.array(z.object({
    name: z.string(),
    path: z.string(),
    isPrimary: z.boolean().optional()
  })),
  baselineCommit: z.string()
});

export const setupNode = {
  name: 'setup',
  outputSchema: SetupOutputSchema,
  execute: async (state) => {
    console.log('\n🔧 Setting up environment...');
    
    const { workspace, repos, githubToken } = state;
    const gitlabToken = process.env.GITLAB_TOKEN || '';
    const gitlabUrl = process.env.GITLAB_URL || '';
    
    // DEBUG: Log token status
    console.log(`🔑 GitHub Token: ${githubToken ? 'Present' : 'MISSING'}`);
    console.log(`🔑 GitLab Token: ${gitlabToken ? 'Present' : 'MISSING'}`);
    if (gitlabUrl) console.log(`🔑 GitLab URL: ${gitlabUrl}`);
    
    // Log environment
    console.log('Container: ECS Fargate');
    console.log('Memory: 4GB');
    console.log('CPU: 2 vCPU');
    console.log('Tools: Node.js, Git, Cursor CLI, Zibby CLI');
    console.log(`Working directory: ${workspace}`);
    
    // Clone repositories
    console.log('\n📦 Cloning repositories...');
    
    const clonedRepos = [];
    for (const repo of repos) {
      console.log(`Cloning ${repo.name}...`);
      
      const repoDir = join(workspace, repo.name);
      
      // Use token for authentication based on provider
      let cloneUrl = repo.url;
      let cloneEnv = {};
      const isGitlab = repo.provider === 'gitlab' || (gitlabUrl && repo.url.includes(new URL(gitlabUrl).host));
      const isGithub = repo.provider === 'github' || repo.url.includes('github.com');
      
      if (isGithub && githubToken) {
        cloneUrl = repo.url.replace('https://github.com', `https://x-access-token:${githubToken}@github.com`);
        cloneEnv = { ...process.env, GIT_TERMINAL_PROMPT: '0', GIT_ASKPASS: 'echo' };
      } else if (isGitlab && gitlabToken && gitlabUrl) {
        try {
          const gitlabHost = new URL(gitlabUrl).host;
          cloneUrl = repo.url.replace(`https://${gitlabHost}`, `https://oauth2:${gitlabToken}@${gitlabHost}`);
        } catch (e) {
          console.warn(`⚠️ Failed to parse GITLAB_URL: ${e.message}`);
        }
        cloneEnv = { ...process.env, GIT_TERMINAL_PROMPT: '0', GIT_ASKPASS: 'echo' };
      }
      
      // Shallow clone with progress output (async, non-blocking)
      await execCommand(
        `git clone --progress --depth 1 --branch ${repo.branch} "${cloneUrl}" "${repoDir}"`,
        workspace,
        cloneEnv
      );
      console.log(`✓ Cloned ${repo.name} on branch ${repo.branch}`);
      
      clonedRepos.push({
        name: repo.name,
        path: repoDir,
        isPrimary: repo.isPrimary
      });
    }
    
    // Initialize git in workspace for diff tracking
    await execCommand('git init', workspace);
    await execCommand('git config user.email "zibby@agent.com"', workspace);
    await execCommand('git config user.name "Zibby Agent"', workspace);
    await execCommand('git add .', workspace);
    await execCommand('git commit --allow-empty -m "baseline"', workspace);
    
    console.log('✅ Environment ready');
    
    const baselineCommit = await execCommand('git rev-parse HEAD', workspace);
    
    return {
      success: true,
      clonedRepos,
      baselineCommit: baselineCommit.trim()
    };
  }
};

// Async version using spawn - streams output in real-time, doesn't block event loop
async function execCommand(command, cwd, env = {}) {
  return new Promise((resolve, reject) => {
    const proc = spawn(command, {
      cwd,
      shell: true,
      env: Object.keys(env).length > 0 ? env : process.env
    });
    
    let stdout = '';
    let stderr = '';
    
    // Stream stdout as it comes (triggers middleware setInterval!)
    proc.stdout.on('data', (data) => {
      const output = data.toString();
      stdout += output;
      console.log(output.trimEnd());
    });
    
    // Stream stderr as it comes
    proc.stderr.on('data', (data) => {
      const output = data.toString();
      stderr += output;
      console.log(output.trimEnd());
    });
    
    proc.on('close', (code) => {
      if (code !== 0) {
        reject(new Error(`Command failed with exit code ${code}: ${command}`));
      } else {
        resolve(stdout || stderr || '');
      }
    });
    
    proc.on('error', (err) => {
      reject(new Error(`Command error: ${command} - ${err.message}`));
    });
  });
}
