import { JSONSchema7 } from 'json-schema';
import { randomUUID } from 'crypto';
import { createTool, createSuccessResult, createErrorResult } from '../../core/tool-framework.js';
import { ToolRegistration, RequestContext } from '../../core/types.js';
import { SecurityScanner } from './scanner.js';
import { SecurityManager } from '../../utils/security-manager.js';
import {
  SecurityConfig,
  SecurityScanResult,
  SecurityFinding,
  SecretFinding,
  VulnerabilityReport,
  SecuritySetupConfig,
  SecurityReport
} from './types.js';

/**
 * Security Management 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 Factor 11: Human Approval for critical security operations
 */

// Input type interfaces
interface GetSecurityStatusInput {
  // No parameters needed
}

interface GetSecurityEventsInput {
  timeRange?: '1h' | '24h' | '7d' | '30d';
  eventTypes?: Array<'access_denied' | 'approval_required' | 'policy_violation' | 'suspicious_activity' | 'error'>;
  severity?: 'low' | 'medium' | 'high' | 'critical';
}

interface ConfigureSecurityPolicyInput {
  requireApprovalFor?: string[];
  roles?: Record<string, string[]>;
  riskThresholds?: Record<string, number>;
  logLevel?: 'debug' | 'info' | 'warn' | 'error';
}

interface ProcessSecurityApprovalInput {
  approvalId: string;
  decision: 'approve' | 'deny';
  reason?: string;
}

interface SecurityScanInput {
  scanType?: 'quick' | 'comprehensive' | 'deep';
  includeFiles?: boolean;
  includeDependencies?: boolean;
  includeSecrets?: boolean;
  includePermissions?: boolean;
  outputFormat?: 'summary' | 'detailed' | 'json';
}

interface CheckSecretsInput {
  scanPath?: string;
  excludePaths?: string[];
  customPatterns?: string[];
}

interface VulnerabilityCheckInput {
  checkNpm?: boolean;
  checkYarn?: boolean;
  severity?: 'low' | 'moderate' | 'high' | 'critical';
  autoFix?: boolean;
}

interface SetupSecurityConfigInput {
  enablePreCommitScans?: boolean;
  enableSecretDetection?: boolean;
  enableVulnerabilityChecks?: boolean;
  createSecurityPolicy?: boolean;
  setupGitHooks?: boolean;
}

interface GenerateSecurityReportInput {
  includeOverview?: boolean;
  includeDetails?: boolean;
  includeRecommendations?: boolean;
  outputPath?: string;
}

interface CheckDataAccessInput {
  scanPath?: string;
  excludePaths?: string[];
  includeWarnings?: boolean;
  includeSuggestions?: boolean;
}

// Security scanner and manager instances
let securityScanner: SecurityScanner;
let securityManager: SecurityManager;

/**
 * Get security status
 */
const getSecurityStatusTool = createTool<GetSecurityStatusInput, any>({
  name: 'get_security_status',
  description: 'Get comprehensive security status overview including recent events, policy status, and system health',
  category: 'security',
  readOnly: true,
  inputSchema: {
    type: 'object',
    properties: {},
    required: [],
    additionalProperties: false
  } as JSONSchema7,

  async execute(input: GetSecurityStatusInput, context: RequestContext) {
    try {
      // Initialize managers if needed
      if (!securityManager) {
        securityManager = SecurityManager.getInstance();
      }

      const status = await securityManager.getSecurityStatus();
      
      return createSuccessResult({
        status,
        generatedAt: new Date().toISOString()
      });
    } catch (error) {
      return createErrorResult({
        code: 'EXECUTION_ERROR',
        message: `Failed to get security status: ${error instanceof Error ? error.message : 'Unknown error'}`,
        category: 'execution'
      });
    }
  }
});

/**
 * Get security events
 */
