/**
 * Security Configuration Management System
 * Provides centralized security policy and configuration management
 */

import * as fs from "fs/promises";
import * as path from "path";
import { z } from "zod";
import { SecurityUtils } from "./SecurityConfig.js";
import { SecurityValidationError } from "./InputValidator.js";
import { LoggerFactory } from "@/utils/logger.js";

const logger = LoggerFactory.security();

interface SecurityPolicy {
  id: string;
  name: string;
  version: string;
  description: string;
  enabled: boolean;
  scope: "global" | "environment" | "application" | "endpoint";
  rules: SecurityPolicyRule[];
  compliance: {
    frameworks: string[]; // OWASP, CWE, GDPR, etc.
    requirements: string[];
  };
  metadata: {
    created: Date;
    updated: Date;
    author: string;
    approved: boolean;
  };
}

interface SecurityPolicyRule {
  id: string;
  name: string;
  type: "authentication" | "authorization" | "input-validation" | "crypto" | "session" | "logging" | "monitoring";
  action: "enforce" | "warn" | "log" | "block";
  conditions: {
    environments?: string[];
    methods?: string[];
    paths?: string[];
    userRoles?: string[];
  };
  parameters: Record<string, unknown>;
  exceptions: string[];
}

interface SecurityConfiguration {
  configId: string;
  version: string;
  environment: string;
  policies: SecurityPolicy[];
  settings: {
    authentication: AuthenticationSettings;
    authorization: AuthorizationSettings;
    inputValidation: InputValidationSettings;
    cryptography: CryptographySettings;
    session: SessionSettings;
    logging: LoggingSettings;
    monitoring: MonitoringSettings;
  };
  overrides: Record<string, unknown>;
  metadata: {
    lastUpdated: Date;
    checksum: string;
  };
}

interface AuthenticationSettings {
  methods: ("password" | "jwt" | "oauth" | "api-key")[];
  passwordPolicy: {
    minLength: number;
    requireUppercase: boolean;
    requireLowercase: boolean;
    requireNumbers: boolean;
    requireSpecialChars: boolean;
    maxAge: number;
    preventReuse: number;
  };
  jwtSettings: {
    algorithm: string;
    expiresIn: string;
    issuer: string;
    audience: string;
  };
  rateLimiting: {
    maxAttempts: number;
    windowMs: number;
    blockDuration: number;
  };
  mfa: {
    enabled: boolean;
    methods: string[];
    required: boolean;
  };
}

interface AuthorizationSettings {
  rbac: {
    enabled: boolean;
    defaultRole: string;
    roleHierarchy: Record<string, string[]>;
  };
  permissions: {
    strict: boolean;
    defaultDeny: boolean;
    inheritance: boolean;
  };
  sessionTimeout: number;
  resourceAccess: {
    checkOrigin: boolean;
    allowedOrigins: string[];
    csrfProtection: boolean;
  };
}

interface InputValidationSettings {
  sanitization: {
    enabled: boolean;
    htmlStripping: boolean;
    sqlEscaping: boolean;
    jsEscaping: boolean;
  };
  validation: {
    strict: boolean;
    maxStringLength: number;
    maxFileSize: number;
    allowedFileTypes: string[];
    blockedPatterns: string[];
  };
  xssProtection: {
    enabled: boolean;
    mode: "filter" | "block";
    reportUri: string;
  };
}

interface CryptographySettings {
  encryption: {
    algorithm: "AES-256-GCM" | "AES-256-CBC" | "ChaCha20-Poly1305";
    keyDerivation: "PBKDF2" | "scrypt" | "Argon2";
    keyRotation: {
      enabled: boolean;
      intervalDays: number;
    };
  };
  hashing: {
    algorithm: "bcrypt" | "scrypt" | "Argon2";
    saltRounds: number;
  };
  tls: {
    minVersion: string;
    cipherSuites: string[];
    hsts: {
      enabled: boolean;
      maxAge: number;
      includeSubDomains: boolean;
    };
  };
}

interface SessionSettings {
  storage: "memory" | "redis" | "database";
  security: {
    httpOnly: boolean;
    secure: boolean;
    sameSite: "strict" | "lax" | "none";
  };
  timeout: {
    idle: number;
    absolute: number;
  };
  regeneration: {
    onLogin: boolean;
    onPrivilegeChange: boolean;
    interval: number;
  };
}

