import { JSONSchema7 } from 'json-schema';
import { randomUUID } from 'crypto';
import { exec } from 'child_process';
import { promisify } from 'util';
import { promises as fs } from 'fs';
import path from 'path';
import { createTool, createSuccessResult, createErrorResult } from '../../core/tool-framework.js';
import { ToolRegistration, RequestContext } from '../../core/types.js';

const execAsync = promisify(exec);

/**
 * Developer Workflow Tools - 12-Factor MCP Implementation
 * 
 * Implements Factor 2: Deterministic Execution with structured outputs
 * Implements Factor 3: Stateless Processes with RequestContext
 * Implements Factor 4: Structured Outputs for LLM consumption
 * Implements TDD enforcement and development workflow management
 */

// Input type interfaces
interface StartFeatureInput {
  featureName: string;
  branchFrom?: string;
  description?: string;
}

interface CheckWorkflowStatusInput {
  includeTests?: boolean;
  includeGitStatus?: boolean;
}

interface SuggestNextActionInput {
  currentContext?: string;
}

interface RunTDDCycleInput {
  featureId?: string;
  testCommand?: string;
  testFile?: string;
  phase?: 'red' | 'green' | 'refactor';
}

interface SetupCommitHooksInput {
  preCommit?: boolean;
  prePush?: boolean;
  commitMsg?: boolean;
  preRebase?: boolean;
}

interface WriteTestInput {
  featureId?: string;
  testName: string;
  testType?: 'unit' | 'integration' | 'e2e';
  description?: string;
  expectedBehavior: string;
}

interface RunTestsInput {
  featureId?: string;
  testFile?: string;
  watch?: boolean;
  coverage?: boolean;
}

interface CompleteFeatureInput {
  featureId: string;
  createPR?: boolean;
  prTitle?: string;
  prDescription?: string;
}

/**
 * Start a new feature with TDD workflow
 */
const startFeatureTool = createTool<StartFeatureInput, any>({
  name: 'start_feature',
  description: 'Start a new feature with TDD workflow and branch management',
  category: 'developer-workflow',
  inputSchema: {
    type: 'object',
    properties: {
      featureName: {
        type: 'string',
        description: 'Name of the feature (will be used for branch name)',
        minLength: 1,
        maxLength: 100,
        pattern: '^[a-zA-Z0-9-_]+$'
      },
      branchFrom: {
        type: 'string',
        default: 'main',
        description: 'Base branch to create feature branch from',
        maxLength: 100
      },
      description: {
        type: 'string',
        description: 'Optional description of the feature',
        maxLength: 500
      }
    },
    required: ['featureName'],
    additionalProperties: false
  } as JSONSchema7,

  async execute(input: StartFeatureInput, context: RequestContext) {
    try {
      const featureId = randomUUID();
      const now = Date.now();
      const branchName = `feature/${input.featureName}`;

      // Check for uncommitted changes
      const { stdout: status } = await execAsync('git status --porcelain');
      if (status.trim()) {
        return createErrorResult({
          code: 'UNCOMMITTED_CHANGES',
          message: 'You have uncommitted changes. Please commit or stash them before starting a new feature.',
          category: 'validation'
        });
      }

      // Create and checkout new branch
      try {
        await execAsync(`git checkout -b ${branchName} ${input.branchFrom || 'main'}`);
      } catch (error) {
        return createErrorResult({
          code: 'GIT_ERROR',
          message: `Failed to create feature branch: ${error instanceof Error ? error.message : 'Unknown error'}`,
          category: 'execution'
        });
      }

      // Store feature in database
      const result = await context.db.run(
        `INSERT INTO development_features 
         (id, project_id, name, description, status, created_at, updated_at) 
         VALUES (?, ?, ?, ?, ?, ?, ?)`,
        [
          featureId,
          context.projectId || 'default',
          input.featureName,
          input.description || '',
          'planning',
          now,
          now
        ]
      );

      if (!result.success) {
        return createErrorResult({
          code: 'DATABASE_ERROR',
          message: 'Failed to save feature to database',
          details: { error: result.error },
          category: 'system'
        });
      }

      // Get TDD configuration
      const tddConfig = await context.db.get(
        'SELECT * FROM development_tdd_config WHERE project_id = ?',
        [context.projectId || 'default']
      );

      return createSuccessResult({
        feature: {
          id: featureId,
          name: input.featureName,
          description: input.description,
          branch: branchName,
          status: 'planning',
          tddRequired: tddConfig.data?.enforce_test_first !== false
        },
        workflow: {
          currentStep: 'write_tests',
          nextSteps: [
            'Write failing tests for your feature',
            'Run tests to verify they fail (RED phase)',
            'Implement minimal code to make tests pass (GREEN phase)',
            'Refactor while keeping tests green (REFACTOR phase)'
          ]
        },
        message: `Started feature: ${input.featureName}`,
        suggestions: [
          'Use "write_test" to create your first test',
          'Use "run_tdd_cycle" to guide through TDD phases',
          'Use "check_workflow_status" to see current progress'
        ]
      });

    } catch (error) {
      return createErrorResult({
        code: 'EXECUTION_ERROR',
        message: `Failed to start feature: ${error instanceof Error ? error.message : 'Unknown error'}`,
        category: 'execution'
      });
    }
  }
});

