import { glob } from 'glob';
import { readFileSync, existsSync } from 'fs';
import { join } from 'path';
import { execSync } from 'child_process';

/**
 * Template Data Sources - Inject dynamic MCP data into templates
 *
 * Provides project context, compliance status, and recent activity
 * for enriching template placeholders.
 */

/**
 * Get project structure statistics
 * @param {string} projectPath - Project root path
 * @returns {Promise<Object>} Project structure data
 */
export async function getProjectStructure(projectPath = process.cwd()) {
  try {
    // Find all files (excluding common ignore patterns)
    const files = await glob('**/*', {
      cwd: projectPath,
      ignore: [
        'node_modules/**',
        'bin/**',
        'obj/**',
        '.git/**',
        '.morph/**',
        'dist/**',
        'build/**',
        '*.log'
      ],
      nodir: true
    });

    // Calculate language stats
    const languageStats = {};
    files.forEach(file => {
      const ext = file.split('.').pop();
      languageStats[ext] = (languageStats[ext] || 0) + 1;
    });

    // Get test coverage if available
    let testCoverage = null;
    const coveragePath = join(projectPath, 'coverage/coverage-summary.json');
    if (existsSync(coveragePath)) {
      const coverageData = JSON.parse(readFileSync(coveragePath, 'utf8'));
      testCoverage = coverageData.total?.lines?.pct || null;
    }

    // Get last commit info
    let lastCommit = null;
    try {
      const gitLog = execSync('git log -1 --format="%H|%an|%ar|%s"', {
        cwd: projectPath,
        encoding: 'utf8',
        stdio: 'pipe'
      });

      const [hash, author, time, message] = gitLog.trim().split('|');
      lastCommit = { hash: hash.substring(0, 7), author, time, message };
    } catch {
      // Git not available or not a repo
    }

    return {
      totalFiles: files.length,
      languageStats,
      testCoverage: testCoverage ? Math.round(testCoverage) : null,
      lastCommit,
      filesByExtension: {
        cs: languageStats.cs || 0,
        js: languageStats.js || 0,
        ts: languageStats.ts || 0,
        tsx: languageStats.tsx || 0,
        razor: languageStats.razor || 0,
        css: languageStats.css || 0,
        md: languageStats.md || 0
      }
    };
  } catch (error) {
    return {
      error: error.message,
      totalFiles: 0,
      testCoverage: null
    };
  }
}

/**
 * Get dependency information
 * @param {string} projectPath - Project root path
 * @returns {Promise<Object>} Dependency data
 */
export async function getDependencyInfo(projectPath = process.cwd()) {
  const dependencies = {
    nuget: [],
    npm: [],
    outdated: []
  };

  try {
    // Check for NuGet packages (C# projects)
    const csprojFiles = await glob('**/*.csproj', {
      cwd: projectPath,
      ignore: ['**/bin/**', '**/obj/**']
    });

    if (csprojFiles.length > 0) {
      const csprojPath = join(projectPath, csprojFiles[0]);
      const csprojContent = readFileSync(csprojPath, 'utf8');

      // Extract PackageReference elements
      const packageRegex = /<PackageReference\s+Include="([^"]+)"\s+Version="([^"]+)"/g;
      let match;

      while ((match = packageRegex.exec(csprojContent)) !== null) {
        dependencies.nuget.push({
          name: match[1],
          version: match[2]
        });
      }
    }

    // Check for npm packages
    const packageJsonPath = join(projectPath, 'package.json');
    if (existsSync(packageJsonPath)) {
      const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'));

      const allDeps = {
        ...packageJson.dependencies,
        ...packageJson.devDependencies
      };

      Object.entries(allDeps).forEach(([name, version]) => {
        dependencies.npm.push({ name, version });
      });
    }

  } catch (error) {
    dependencies.error = error.message;
  }

  return dependencies;
}

/**
 * Get compliance status from validators
 * @param {string} projectPath - Project root path
 * @returns {Promise<Object>} Compliance data
 */