interface LoggingSettings {
  level: "error" | "warn" | "info" | "debug";
  security: {
    logFailedAuth: boolean;
    logPrivilegeEscalation: boolean;
    logDataAccess: boolean;
    logConfigChanges: boolean;
  };
  retention: {
    days: number;
    compression: boolean;
    encryption: boolean;
  };
  alerting: {
    enabled: boolean;
    thresholds: Record<string, number>;
    channels: string[];
  };
}

interface MonitoringSettings {
  realTime: {
    enabled: boolean;
    metrics: string[];
    alertThresholds: Record<string, number>;
  };
  anomalyDetection: {
    enabled: boolean;
    sensitivity: "low" | "medium" | "high";
    models: string[];
  };
  compliance: {
    enabled: boolean;
    frameworks: string[];
    reportingSchedule: string;
  };
}

/**
 * Security Configuration Schema Validation
 */
const SecurityPolicySchema = z.object({
  id: z.string().min(1),
  name: z.string().min(1),
  version: z.string().regex(/^\d+\.\d+\.\d+$/),
  description: z.string().min(1),
  enabled: z.boolean(),
  scope: z.enum(["global", "environment", "application", "endpoint"]),
  rules: z.array(
    z.object({
      id: z.string().min(1),
      name: z.string().min(1),
      type: z.enum([
        "authentication",
        "authorization",
        "input-validation",
        "crypto",
        "session",
        "logging",
        "monitoring",
      ]),
      action: z.enum(["enforce", "warn", "log", "block"]),
      conditions: z.object({
        environments: z.array(z.string()).optional(),
        methods: z.array(z.string()).optional(),
        paths: z.array(z.string()).optional(),
        userRoles: z.array(z.string()).optional(),
      }),
      parameters: z.record(z.string(), z.unknown()),
      exceptions: z.array(z.string()),
    }),
  ),
  compliance: z.object({
    frameworks: z.array(z.string()),
    requirements: z.array(z.string()),
  }),
  metadata: z.object({
    created: z.date(),
    updated: z.date(),
    author: z.string(),
    approved: z.boolean(),
  }),
});

/**
 * Security Configuration Manager
 */
export class SecurityConfigManager {
  private configurations: Map<string, SecurityConfiguration> = new Map();
  private policies: Map<string, SecurityPolicy> = new Map();
  private configPath: string;

  constructor(configPath: string = "security-config") {
    this.configPath = configPath;
  }

  /**
   * Initialize security configuration manager
   */
  async initialize(): Promise<void> {
    logger.info("Initializing security configuration manager");

    await this.ensureConfigDirectory();
    await this.loadConfigurations();
    await this.loadPolicies();

    logger.info("Loaded configurations and policies", {
      configurationCount: this.configurations.size,
      policyCount: this.policies.size,
    });
  }

  /**
   * Create a new security policy
   */
  async createPolicy(policyData: Omit<SecurityPolicy, "id" | "metadata">): Promise<SecurityPolicy> {
    const policy: SecurityPolicy = {
      ...policyData,
      id: SecurityUtils.generateSecureToken(16),
      metadata: {
        created: new Date(),
        updated: new Date(),
        author: "system",
        approved: false,
      },
    };

    // Validate policy
    try {
      SecurityPolicySchema.parse(policy);
    } catch (_error) {
      throw new SecurityValidationError("Invalid security policy", [{ message: String(_error) }]);
    }

    this.policies.set(policy.id, policy);
    await this.savePolicyToFile(policy);

    logger.info(`Created policy: ${policy.name}`, { policyId: policy.id });
    return policy;
  }

  /**
   * Update an existing security policy
   */
  async updatePolicy(policyId: string, updates: Partial<SecurityPolicy>): Promise<SecurityPolicy> {
    const existingPolicy = this.policies.get(policyId);
    if (!existingPolicy) {
      throw new SecurityValidationError("Policy not found", [{ message: `Policy ${policyId} not found` }]);
    }

    const updatedPolicy: SecurityPolicy = {
      ...existingPolicy,
      ...updates,
      id: policyId, // Ensure ID doesn't change
      metadata: {
        ...existingPolicy.metadata,
        updated: new Date(),
      },
    };

    // Validate updated policy
    try {
      SecurityPolicySchema.parse(updatedPolicy);
    } catch (_error) {
      throw new SecurityValidationError("Invalid policy update", [{ message: String(_error) }]);
    }

    this.policies.set(policyId, updatedPolicy);
    await this.savePolicyToFile(updatedPolicy);

    logger.info(`Updated policy: ${updatedPolicy.name}`, { policyId });
    return updatedPolicy;
  }