/**
 * Check current development workflow status
 */
const checkWorkflowStatusTool = createTool<CheckWorkflowStatusInput, any>({
  name: 'check_workflow_status',
  description: 'Check current development workflow status including TDD phase and git state',
  category: 'developer-workflow',
  readOnly: true,
  inputSchema: {
    type: 'object',
    properties: {
      includeTests: {
        type: 'boolean',
        default: true,
        description: 'Include test status in the response'
      },
      includeGitStatus: {
        type: 'boolean',
        default: true,
        description: 'Include git status in the response'
      }
    },
    additionalProperties: false
  } as JSONSchema7,

  async execute(input: CheckWorkflowStatusInput, context: RequestContext) {
    try {
      const status: any = {
        project: context.projectId || 'default',
        timestamp: new Date().toISOString()
      };

      // Get current git status
      if (input.includeGitStatus !== false) {
        try {
          const { stdout: branch } = await execAsync('git branch --show-current');
          const { stdout: gitStatus } = await execAsync('git status --porcelain');
          const { stdout: ahead } = await execAsync('git rev-list --count @{u}..HEAD 2>/dev/null || echo "0"');
          const { stdout: behind } = await execAsync('git rev-list --count HEAD..@{u} 2>/dev/null || echo "0"');

          status.git = {
            currentBranch: branch.trim(),
            uncommittedChanges: gitStatus.split('\n').filter(line => line.trim()).length,
            changedFiles: gitStatus.split('\n').filter(line => line.trim()).map(line => line.substring(3)),
            aheadOfRemote: parseInt(ahead.trim()),
            behindRemote: parseInt(behind.trim())
          };
        } catch (error) {
          status.git = {
            error: 'Failed to get git status',
            details: error instanceof Error ? error.message : 'Unknown error'
          };
        }
      }

      // Get active feature
      const activeFeature = await context.db.get(
        `SELECT * FROM development_features 
         WHERE project_id = ? AND status != 'completed' 
         ORDER BY created_at DESC LIMIT 1`,
        [context.projectId || 'default']
      );

      if (activeFeature.data) {
        status.activeFeature = {
          id: activeFeature.data.id,
          name: activeFeature.data.name,
          status: activeFeature.data.status,
          testCoverage: activeFeature.data.test_coverage || 0
        };

        // Get current TDD session
        const tddSession = await context.db.get(
          `SELECT * FROM development_tdd_sessions 
           WHERE feature_id = ? AND completed_at IS NULL 
           ORDER BY started_at DESC LIMIT 1`,
          [activeFeature.data.id]
        );

        if (tddSession.data) {
          status.tddSession = {
            id: tddSession.data.id,
            currentPhase: tddSession.data.current_phase,
            startedAt: new Date(tddSession.data.started_at).toISOString()
          };
        }

        // Get test cases for this feature
        if (input.includeTests !== false) {
          const testCases = await context.db.all(
            `SELECT * FROM development_test_cases 
             WHERE feature_id = ? ORDER BY created_at`,
            [activeFeature.data.id]
          );

          status.tests = {
            total: testCases.data?.length || 0,
            passing: testCases.data?.filter(t => t.status === 'passing').length || 0,
            failing: testCases.data?.filter(t => t.status === 'failing').length || 0,
            pending: testCases.data?.filter(t => t.status === 'pending').length || 0
          };
        }
      }

      // Get TDD configuration
      const tddConfig = await context.db.get(
        'SELECT * FROM development_tdd_config WHERE project_id = ?',
        [context.projectId || 'default']
      );

      status.tddConfig = {
        enforceTestFirst: tddConfig.data?.enforce_test_first !== false,
        minimumCoverage: tddConfig.data?.minimum_test_coverage || 80,
        requireTestsBeforeImplementation: tddConfig.data?.require_tests_before_implementation !== false
      };

      // Calculate workflow recommendations
      const recommendations = [];
      if (!status.activeFeature) {
        recommendations.push('Start a new feature with "start_feature"');
      } else if (status.tests?.total === 0) {
        recommendations.push('Write your first test with "write_test"');
      } else if (status.tests?.failing > 0) {
        recommendations.push('Fix failing tests or implement features to make them pass');
      } else if (status.tests?.passing > 0 && status.git?.uncommittedChanges > 0) {
        recommendations.push('Commit your progress');
      }

      status.recommendations = recommendations;

      return createSuccessResult({
        status,
        message: 'Workflow status retrieved successfully'
      });

    } catch (error) {
      return createErrorResult({
        code: 'EXECUTION_ERROR',
        message: `Failed to check workflow status: ${error instanceof Error ? error.message : 'Unknown error'}`,
        category: 'execution'
      });
    }
  }
});