const getSecurityEventsTool = createTool<GetSecurityEventsInput, any>({
  name: 'get_security_events',
  description: 'Retrieve security events and incidents with filtering options',
  category: 'security',
  readOnly: true,
  inputSchema: {
    type: 'object',
    properties: {
      timeRange: {
        type: 'string',
        enum: ['1h', '24h', '7d', '30d'],
        default: '24h',
        description: 'Time range for event retrieval'
      },
      eventTypes: {
        type: 'array',
        items: {
          type: 'string',
          enum: ['access_denied', 'approval_required', 'policy_violation', 'suspicious_activity', 'error']
        },
        description: 'Filter events by type'
      },
      severity: {
        type: 'string',
        enum: ['low', 'medium', 'high', 'critical'],
        default: 'low',
        description: 'Minimum severity level to include'
      }
    },
    required: [],
    additionalProperties: false
  } as JSONSchema7,

  async execute(input: GetSecurityEventsInput, context: RequestContext) {
    try {
      if (!securityManager) {
        securityManager = SecurityManager.getInstance();
      }

      const events = await securityManager.getSecurityEvents({
        timeRange: input.timeRange || '24h',
        eventTypes: input.eventTypes,
        severity: input.severity || 'low'
      });
      
      return createSuccessResult({
        timeRange: input.timeRange || '24h',
        eventCount: events.length,
        events,
        generatedAt: new Date().toISOString()
      });
    } catch (error) {
      return createErrorResult({
        code: 'EXECUTION_ERROR',
        message: `Failed to get security events: ${error instanceof Error ? error.message : 'Unknown error'}`,
        category: 'execution'
      });
    }
  }
});

/**
 * Configure security policy
 */
const configureSecurityPolicyTool = createTool<ConfigureSecurityPolicyInput, any>({
  name: 'configure_security_policy',
  description: 'Configure security policies including approval requirements, role definitions, and risk thresholds',
  category: 'security',
  requiresApproval: true,
  inputSchema: {
    type: 'object',
    properties: {
      requireApprovalFor: {
        type: 'array',
        items: { type: 'string' },
        description: 'List of operations requiring human approval'
      },
      roles: {
        type: 'object',
        additionalProperties: {
          type: 'array',
          items: { type: 'string' }
        },
        description: 'Role definitions with permissions'
      },
      riskThresholds: {
        type: 'object',
        additionalProperties: { type: 'number' },
        description: 'Risk threshold values for different operations'
      },
      logLevel: {
        type: 'string',
        enum: ['debug', 'info', 'warn', 'error'],
        default: 'info',
        description: 'Security logging level'
      }
    },
    required: [],
    additionalProperties: false
  } as JSONSchema7,

  async execute(input: ConfigureSecurityPolicyInput, context: RequestContext) {
    try {
      if (!securityManager) {
        securityManager = SecurityManager.getInstance();
      }

      await securityManager.configureSecurityPolicy({
        requireApprovalFor: input.requireApprovalFor || [],
        roles: input.roles || {},
        riskThresholds: input.riskThresholds || {},
        logLevel: input.logLevel || 'info'
      });
      
      // Log security event
      await context.db.run(
        `INSERT INTO security_events 
         (id, event_type, tool_name, user_id, context, risk_level, details, created_at) 
         VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
        [
          randomUUID(),
          'policy_change',
          'configure_security_policy',
          context.userId || 'system',
          JSON.stringify({ projectId: context.projectId }),
          'high',
          JSON.stringify(input),
          Date.now()
        ]
      );

      return createSuccessResult({
        configuration: {
          requireApprovalFor: input.requireApprovalFor || [],
          roles: input.roles || {},
          riskThresholds: input.riskThresholds || {},
          logLevel: input.logLevel || 'info'
        },
        updatedAt: new Date().toISOString()
      });
    } catch (error) {
      return createErrorResult({
        code: 'EXECUTION_ERROR',
        message: `Failed to configure security policy: ${error instanceof Error ? error.message : 'Unknown error'}`,
        category: 'execution'
      });
    }
  }
});

/**
 * Process security approval
 */
const processSecurityApprovalTool = createTool<ProcessSecurityApprovalInput, any>({
  name: 'process_security_approval',
  description: 'Process pending security approval requests',
  category: 'security',
  inputSchema: {
    type: 'object',
    properties: {
      approvalId: {
        type: 'string',
        description: 'Unique identifier for the approval request',
        minLength: 1
      },
      decision: {
        type: 'string',
        enum: ['approve', 'deny'],
        description: 'Decision for the approval request'
      },
      reason: {
        type: 'string',
        description: 'Optional reason for the decision',
        maxLength: 1000
      }
    },
    required: ['approvalId', 'decision'],
    additionalProperties: false
  } as JSONSchema7,

  async execute(input: ProcessSecurityApprovalInput, context: RequestContext) {
    try {
      if (!securityManager) {
        securityManager = SecurityManager.getInstance();
      }

      const result = await securityManager.processApproval({
        approvalId: input.approvalId,
        decision: input.decision,
        reason: input.reason
      });
      
      // Log security event
      await context.db.run(
        `INSERT INTO security_events 
         (id, event_type, tool_name, user_id, context, risk_level, details, created_at) 
         VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
        [
          randomUUID(),
          'approval_processed',
          'process_security_approval',
          context.userId || 'system',
          JSON.stringify({ projectId: context.projectId, approvalId: input.approvalId }),
          'medium',
          JSON.stringify({ decision: input.decision, reason: input.reason }),
          Date.now()
        ]
      );

      return createSuccessResult({
        approvalId: input.approvalId,
        decision: input.decision,
        reason: input.reason,
        result,
        processedAt: new Date().toISOString()
      });
    } catch (error) {
      return createErrorResult({
        code: 'EXECUTION_ERROR',
        message: `Failed to process approval: ${error instanceof Error ? error.message : 'Unknown error'}`,
        category: 'execution'
      });
    }
  }
});