  /**
   * Create a new security configuration
   */
  async createConfiguration(
    environment: string,
    configData: Partial<SecurityConfiguration>,
  ): Promise<SecurityConfiguration> {
    const config: SecurityConfiguration = {
      configId: SecurityUtils.generateSecureToken(16),
      version: "1.0.0",
      environment,
      policies: [],
      settings: configData.settings || this.getDefaultSettings(),
      overrides: configData.overrides || {},
      metadata: {
        lastUpdated: new Date(),
        checksum: "",
      },
    };

    // Calculate checksum
    config.metadata.checksum = await this.calculateChecksum(config);

    this.configurations.set(environment, config);
    await this.saveConfigurationToFile(config);

    logger.info(`Created configuration for environment: ${environment}`, { environment });
    return config;
  }

  /**
   * Get configuration for environment
   */
  getConfiguration(environment: string): SecurityConfiguration | null {
    return this.configurations.get(environment) || null;
  }

  /**
   * Get all configurations
   */
  getAllConfigurations(): SecurityConfiguration[] {
    return Array.from(this.configurations.values());
  }

  /**
   * Apply policies to configuration
   */
  async applyPoliciesToConfiguration(environment: string, policyIds: string[]): Promise<SecurityConfiguration> {
    const config = this.configurations.get(environment);
    if (!config) {
      throw new SecurityValidationError("Configuration not found", [
        { message: `Environment ${environment} not found` },
      ]);
    }

    const policies: SecurityPolicy[] = [];
    for (const policyId of policyIds) {
      const policy = this.policies.get(policyId);
      if (!policy) {
        throw new SecurityValidationError("Policy not found", [{ message: `Policy ${policyId} not found` }]);
      }
      if (!policy.enabled) {
        logger.warn(`Skipping disabled policy: ${policy.name}`, { policyName: policy.name });
        continue;
      }
      policies.push(policy);
    }

    config.policies = policies;
    config.metadata.lastUpdated = new Date();
    config.metadata.checksum = await this.calculateChecksum(config);

    this.configurations.set(environment, config);
    await this.saveConfigurationToFile(config);

    logger.info(`Applied policies to ${environment}`, { policyCount: policies.length, environment });
    return config;
  }

  /**
   * Validate configuration compliance
   */
  async validateCompliance(environment: string): Promise<{
    compliant: boolean;
    violations: string[];
    recommendations: string[];
  }> {
    const config = this.configurations.get(environment);
    if (!config) {
      throw new SecurityValidationError("Configuration not found", [
        { message: `Environment ${environment} not found` },
      ]);
    }

    const violations: string[] = [];
    const recommendations: string[] = [];

    // Check password policy compliance
    if (config.settings.authentication.passwordPolicy.minLength < 8) {
      violations.push("Password minimum length below recommended 8 characters");
    }

    // Check encryption compliance
    if (!["AES-256-GCM", "ChaCha20-Poly1305"].includes(config.settings.cryptography.encryption.algorithm)) {
      violations.push("Weak encryption algorithm detected");
    }

    // Check session security
    if (!config.settings.session.security.httpOnly || !config.settings.session.security.secure) {
      violations.push("Insecure session configuration");
    }

    // Check HTTPS enforcement
    if (!config.settings.cryptography.tls.hsts.enabled) {
      recommendations.push("Enable HSTS for enhanced security");
    }

    // Check MFA configuration
    if (!config.settings.authentication.mfa.enabled) {
      recommendations.push("Consider enabling multi-factor authentication");
    }

    // Check compliance frameworks
    const requiredFrameworks = ["OWASP", "CWE"];
    const configuredFrameworks = config.policies.flatMap((p) => p.compliance.frameworks);

    for (const framework of requiredFrameworks) {
      if (!configuredFrameworks.includes(framework)) {
        recommendations.push(`Add ${framework} compliance policies`);
      }
    }

    return {
      compliant: violations.length === 0,
      violations,
      recommendations,
    };
  }