/**
 * Get AI suggestions for next development steps
 */
const suggestNextActionTool = createTool<SuggestNextActionInput, any>({
  name: 'suggest_next_action',
  description: 'Get AI-powered suggestions for next development steps based on current workflow state',
  category: 'developer-workflow',
  readOnly: true,
  inputSchema: {
    type: 'object',
    properties: {
      currentContext: {
        type: 'string',
        description: 'Additional context about what you are working on',
        maxLength: 500
      }
    },
    additionalProperties: false
  } as JSONSchema7,

  async execute(input: SuggestNextActionInput, context: RequestContext) {
    try {
      // Get current workflow status
      const statusResult = await checkWorkflowStatusTool.execute({}, context);
      if (!statusResult.success) {
        return statusResult;
      }

      const status = statusResult.data.status;
      const suggestions: any[] = [];

      // Analyze current state and provide suggestions
      if (!status.activeFeature) {
        suggestions.push({
          action: 'start_feature',
          priority: 'high',
          reason: 'No active feature detected',
          description: 'Begin by starting a new feature to establish TDD workflow',
          nextSteps: ['Define feature requirements', 'Create feature branch', 'Write first test']
        });
      } else {
        const feature = status.activeFeature;
        const tests = status.tests || {};
        const git = status.git || {};

        // TDD Phase analysis
        if (tests.total === 0) {
          suggestions.push({
            action: 'write_test',
            priority: 'critical',
            reason: 'No tests written for active feature',
            description: 'Start TDD cycle by writing a failing test',
            nextSteps: ['Define expected behavior', 'Write failing test', 'Verify test fails']
          });
        } else if (tests.failing > 0) {
          suggestions.push({
            action: 'implement_feature',
            priority: 'high',
            reason: `${tests.failing} failing test(s) detected`,
            description: 'Implement minimal code to make failing tests pass (GREEN phase)',
            nextSteps: ['Implement feature logic', 'Run tests', 'Verify tests pass']
          });
        } else if (tests.passing > 0 && git.uncommittedChanges > 0) {
          suggestions.push({
            action: 'commit_changes',
            priority: 'medium',
            reason: 'Tests passing with uncommitted changes',
            description: 'Commit your progress to save working state',
            nextSteps: ['Review changes', 'Commit with descriptive message', 'Consider refactoring']
          });
        } else if (tests.passing > 0) {
          suggestions.push({
            action: 'refactor_or_extend',
            priority: 'medium',
            reason: 'Tests passing - good time to refactor or add features',
            description: 'REFACTOR phase: Improve code quality while keeping tests green',
            nextSteps: ['Identify code smells', 'Refactor safely', 'Add edge case tests']
          });
        }

        // Git workflow suggestions
        if (git.aheadOfRemote > 0) {
          suggestions.push({
            action: 'push_changes',
            priority: 'low',
            reason: `${git.aheadOfRemote} commits ahead of remote`,
            description: 'Push local commits to remote repository',
            nextSteps: ['Review commits', 'Push to remote', 'Consider creating PR']
          });
        }

        // Coverage suggestions
        if (feature.testCoverage < (status.tddConfig?.minimumCoverage || 80)) {
          suggestions.push({
            action: 'improve_coverage',
            priority: 'medium',
            reason: `Test coverage (${feature.testCoverage}%) below minimum`,
            description: 'Add more comprehensive tests to meet coverage requirements',
            nextSteps: ['Identify uncovered code', 'Write additional tests', 'Run coverage report']
          });
        }
      }

      // Add context-specific suggestions
      if (input.currentContext) {
        suggestions.push({
          action: 'context_analysis',
          priority: 'info',
          reason: 'Based on provided context',
          description: `Consider: ${input.currentContext}`,
          nextSteps: ['Analyze current context', 'Plan implementation approach', 'Write tests first']
        });
      }

      return createSuccessResult({
        suggestions: suggestions.slice(0, 5), // Limit to top 5 suggestions
        workflowState: {
          phase: status.tddSession?.currentPhase || 'planning',
          activeFeature: status.activeFeature?.name || null,
          testsSummary: status.tests
        },
        message: 'Next action suggestions generated successfully'
      });

    } catch (error) {
      return createErrorResult({
        code: 'EXECUTION_ERROR',
        message: `Failed to generate suggestions: ${error instanceof Error ? error.message : 'Unknown error'}`,
        category: 'execution'
      });
    }
  }
});