/**
 * Perform security scan
 */
const securityScanTool = createTool<SecurityScanInput, any>({
  name: 'security_scan',
  description: 'Perform comprehensive security scan of the project',
  category: 'security',
  readOnly: true,
  inputSchema: {
    type: 'object',
    properties: {
      scanType: {
        type: 'string',
        enum: ['quick', 'comprehensive', 'deep'],
        default: 'comprehensive',
        description: 'Type of security scan to perform'
      },
      includeFiles: {
        type: 'boolean',
        default: true,
        description: 'Scan source files for security issues'
      },
      includeDependencies: {
        type: 'boolean',
        default: true,
        description: 'Check dependencies for vulnerabilities'
      },
      includeSecrets: {
        type: 'boolean',
        default: true,
        description: 'Scan for exposed secrets and credentials'
      },
      includePermissions: {
        type: 'boolean',
        default: true,
        description: 'Check file permissions and access controls'
      },
      outputFormat: {
        type: 'string',
        enum: ['summary', 'detailed', 'json'],
        default: 'detailed',
        description: 'Format for scan results'
      }
    },
    required: [],
    additionalProperties: false
  } as JSONSchema7,

  async execute(input: SecurityScanInput, context: RequestContext) {
    try {
      if (!securityScanner) {
        const { ConfigManager } = await import('../../config/config-manager.js');
        securityScanner = new SecurityScanner(new ConfigManager());
      }

      const config: SecurityConfig = {
        scanType: input.scanType || 'comprehensive',
        includeFiles: input.includeFiles !== false,
        includeDependencies: input.includeDependencies !== false,
        includeSecrets: input.includeSecrets !== false,
        includePermissions: input.includePermissions !== false,
        outputFormat: input.outputFormat || 'detailed'
      };

      const scanResult = await securityScanner.performScan(config);

      // Log security event
      await context.db.run(
        `INSERT INTO security_events 
         (id, event_type, tool_name, user_id, context, risk_level, details, created_at) 
         VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
        [
          randomUUID(),
          'security_scan',
          'security_scan',
          context.userId || 'system',
          JSON.stringify({ projectId: context.projectId }),
          scanResult.summary.status === 'fail' ? 'high' : 'low',
          JSON.stringify({
            scanType: input.scanType,
            summary: scanResult.summary
          }),
          Date.now()
        ]
      );

      return createSuccessResult({
        scanResult,
        timestamp: new Date().toISOString()
      });
    } catch (error) {
      return createErrorResult({
        code: 'EXECUTION_ERROR',
        message: `Security scan failed: ${error instanceof Error ? error.message : 'Unknown error'}`,
        category: 'execution'
      });
    }
  }
});

/**
 * Check for secrets
 */
const checkSecretsTool = createTool<CheckSecretsInput, any>({
  name: 'check_secrets',
  description: 'Scan for exposed secrets, API keys, and credentials',
  category: 'security',
  readOnly: true,
  inputSchema: {
    type: 'object',
    properties: {
      scanPath: {
        type: 'string',
        default: '.',
        description: 'Path to scan for secrets'
      },
      excludePaths: {
        type: 'array',
        items: { type: 'string' },
        default: ['.git', 'node_modules', '.atlas'],
        description: 'Paths to exclude from scanning'
      },
      customPatterns: {
        type: 'array',
        items: { type: 'string' },
        description: 'Custom regex patterns to detect secrets'
      }
    },
    required: [],
    additionalProperties: false
  } as JSONSchema7,

  async execute(input: CheckSecretsInput, context: RequestContext) {
    try {
      if (!securityScanner) {
        const { ConfigManager } = await import('../../config/config-manager.js');
        securityScanner = new SecurityScanner(new ConfigManager());
      }

      const secretsFound = await securityScanner.scanForSecrets({
        scanPath: input.scanPath || '.',
        excludePaths: input.excludePaths || ['.git', 'node_modules', '.atlas'],
        customPatterns: input.customPatterns || []
      });

      // Log security event if secrets found
      if (secretsFound.length > 0) {
        await context.db.run(
          `INSERT INTO security_events 
           (id, event_type, tool_name, user_id, context, risk_level, details, created_at) 
           VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
          [
            randomUUID(),
            'secrets_detected',
            'check_secrets',
            context.userId || 'system',
            JSON.stringify({ projectId: context.projectId }),
            'critical',
            JSON.stringify({
              count: secretsFound.length,
              types: [...new Set(secretsFound.map((s: SecretFinding) => s.type))]
            }),
            Date.now()
          ]
        );
      }

      return createSuccessResult({
        secretsFound,
        scanCompleted: true
      });
    } catch (error) {
      return createErrorResult({
        code: 'EXECUTION_ERROR',
        message: `Secrets scan failed: ${error instanceof Error ? error.message : 'Unknown error'}`,
        category: 'execution'
      });
    }
  }
});