  /**
   * Generate default security settings
   */
  private getDefaultSettings(): SecurityConfiguration["settings"] {
    return {
      authentication: {
        methods: ["password", "jwt"],
        passwordPolicy: {
          minLength: 8,
          requireUppercase: true,
          requireLowercase: true,
          requireNumbers: true,
          requireSpecialChars: true,
          maxAge: 90,
          preventReuse: 5,
        },
        jwtSettings: {
          algorithm: "HS256",
          expiresIn: "1h",
          issuer: "mcp-wordpress",
          audience: "mcp-wordpress-users",
        },
        rateLimiting: {
          maxAttempts: 5,
          windowMs: 900000, // 15 minutes
          blockDuration: 3600000, // 1 hour
        },
        mfa: {
          enabled: false,
          methods: ["totp", "sms"],
          required: false,
        },
      },
      authorization: {
        rbac: {
          enabled: true,
          defaultRole: "user",
          roleHierarchy: {
            admin: ["editor", "user"],
            editor: ["user"],
            user: [],
          },
        },
        permissions: {
          strict: true,
          defaultDeny: true,
          inheritance: true,
        },
        sessionTimeout: 3600, // 1 hour
        resourceAccess: {
          checkOrigin: true,
          allowedOrigins: [],
          csrfProtection: true,
        },
      },
      inputValidation: {
        sanitization: {
          enabled: true,
          htmlStripping: true,
          sqlEscaping: true,
          jsEscaping: true,
        },
        validation: {
          strict: true,
          maxStringLength: 10000,
          maxFileSize: 10485760, // 10MB
          allowedFileTypes: ["image/jpeg", "image/png", "application/pdf"],
          blockedPatterns: ["<script>", "javascript:", "vbscript:"],
        },
        xssProtection: {
          enabled: true,
          mode: "block",
          reportUri: "/security/xss-report",
        },
      },
      cryptography: {
        encryption: {
          algorithm: "AES-256-GCM",
          keyDerivation: "PBKDF2",
          keyRotation: {
            enabled: true,
            intervalDays: 90,
          },
        },
        hashing: {
          algorithm: "bcrypt",
          saltRounds: 12,
        },
        tls: {
          minVersion: "1.2",
          cipherSuites: ["ECDHE-RSA-AES256-GCM-SHA384", "ECDHE-RSA-AES128-GCM-SHA256", "ECDHE-RSA-AES256-SHA384"],
          hsts: {
            enabled: true,
            maxAge: 31536000, // 1 year
            includeSubDomains: true,
          },
        },
      },
      session: {
        storage: "memory",
        security: {
          httpOnly: true,
          secure: true,
          sameSite: "strict",
        },
        timeout: {
          idle: 1800, // 30 minutes
          absolute: 28800, // 8 hours
        },
        regeneration: {
          onLogin: true,
          onPrivilegeChange: true,
          interval: 3600, // 1 hour
        },
      },
      logging: {
        level: "info",
        security: {
          logFailedAuth: true,
          logPrivilegeEscalation: true,
          logDataAccess: true,
          logConfigChanges: true,
        },
        retention: {
          days: 90,
          compression: true,
          encryption: true,
        },
        alerting: {
          enabled: true,
          thresholds: {
            failedLogins: 10,
            privilegeEscalation: 1,
            dataAccess: 100,
          },
          channels: ["email", "webhook"],
        },
      },
      monitoring: {
        realTime: {
          enabled: true,
          metrics: ["requests", "errors", "latency", "security_events"],
          alertThresholds: {
            errorRate: 0.05,
            latencyP99: 1000,
            securityEvents: 10,
          },
        },
        anomalyDetection: {
          enabled: true,
          sensitivity: "medium",
          models: ["statistical", "ml"],
        },
        compliance: {
          enabled: true,
          frameworks: ["OWASP", "CWE"],
          reportingSchedule: "daily",
        },
      },
    };
  }

  /**
   * Load configurations from files
   */
  private async loadConfigurations(): Promise<void> {
    try {
      const configDir = path.join(this.configPath, "configurations");
      await fs.access(configDir);

      const files = await fs.readdir(configDir);

      for (const file of files) {
        if (file.endsWith(".json")) {
          const filePath = path.join(configDir, file);
          const content = await fs.readFile(filePath, "utf-8");
          const config: SecurityConfiguration = JSON.parse(content);

          // Convert date strings back to Date objects
          config.metadata.lastUpdated = new Date(config.metadata.lastUpdated);

          this.configurations.set(config.environment, config);
        }
      }
    } catch (_error) {
      logger.info("No existing configurations found, will create new ones");
    }
  }