/**
 * Run TDD cycle with guidance
 */
const runTDDCycleTool = createTool<RunTDDCycleInput, any>({
  name: 'run_tdd_cycle',
  description: 'Guide through Test-Driven Development red-green-refactor cycle',
  category: 'developer-workflow',
  inputSchema: {
    type: 'object',
    properties: {
      featureId: {
        type: 'string',
        description: 'Feature ID to run TDD cycle for (optional, uses active feature if not provided)'
      },
      testCommand: {
        type: 'string',
        default: 'npm test',
        description: 'Command to run tests',
        maxLength: 200
      },
      testFile: {
        type: 'string',
        description: 'Specific test file to run',
        maxLength: 500
      },
      phase: {
        type: 'string',
        enum: ['red', 'green', 'refactor'],
        description: 'Specific TDD phase to execute'
      }
    },
    additionalProperties: false
  } as JSONSchema7,

  async execute(input: RunTDDCycleInput, context: RequestContext) {
    try {
      // Get or determine feature
      let featureId = input.featureId;
      if (!featureId) {
        const activeFeature = await context.db.get(
          `SELECT id FROM development_features 
           WHERE project_id = ? AND status != 'completed' 
           ORDER BY created_at DESC LIMIT 1`,
          [context.projectId || 'default']
        );
        featureId = activeFeature.data?.id;
      }

      if (!featureId) {
        return createErrorResult({
          code: 'NO_ACTIVE_FEATURE',
          message: 'No active feature found. Start a feature first.',
          category: 'validation'
        });
      }

      const sessionId = randomUUID();
      const now = Date.now();

      // Create or get TDD session
      let session = await context.db.get(
        `SELECT * FROM development_tdd_sessions 
         WHERE feature_id = ? AND completed_at IS NULL 
         ORDER BY started_at DESC LIMIT 1`,
        [featureId]
      );

      if (!session.data) {
        // Create new session
        const result = await context.db.run(
          `INSERT INTO development_tdd_sessions 
           (id, feature_id, project_id, current_phase, started_at, created_at, updated_at) 
           VALUES (?, ?, ?, ?, ?, ?, ?)`,
          [sessionId, featureId, context.projectId || 'default', 'red', now, now, now]
        );

        if (!result.success) {
          return createErrorResult({
            code: 'DATABASE_ERROR',
            message: 'Failed to create TDD session',
            category: 'system'
          });
        }
        session = { success: true, data: { id: sessionId, current_phase: 'red' } };
      }

      const currentPhase = input.phase || session.data.current_phase;
      const testCommand = input.testFile ? 
        `${input.testCommand || 'npm test'} ${input.testFile}` : 
        (input.testCommand || 'npm test');

      let phaseResult: any = {};
      let nextPhase = currentPhase;

      // Execute TDD phase
      switch (currentPhase) {
        case 'red':
          phaseResult = await executeRedPhase(testCommand, featureId, context);
          nextPhase = phaseResult.testsFailingAsExpected ? 'green' : 'red';
          break;
        case 'green':
          phaseResult = await executeGreenPhase(testCommand, featureId, context);
          nextPhase = phaseResult.testsPassingNow ? 'refactor' : 'green';
          break;
        case 'refactor':
          phaseResult = await executeRefactorPhase(testCommand, featureId, context);
          nextPhase = 'red'; // Ready for next feature/test
          break;
      }

      // Update session phase
      await context.db.run(
        'UPDATE development_tdd_sessions SET current_phase = ?, updated_at = ? WHERE id = ?',
        [nextPhase, Date.now(), session.data.id]
      );

      // Record phase history
      await context.db.run(
        `INSERT INTO development_tdd_phase_history 
         (id, session_id, project_id, phase, started_at, completed_at, notes) 
         VALUES (?, ?, ?, ?, ?, ?, ?)`,
        [
          randomUUID(),
          session.data.id,
          context.projectId || 'default',
          currentPhase,
          now,
          Date.now(),
          JSON.stringify(phaseResult)
        ]
      );

      return createSuccessResult({
        tddCycle: {
          currentPhase,
          nextPhase,
          sessionId: session.data.id,
          featureId,
          result: phaseResult
        },
        guidance: getTDDPhaseGuidance(currentPhase, nextPhase, phaseResult),
        message: `TDD ${currentPhase.toUpperCase()} phase completed`
      });

    } catch (error) {
      return createErrorResult({
        code: 'EXECUTION_ERROR',
        message: `Failed to run TDD cycle: ${error instanceof Error ? error.message : 'Unknown error'}`,
        category: 'execution'
      });
    }
  }
});