/**
 * Check vulnerabilities
 */
const vulnerabilityCheckTool = createTool<VulnerabilityCheckInput, any>({
  name: 'vulnerability_check',
  description: 'Check dependencies for known vulnerabilities',
  category: 'security',
  readOnly: true,
  inputSchema: {
    type: 'object',
    properties: {
      checkNpm: {
        type: 'boolean',
        default: true,
        description: 'Check npm dependencies'
      },
      checkYarn: {
        type: 'boolean',
        default: true,
        description: 'Check yarn dependencies'
      },
      severity: {
        type: 'string',
        enum: ['low', 'moderate', 'high', 'critical'],
        default: 'moderate',
        description: 'Minimum severity level to report'
      },
      autoFix: {
        type: 'boolean',
        default: false,
        description: 'Automatically fix vulnerabilities when possible'
      }
    },
    required: [],
    additionalProperties: false
  } as JSONSchema7,

  async execute(input: VulnerabilityCheckInput, context: RequestContext) {
    try {
      if (!securityScanner) {
        const { ConfigManager } = await import('../../config/config-manager.js');
        securityScanner = new SecurityScanner(new ConfigManager());
      }

      const vulnerabilities = await securityScanner.checkVulnerabilities({
        checkNpm: input.checkNpm !== false,
        checkYarn: input.checkYarn !== false,
        severity: input.severity || 'moderate',
        autoFix: input.autoFix || false
      });

      // Log security event if vulnerabilities found
      if (vulnerabilities.total > 0) {
        await context.db.run(
          `INSERT INTO security_events 
           (id, event_type, tool_name, user_id, context, risk_level, details, created_at) 
           VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
          [
            randomUUID(),
            'vulnerabilities_detected',
            'vulnerability_check',
            context.userId || 'system',
            JSON.stringify({ projectId: context.projectId }),
            vulnerabilities.critical > 0 ? 'critical' : 'high',
            JSON.stringify({
              total: vulnerabilities.total,
              critical: vulnerabilities.critical,
              high: vulnerabilities.high,
              moderate: vulnerabilities.moderate,
              low: vulnerabilities.low
            }),
            Date.now()
          ]
        );
      }

      return createSuccessResult({
        vulnerabilities,
        scanCompleted: true
      });
    } catch (error) {
      return createErrorResult({
        code: 'EXECUTION_ERROR',
        message: `Vulnerability check failed: ${error instanceof Error ? error.message : 'Unknown error'}`,
        category: 'execution'
      });
    }
  }
});

/**
 * Setup security configuration
 */
const setupSecurityConfigTool = createTool<SetupSecurityConfigInput, any>({
  name: 'setup_security_config',
  description: 'Configure comprehensive security tools and policies',
  category: 'security',
  requiresApproval: true,
  inputSchema: {
    type: 'object',
    properties: {
      enablePreCommitScans: {
        type: 'boolean',
        default: true,
        description: 'Enable security scans in pre-commit hooks'
      },
      enableSecretDetection: {
        type: 'boolean',
        default: true,
        description: 'Enable secret detection in CI/CD'
      },
      enableVulnerabilityChecks: {
        type: 'boolean',
        default: true,
        description: 'Enable dependency vulnerability checks'
      },
      createSecurityPolicy: {
        type: 'boolean',
        default: true,
        description: 'Create SECURITY.md policy file'
      },
      setupGitHooks: {
        type: 'boolean',
        default: true,
        description: 'Setup Git hooks for security checks'
      }
    },
    required: [],
    additionalProperties: false
  } as JSONSchema7,

  async execute(input: SetupSecurityConfigInput, context: RequestContext) {
    try {
      if (!securityScanner) {
        const { ConfigManager } = await import('../../config/config-manager.js');
        securityScanner = new SecurityScanner(new ConfigManager());
      }

      const setupResult = await securityScanner.setupSecurityConfiguration({
        enablePreCommitScans: input.enablePreCommitScans !== false,
        enableSecretDetection: input.enableSecretDetection !== false,
        enableVulnerabilityChecks: input.enableVulnerabilityChecks !== false,
        createSecurityPolicy: input.createSecurityPolicy !== false,
        setupGitHooks: input.setupGitHooks !== false
      });

      // Log security event
      await context.db.run(
        `INSERT INTO security_events 
         (id, event_type, tool_name, user_id, context, risk_level, details, created_at) 
         VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
        [
          randomUUID(),
          'security_setup',
          'setup_security_config',
          context.userId || 'system',
          JSON.stringify({ projectId: context.projectId }),
          'medium',
          JSON.stringify(input),
          Date.now()
        ]
      );

      return createSuccessResult({
        setupResult,
        configuration: {
          enablePreCommitScans: input.enablePreCommitScans !== false,
          enableSecretDetection: input.enableSecretDetection !== false,
          enableVulnerabilityChecks: input.enableVulnerabilityChecks !== false,
          createSecurityPolicy: input.createSecurityPolicy !== false,
          setupGitHooks: input.setupGitHooks !== false
        }
      });
    } catch (error) {
      return createErrorResult({
        code: 'EXECUTION_ERROR',
        message: `Security setup failed: ${error instanceof Error ? error.message : 'Unknown error'}`,
        category: 'execution'
      });
    }
  }
});

/**
 * Generate security report
 */
const generateSecurityReportTool = createTool<GenerateSecurityReportInput, any>({
  name: 'generate_security_report',
  description: 'Generate comprehensive security report for the project',
  category: 'security',
  readOnly: true,
  inputSchema: {
    type: 'object',
    properties: {
      includeOverview: {
        type: 'boolean',
        default: true,
        description: 'Include security overview section'
      },
      includeDetails: {
        type: 'boolean',
        default: true,
        description: 'Include detailed findings'
      },
      includeRecommendations: {
        type: 'boolean',
        default: true,
        description: 'Include security recommendations'
      },
      outputPath: {
        type: 'string',
        default: 'SECURITY.md',
        description: 'Path to save the security report'
      }
    },
    required: [],
    additionalProperties: false
  } as JSONSchema7,

  async execute(input: GenerateSecurityReportInput, context: RequestContext) {
    try {
      if (!securityScanner) {
        const { ConfigManager } = await import('../../config/config-manager.js');
        securityScanner = new SecurityScanner(new ConfigManager());
      }

      const report = await securityScanner.generateSecurityReport({
        includeOverview: input.includeOverview !== false,
        includeDetails: input.includeDetails !== false,
        includeRecommendations: input.includeRecommendations !== false
      });

      // Save report to file
      const fsModule = await import('fs');
      const pathModule = await import('path');
      await fsModule.promises.writeFile(
        pathModule.join(process.cwd(), input.outputPath || 'SECURITY.md'),
        report.markdown
      );

      return createSuccessResult({
        reportGenerated: true,
        outputPath: input.outputPath || 'SECURITY.md',
        summary: report.summary
      });
    } catch (error) {
      return createErrorResult({
        code: 'EXECUTION_ERROR',
        message: `Report generation failed: ${error instanceof Error ? error.message : 'Unknown error'}`,
        category: 'execution'
      });
    }
  }
});

/**
 * Check data access
 */
const checkDataAccessTool = createTool<CheckDataAccessInput, any>({
  name: 'check_data_access',
  description: 'Monitor and detect improper access to .atlas/ directory',
  category: 'security',
  readOnly: true,
  inputSchema: {
    type: 'object',
    properties: {
      scanPath: {
        type: 'string',
        default: '.',
        description: 'Path to scan for data access violations'
      },
      excludePaths: {
        type: 'array',
        items: { type: 'string' },
        default: ['.git', 'node_modules', 'dist', 'build'],
        description: 'Paths to exclude from scanning'
      },
      includeWarnings: {
        type: 'boolean',
        default: true,
        description: 'Include warnings for potential violations'
      },
      includeSuggestions: {
        type: 'boolean',
        default: true,
        description: 'Include suggestions for proper MCP tool usage'
      }
    },
    required: [],
    additionalProperties: false
  } as JSONSchema7,

  async execute(input: CheckDataAccessInput, context: RequestContext) {
    try {
      if (!securityScanner) {
        const { ConfigManager } = await import('../../config/config-manager.js');
        securityScanner = new SecurityScanner(new ConfigManager());
      }

      const accessViolations = await securityScanner.checkDataAccess({
        scanPath: input.scanPath || '.',
        excludePaths: input.excludePaths || ['.git', 'node_modules', 'dist', 'build'],
        includeWarnings: input.includeWarnings !== false,
        includeSuggestions: input.includeSuggestions !== false
      });

      // Log security event if violations found
      if (accessViolations.length > 0) {
        await context.db.run(
          `INSERT INTO security_events 
           (id, event_type, tool_name, user_id, context, risk_level, details, created_at) 
           VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
          [
            randomUUID(),
            'data_access_violation',
            'check_data_access',
            context.userId || 'system',
            JSON.stringify({ projectId: context.projectId }),
            'high',
            JSON.stringify({
              violationCount: accessViolations.length,
              types: [...new Set(accessViolations.map((v: any) => v.type))]
            }),
            Date.now()
          ]
        );
      }

      return createSuccessResult({
        violations: accessViolations,
        scanCompleted: true
      });
    } catch (error) {
      return createErrorResult({
        code: 'EXECUTION_ERROR',
        message: `Data access check failed: ${error instanceof Error ? error.message : 'Unknown error'}`,
        category: 'execution'
      });
    }
  }
});

/**
 * Setup security management tools
 */
export async function setupSecurityTools(): Promise<ToolRegistration> {
  return {
    module: 'security',
    tools: [
      getSecurityStatusTool,
      getSecurityEventsTool,
      configureSecurityPolicyTool,
      processSecurityApprovalTool,
      securityScanTool,
      checkSecretsTool,
      vulnerabilityCheckTool,
      setupSecurityConfigTool,
      generateSecurityReportTool,
      checkDataAccessTool
    ]
  };
}