  /**
   * Load policies from files
   */
  private async loadPolicies(): Promise<void> {
    try {
      const policiesDir = path.join(this.configPath, "policies");
      await fs.access(policiesDir);

      const files = await fs.readdir(policiesDir);

      for (const file of files) {
        if (file.endsWith(".json")) {
          const filePath = path.join(policiesDir, file);
          const content = await fs.readFile(filePath, "utf-8");
          const policy: SecurityPolicy = JSON.parse(content);

          // Convert date strings back to Date objects
          policy.metadata.created = new Date(policy.metadata.created);
          policy.metadata.updated = new Date(policy.metadata.updated);

          this.policies.set(policy.id, policy);
        }
      }
    } catch (_error) {
      logger.info("No existing policies found");
    }
  }

  /**
   * Save configuration to file
   */
  private async saveConfigurationToFile(config: SecurityConfiguration): Promise<void> {
    const configDir = path.join(this.configPath, "configurations");
    await fs.mkdir(configDir, { recursive: true });

    const filePath = path.join(configDir, `${config.environment}.json`);
    await fs.writeFile(filePath, JSON.stringify(config, null, 2), "utf-8");
  }

  /**
   * Save policy to file
   */
  private async savePolicyToFile(policy: SecurityPolicy): Promise<void> {
    const policiesDir = path.join(this.configPath, "policies");
    await fs.mkdir(policiesDir, { recursive: true });

    const filePath = path.join(policiesDir, `${policy.id}.json`);
    await fs.writeFile(filePath, JSON.stringify(policy, null, 2), "utf-8");
  }

  /**
   * Ensure config directory exists
   */
  private async ensureConfigDirectory(): Promise<void> {
    await fs.mkdir(this.configPath, { recursive: true });
    await fs.mkdir(path.join(this.configPath, "configurations"), { recursive: true });
    await fs.mkdir(path.join(this.configPath, "policies"), { recursive: true });
  }

  /**
   * Calculate configuration checksum
   */
  private async calculateChecksum(config: SecurityConfiguration): Promise<string> {
    const configForHash = {
      ...config,
      metadata: {
        ...config.metadata,
        checksum: "", // Exclude checksum from hash calculation
      },
    };

    const _configString = JSON.stringify(configForHash, Object.keys(configForHash).sort());
    return SecurityUtils.generateSecureToken(32);
  }

  /**
   * Get all policies
   */
  getAllPolicies(): SecurityPolicy[] {
    return Array.from(this.policies.values());
  }

  /**
   * Get policy by ID
   */
  getPolicy(policyId: string): SecurityPolicy | null {
    return this.policies.get(policyId) || null;
  }

  /**
   * Delete policy
   */
  async deletePolicy(policyId: string): Promise<boolean> {
    const policy = this.policies.get(policyId);
    if (!policy) {
      return false;
    }

    this.policies.delete(policyId);

    try {
      const filePath = path.join(this.configPath, "policies", `${policyId}.json`);
      await fs.unlink(filePath);
      logger.info(`Deleted policy: ${policy.name}`, { policyId });
      return true;
    } catch (_error) {
      logger.warn("Failed to delete policy file", { _error });
      return false;
    }
  }

  /**
   * Export configuration
   */
  async exportConfiguration(environment: string): Promise<string> {
    const config = this.configurations.get(environment);
    if (!config) {
      throw new SecurityValidationError("Configuration not found", [
        { message: `Environment ${environment} not found` },
      ]);
    }

    return JSON.stringify(config, null, 2);
  }

  /**
   * Import configuration
   */
  async importConfiguration(configData: string): Promise<SecurityConfiguration> {
    try {
      const config: SecurityConfiguration = JSON.parse(configData);

      // Validate configuration structure
      if (!config.configId || !config.environment) {
        throw new Error("Invalid configuration format");
      }

      // Convert date strings to Date objects
      config.metadata.lastUpdated = new Date(config.metadata.lastUpdated);

      this.configurations.set(config.environment, config);
      await this.saveConfigurationToFile(config);

      logger.info(`Imported configuration for environment: ${config.environment}`, { environment: config.environment });
      return config;
    } catch (_error) {
      throw new SecurityValidationError("Failed to import configuration", [{ message: String(_error) }]);
    }
  }
}