// Helper functions for TDD cycle execution
async function executeRedPhase(testCommand: string, featureId: string, context: RequestContext) {
    try {
      const { stdout, stderr } = await execAsync(testCommand);
      return {
        testsFailingAsExpected: false,
        output: stdout,
        error: stderr,
        message: 'Tests are passing - you need to write a failing test first!'
      };
    } catch (error) {
      return {
        testsFailingAsExpected: true,
        output: '',
        error: error instanceof Error ? error.message : 'Tests failed as expected',
        message: 'Good! Tests are failing as expected. Now implement the feature.'
      };
    }
}

async function executeGreenPhase(testCommand: string, featureId: string, context: RequestContext) {
    try {
      const { stdout, stderr } = await execAsync(testCommand);
      return {
        testsPassingNow: true,
        output: stdout,
        error: '',
        message: 'Excellent! Tests are now passing. Ready for refactoring.'
      };
    } catch (error) {
      return {
        testsPassingNow: false,
        output: '',
        error: error instanceof Error ? error.message : 'Tests still failing',
        message: 'Tests still failing. Continue implementing the feature.'
      };
    }
}

async function executeRefactorPhase(testCommand: string, featureId: string, context: RequestContext) {
    try {
      const { stdout, stderr } = await execAsync(testCommand);
      return {
        testsStillPassing: true,
        output: stdout,
        error: '',
        message: 'Tests still passing after refactoring. Great job!'
      };
    } catch (error) {
      return {
        testsStillPassing: false,
        output: '',
        error: error instanceof Error ? error.message : 'Tests broken during refactoring',
        message: 'Tests broken during refactoring. Revert and try again.'
      };
    }
}

function getTDDPhaseGuidance(currentPhase: string, nextPhase: string, result: any) {
    const guidance: any = {
      currentPhase: currentPhase.toUpperCase(),
      nextPhase: nextPhase.toUpperCase()
    };

    switch (currentPhase) {
      case 'red':
        guidance.description = 'RED phase: Write a failing test';
        guidance.success = result.testsFailingAsExpected;
        guidance.nextSteps = result.testsFailingAsExpected ? 
          ['Implement minimal code to make the test pass'] :
          ['Write a failing test first - this is crucial for TDD'];
        break;
      case 'green':
        guidance.description = 'GREEN phase: Make the test pass';
        guidance.success = result.testsPassingNow;
        guidance.nextSteps = result.testsPassingNow ?
          ['Refactor the code while keeping tests green'] :
          ['Continue implementing until tests pass'];
        break;
      case 'refactor':
        guidance.description = 'REFACTOR phase: Improve code quality';
        guidance.success = result.testsStillPassing;
        guidance.nextSteps = result.testsStillPassing ?
          ['Write next test or complete feature'] :
          ['Revert refactoring that broke tests'];
        break;
    }

    return guidance;
}

/**
 * Setup git commit hooks for TDD enforcement
 */