export async function getComplianceStatus(projectPath = process.cwd()) {
  const compliance = {
    architectureViolations: 0,
    packageConflicts: 0,
    designSystemCompliance: 100,
    securityIssues: 0,
    overall: 100
  };

  try {
    // Run validators if available
    const validators = ['architecture', 'packages', 'design-system', 'security'];

    for (const validator of validators) {
      try {
        const result = execSync(
          `node bin/validate.js ${validator} --json`,
          {
            cwd: projectPath,
            encoding: 'utf8',
            stdio: 'pipe'
          }
        );

        const parsed = JSON.parse(result);

        if (validator === 'architecture') {
          compliance.architectureViolations = parsed.errors || 0;
        } else if (validator === 'packages') {
          compliance.packageConflicts = parsed.errors || 0;
        } else if (validator === 'design-system') {
          const total = parsed.total || 100;
          const errors = parsed.errors || 0;
          compliance.designSystemCompliance = Math.round(((total - errors) / total) * 100);
        } else if (validator === 'security') {
          compliance.securityIssues = parsed.errors || 0;
        }
      } catch {
        // Validator not available or failed - skip
      }
    }

    // Calculate overall compliance score
    const violations = compliance.architectureViolations +
                      compliance.packageConflicts +
                      compliance.securityIssues;

    compliance.overall = Math.max(0, 100 - (violations * 5));

  } catch (error) {
    compliance.error = error.message;
  }

  return compliance;
}

/**
 * Get recent activity and history
 * @param {string} projectPath - Project root path
 * @returns {Promise<Object>} Activity data
 */
export async function getRecentActivity(projectPath = process.cwd()) {
  const activity = {
    lastFeature: null,
    recentCommits: [],
    activeBranches: [],
    lastDeployment: null
  };

  try {
    // Check state.json for last feature
    const statePath = join(projectPath, '.morph/state.json');
    if (existsSync(statePath)) {
      const state = JSON.parse(readFileSync(statePath, 'utf8'));

      // Find most recently updated feature
      let lastFeature = null;
      let lastTimestamp = null;

      Object.entries(state.features || {}).forEach(([name, feature]) => {
        const updatedAt = feature.updatedAt || feature.createdAt;
        if (updatedAt && (!lastTimestamp || updatedAt > lastTimestamp)) {
          lastTimestamp = updatedAt;
          lastFeature = name;
        }
      });

      activity.lastFeature = lastFeature;
    }

    // Get recent commits
    try {
      const gitLog = execSync('git log -5 --format="%h|%an|%ar|%s"', {
        cwd: projectPath,
        encoding: 'utf8',
        stdio: 'pipe'
      });

      activity.recentCommits = gitLog.trim().split('\n').map(line => {
        const [hash, author, time, message] = line.split('|');
        return { hash, author, time, message };
      });
    } catch {
      // Git not available
    }

    // Get active branches
    try {
      const branches = execSync('git branch -a', {
        cwd: projectPath,
        encoding: 'utf8',
        stdio: 'pipe'
      });

      activity.activeBranches = branches
        .split('\n')
        .map(b => b.trim().replace(/^\*\s+/, ''))
        .filter(b => b && !b.includes('->'));
    } catch {
      // Git not available
    }

  } catch (error) {
    activity.error = error.message;
  }

  return activity;
}

/**
 * Get all template data sources combined
 * @param {string} projectPath - Project root path
 * @returns {Promise<Object>} All data sources
 */
export async function getAllTemplatePlaceholders(projectPath = process.cwd()) {
  const [structure, dependencies, compliance, activity] = await Promise.all([
    getProjectStructure(projectPath),
    getDependencyInfo(projectPath),
    getComplianceStatus(projectPath),
    getRecentActivity(projectPath)
  ]);

  return {
    MCP_PROJECT_FILES: structure.totalFiles,
    MCP_TEST_COVERAGE: structure.testCoverage || 'N/A',
    MCP_COMPLIANCE_SCORE: compliance.overall,
    MCP_LAST_FEATURE: activity.lastFeature || 'None',
    MCP_LAST_COMMIT: structure.lastCommit?.message || 'Unknown',
    MCP_LAST_COMMIT_AUTHOR: structure.lastCommit?.author || 'Unknown',
    MCP_LAST_COMMIT_TIME: structure.lastCommit?.time || 'Unknown',

    MCP_CS_FILES: structure.filesByExtension?.cs || 0,
    MCP_RAZOR_FILES: structure.filesByExtension?.razor || 0,
    MCP_TS_FILES: structure.filesByExtension?.ts || 0,
    MCP_JS_FILES: structure.filesByExtension?.js || 0,

    MCP_NUGET_PACKAGES: dependencies.nuget.length,
    MCP_NPM_PACKAGES: dependencies.npm.length,

    MCP_ARCHITECTURE_VIOLATIONS: compliance.architectureViolations,
    MCP_PACKAGE_CONFLICTS: compliance.packageConflicts,
    MCP_SECURITY_ISSUES: compliance.securityIssues,

    MCP_RECENT_BRANCHES: activity.activeBranches.slice(0, 3).join(', '),

    // Full objects for advanced usage
    _raw: {
      structure,
      dependencies,
      compliance,
      activity
    }
  };
}