const setupCommitHooksTool = createTool<SetupCommitHooksInput, any>({
  name: 'setup_commit_hooks',
  description: 'Setup git hooks to enforce TDD practices and code quality',
  category: 'developer-workflow',
  inputSchema: {
    type: 'object',
    properties: {
      preCommit: {
        type: 'boolean',
        default: true,
        description: 'Run tests before every commit'
      },
      prePush: {
        type: 'boolean',
        default: true,
        description: 'Run full test suite before push'
      },
      commitMsg: {
        type: 'boolean',
        default: false,
        description: 'Validate commit message format'
      },
      preRebase: {
        type: 'boolean',
        default: false,
        description: 'Run tests before rebase'
      }
    },
    additionalProperties: false
  } as JSONSchema7,

  async execute(input: SetupCommitHooksInput, context: RequestContext) {
    try {
      const hooksDir = path.join('.git', 'hooks');
      const setupHooks: string[] = [];

      // Create hooks directory if it doesn't exist
      try {
        await fs.mkdir(hooksDir, { recursive: true });
      } catch (error) {
        return createErrorResult({
          code: 'FILESYSTEM_ERROR',
          message: 'Failed to create git hooks directory',
          category: 'system'
        });
      }

      // Pre-commit hook
      if (input.preCommit !== false) {
        const preCommitHook = `#!/bin/sh
# Atlas TDD Pre-commit Hook
# Ensures tests pass before allowing commits

echo "🧪 Running tests before commit..."
npm test -- --passWithNoTests

if [ $? -ne 0 ]; then
  echo "❌ Tests failed! Fix them before committing."
  echo "TDD requires all tests to pass before committing changes."
  exit 1
fi

echo "✅ All tests pass! Proceeding with commit..."
`;
        
        await fs.writeFile(path.join(hooksDir, 'pre-commit'), preCommitHook, { mode: 0o755 });
        setupHooks.push('pre-commit');
      }

      // Pre-push hook
      if (input.prePush !== false) {
        const prePushHook = `#!/bin/sh
# Atlas TDD Pre-push Hook
# Runs comprehensive checks before pushing

echo "🔍 Running pre-push checks..."

# Run full test suite
echo "Running full test suite..."
npm test

if [ $? -ne 0 ]; then
  echo "❌ Tests failed! Cannot push."
  exit 1
fi

# Run linter if available
if command -v npm run lint >/dev/null 2>&1; then
  echo "Running linter..."
  npm run lint
  if [ $? -ne 0 ]; then
    echo "⚠️  Linting issues found. Please fix them."
    exit 1
  fi
fi

echo "✅ All checks passed! Pushing to remote..."
`;
        
        await fs.writeFile(path.join(hooksDir, 'pre-push'), prePushHook, { mode: 0o755 });
        setupHooks.push('pre-push');
      }

      // Commit message hook
      if (input.commitMsg) {
        const commitMsgHook = `#!/bin/sh
# Atlas Commit Message Hook
# Validates commit message format

commit_regex='^(feat|fix|docs|style|refactor|test|chore)(\(.+\))?: .{1,50}'

if ! grep -qE "$commit_regex" "$1"; then
  echo "❌ Invalid commit message format!"
  echo "Format: type(scope): description"
  echo "Types: feat, fix, docs, style, refactor, test, chore"
  echo "Example: feat(auth): add user login functionality"
  exit 1
fi
`;
        
        await fs.writeFile(path.join(hooksDir, 'commit-msg'), commitMsgHook, { mode: 0o755 });
        setupHooks.push('commit-msg');
      }

      // Pre-rebase hook
      if (input.preRebase) {
        const preRebaseHook = `#!/bin/sh
# Atlas Pre-rebase Hook
# Ensures tests pass before rebasing

echo "🧪 Running tests before rebase..."
npm test -- --passWithNoTests

if [ $? -ne 0 ]; then
  echo "❌ Tests failed! Fix them before rebasing."
  exit 1
fi

echo "✅ Tests pass! Proceeding with rebase..."
`;
        
        await fs.writeFile(path.join(hooksDir, 'pre-rebase'), preRebaseHook, { mode: 0o755 });
        setupHooks.push('pre-rebase');
      }

      return createSuccessResult({
        hooks: setupHooks,
        message: `Git hooks configured successfully`,
        benefits: [
          'TDD practices enforced automatically',
          'Code quality maintained',
          'Prevents broken code from being committed',
          'Ensures test coverage before sharing code'
        ],
        usage: 'Hooks will run automatically during git operations'
      });

    } catch (error) {
      return createErrorResult({
        code: 'EXECUTION_ERROR',
        message: `Failed to setup commit hooks: ${error instanceof Error ? error.message : 'Unknown error'}`,
        category: 'execution'
      });
    }
  }
});

/**
 * Write a test case
 */
const writeTestTool = createTool<WriteTestInput, any>({
  name: 'write_test',
  description: 'Write a test case for TDD development',
  category: 'developer-workflow',
  inputSchema: {
    type: 'object',
    properties: {
      featureId: {
        type: 'string',
        description: 'Feature ID to write test for (optional, uses active feature if not provided)'
      },
      testName: {
        type: 'string',
        description: 'Name of the test case',
        minLength: 1,
        maxLength: 200
      },
      testType: {
        type: 'string',
        enum: ['unit', 'integration', 'e2e'],
        default: 'unit',
        description: 'Type of test'
      },
      description: {
        type: 'string',
        description: 'Description of what the test does',
        maxLength: 500
      },
      expectedBehavior: {
        type: 'string',
        description: 'Expected behavior when test passes',
        minLength: 1,
        maxLength: 1000
      }
    },
    required: ['testName', 'expectedBehavior'],
    additionalProperties: false
  } as JSONSchema7,

  async execute(input: WriteTestInput, context: RequestContext) {
    try {
      // Get or determine feature
      let featureId = input.featureId;
      if (!featureId) {
        const activeFeature = await context.db.get(
          `SELECT id FROM development_features 
           WHERE project_id = ? AND status != 'completed' 
           ORDER BY created_at DESC LIMIT 1`,
          [context.projectId || 'default']
        );
        featureId = activeFeature.data?.id;
      }

      if (!featureId) {
        return createErrorResult({
          code: 'NO_ACTIVE_FEATURE',
          message: 'No active feature found. Start a feature first.',
          category: 'validation'
        });
      }

      const testId = randomUUID();
      const now = Date.now();

      // Store test case
      const result = await context.db.run(
        `INSERT INTO development_test_cases 
         (id, feature_id, project_id, name, description, type, status, expected_behavior, created_at, updated_at) 
         VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
        [
          testId,
          featureId,
          context.projectId || 'default',
          input.testName,
          input.description || '',
          input.testType || 'unit',
          'pending',
          input.expectedBehavior,
          now,
          now
        ]
      );

      if (!result.success) {
        return createErrorResult({
          code: 'DATABASE_ERROR',
          message: 'Failed to save test case',
          category: 'system'
        });
      }

      // Update feature status to testing if still in planning
      await context.db.run(
        `UPDATE development_features 
         SET status = 'testing', updated_at = ? 
         WHERE id = ? AND status = 'planning'`,
        [now, featureId]
      );

      return createSuccessResult({
        test: {
          id: testId,
          name: input.testName,
          type: input.testType || 'unit',
          description: input.description,
          expectedBehavior: input.expectedBehavior,
          status: 'pending'
        },
        nextSteps: [
          'Run the test to see it fail (RED phase)',
          'Implement minimal code to make it pass (GREEN phase)',
          'Refactor while keeping tests green (REFACTOR phase)'
        ],
        tddGuidance: {
          phase: 'red',
          description: 'You should now run this test and verify it fails',
          command: 'Use "run_tdd_cycle" to guide through the TDD process'
        },
        message: 'Test case created successfully'
      });

    } catch (error) {
      return createErrorResult({
        code: 'EXECUTION_ERROR',
        message: `Failed to write test: ${error instanceof Error ? error.message : 'Unknown error'}`,
        category: 'execution'
      });
    }
  }
});

/**
 * Run tests with options
 */
const runTestsTool = createTool<RunTestsInput, any>({
  name: 'run_tests',
  description: 'Run tests with various options and track results',
  category: 'developer-workflow',
  inputSchema: {
    type: 'object',
    properties: {
      featureId: {
        type: 'string',
        description: 'Feature ID to run tests for (optional)'
      },
      testFile: {
        type: 'string',
        description: 'Specific test file to run',
        maxLength: 500
      },
      watch: {
        type: 'boolean',
        default: false,
        description: 'Run tests in watch mode'
      },
      coverage: {
        type: 'boolean',
        default: false,
        description: 'Generate coverage report'
      }
    },
    additionalProperties: false
  } as JSONSchema7,

  async execute(input: RunTestsInput, context: RequestContext) {
    try {
      let command = 'npm test';
      
      if (input.coverage) {
        command += ' -- --coverage';
      }
      
      if (input.testFile) {
        command += ` ${input.testFile}`;
      }

      if (input.watch) {
        command += ' -- --watch';
        return createSuccessResult({
          command,
          message: 'Started tests in watch mode',
          instructions: 'Tests will run automatically when files change. Press Ctrl+C to stop.'
        });
      }

      // Run tests
      let testResult: any;
      try {
        const { stdout, stderr } = await execAsync(command);
        testResult = {
          success: true,
          output: stdout,
          error: stderr || ''
        };
      } catch (error: any) {
        testResult = {
          success: false,
          output: error.stdout || '',
          error: error.stderr || error.message || 'Test execution failed'
        };
      }

      // Update test case statuses if feature specified
      if (input.featureId) {
        // Parse test results (basic implementation)
        const passingTests = (testResult.output.match(/✓/g) || []).length;
        const failingTests = (testResult.output.match(/✗|×/g) || []).length;

        await context.db.run(
          `UPDATE development_test_cases 
           SET status = ?, updated_at = ? 
           WHERE feature_id = ?`,
          [testResult.success ? 'passing' : 'failing', Date.now(), input.featureId]
        );

        // Update feature test coverage
        const coverage = input.coverage ? parseCoverage(testResult.output) : null;
        if (coverage) {
          await context.db.run(
            'UPDATE development_features SET test_coverage = ?, updated_at = ? WHERE id = ?',
            [coverage, Date.now(), input.featureId]
          );
        }
      }

      return createSuccessResult({
        testResult,
        summary: {
          success: testResult.success,
          hasOutput: testResult.output.length > 0,
          hasErrors: testResult.error.length > 0
        },
        nextSteps: testResult.success ? 
          ['Tests passing! Consider refactoring or adding more tests'] :
          ['Fix failing tests before proceeding'],
        message: testResult.success ? 'Tests completed successfully' : 'Some tests failed'
      });

    } catch (error) {
      return createErrorResult({
        code: 'EXECUTION_ERROR',
        message: `Failed to run tests: ${error instanceof Error ? error.message : 'Unknown error'}`,
        category: 'execution'
      });
    }
  }
});

// Helper function for parsing test coverage
function parseCoverage(output: string): number | null {
    // Basic coverage parsing - would need to be enhanced for specific test runners
    const coverageMatch = output.match(/All files\s+\|\s+(\d+\.?\d*)/);
    return coverageMatch ? parseFloat(coverageMatch[1]) : null;
}

/**
 * Complete a feature
 */
const completeFeatureTool = createTool<CompleteFeatureInput, any>({
  name: 'complete_feature',
  description: 'Complete a feature and optionally create a pull request',
  category: 'developer-workflow',
  inputSchema: {
    type: 'object',
    properties: {
      featureId: {
        type: 'string',
        description: 'Feature ID to complete',
        minLength: 1
      },
      createPR: {
        type: 'boolean',
        default: false,
        description: 'Create a pull request after completing feature'
      },
      prTitle: {
        type: 'string',
        description: 'Pull request title',
        maxLength: 200
      },
      prDescription: {
        type: 'string',
        description: 'Pull request description',
        maxLength: 2000
      }
    },
    required: ['featureId'],
    additionalProperties: false
  } as JSONSchema7,

  async execute(input: CompleteFeatureInput, context: RequestContext) {
    try {
      const now = Date.now();

      // Get feature details
      const feature = await context.db.get(
        'SELECT * FROM development_features WHERE id = ?',
        [input.featureId]
      );

      if (!feature.data) {
        return createErrorResult({
          code: 'FEATURE_NOT_FOUND',
          message: 'Feature not found',
          category: 'validation'
        });
      }

      // Check if tests are passing
      const testSummary = await context.db.get(
        `SELECT 
           COUNT(*) as total,
           SUM(CASE WHEN status = 'passing' THEN 1 ELSE 0 END) as passing,
           SUM(CASE WHEN status = 'failing' THEN 1 ELSE 0 END) as failing
         FROM development_test_cases 
         WHERE feature_id = ?`,
        [input.featureId]
      );

      const tests = testSummary.data;
      if (tests && tests.failing > 0) {
        return createErrorResult({
          code: 'TESTS_FAILING',
          message: `Cannot complete feature with ${tests.failing} failing tests`,
          category: 'validation'
        });
      }

      // Complete TDD sessions
      await context.db.run(
        'UPDATE development_tdd_sessions SET completed_at = ? WHERE feature_id = ? AND completed_at IS NULL',
        [now, input.featureId]
      );

      // Update feature status
      const result = await context.db.run(
        'UPDATE development_features SET status = ?, updated_at = ? WHERE id = ?',
        ['completed', now, input.featureId]
      );

      if (!result.success) {
        return createErrorResult({
          code: 'DATABASE_ERROR',
          message: 'Failed to update feature status',
          category: 'system'
        });
      }

      let prInfo: any = null;
      if (input.createPR) {
        try {
          const branchName = `feature/${feature.data.name}`;
          const title = input.prTitle || `feat: ${feature.data.name}`;
          const description = input.prDescription || 
            `## Summary\n\n${feature.data.description || 'Feature implementation'}\n\n## Tests\n\n- ✅ ${tests?.passing || 0} tests passing\n- 🧪 Test coverage: ${feature.data.test_coverage || 0}%`;

          // Create PR using gh CLI if available
          try {
            const { stdout } = await execAsync(`gh pr create --title "${title}" --body "${description}"`);
            prInfo = {
              created: true,
              url: stdout.trim(),
              title,
              description
            };
          } catch (error) {
            prInfo = {
              created: false,
              error: 'gh CLI not available or authentication failed',
              suggestion: `Manually create PR from ${branchName} to main`
            };
          }
        } catch (error) {
          prInfo = {
            created: false,
            error: error instanceof Error ? error.message : 'Unknown error'
          };
        }
      }

      return createSuccessResult({
        feature: {
          id: input.featureId,
          name: feature.data.name,
          status: 'completed',
          completedAt: new Date(now).toISOString()
        },
        testSummary: {
          total: tests?.total || 0,
          passing: tests?.passing || 0,
          coverage: feature.data.test_coverage || 0
        },
        pullRequest: prInfo,
        nextSteps: [
          'Review the completed feature',
          'Merge pull request if created',
          'Start next feature or epic',
          'Update project documentation'
        ],
        message: `Feature '${feature.data.name}' completed successfully`
      });

    } catch (error) {
      return createErrorResult({
        code: 'EXECUTION_ERROR',
        message: `Failed to complete feature: ${error instanceof Error ? error.message : 'Unknown error'}`,
        category: 'execution'
      });
    }
  }
});

/**
 * Setup developer workflow tools
 */
export async function setupDeveloperWorkflowTools(): Promise<ToolRegistration> {
  return {
    module: 'developer-workflow',
    tools: [
      startFeatureTool,
      checkWorkflowStatusTool,
      suggestNextActionTool,
      runTDDCycleTool,
      setupCommitHooksTool,
      writeTestTool,
      runTestsTool,
      completeFeatureTool
    ]
  };
}