// Admin Vault Provisioning Service
// Provisions private admin vault for Sankofa Admin Portal

import { logger } from '@/infrastructure/monitoring/logger';
import { DbisError, ErrorCode } from '@/shared/types';

export interface AdminVaultRequest {
  organizationName: string;
  vaultName: string;
  adminLevel: 'super_admin' | 'admin' | 'operator';
  features?: {
    auditLogging?: boolean;
    backupEnabled?: boolean;
    encryptionLevel?: 'standard' | 'enhanced' | 'quantum';
  };
}

export interface AdminVaultResult {
  vaultId: string;
  vaultPath: string; // e.g., "secret/data/admin/sankofa-admin/"
  apiEndpoint: string;
  roleId: string;
  secretId: string;
  status: 'provisioned' | 'pending' | 'failed';
  metadata: {
    createdAt: Date;
    organizationId: string;
    adminLevel: string;
  };
}

export class AdminVaultProvisioningService {
  private readonly VAULT_CLUSTER_ENDPOINTS = [
    'http://192.168.11.200:8200',
    'http://192.168.11.215:8200',
    'http://192.168.11.202:8200',
  ];

  private readonly VAULT_ROOT_TOKEN = process.env.VAULT_ROOT_TOKEN || process.env.VAULT_TOKEN || '';
  private readonly ADMIN_VAULT_BASE_PATH = 'secret/data/admin';

  /**
   * Provision admin vault for Sankofa Admin Portal
   */
  async provisionAdminVault(request: AdminVaultRequest): Promise<AdminVaultResult> {
    logger.info('Provisioning admin vault', {
      organizationName: request.organizationName,
      vaultName: request.vaultName,
      adminLevel: request.adminLevel,
    });

    try {
      // Step 1: Generate unique vault path
      const orgId = this.generateOrgId(request.organizationName);
      const vaultPath = `${this.ADMIN_VAULT_BASE_PATH}/${orgId}/${request.vaultName}`;
      const vaultId = `admin-vault-${orgId}-${Date.now()}`;

      // Step 2: Create AppRole for admin vault with elevated permissions
      const { roleId, secretId } = await this.createAdminAppRole({
        vaultId,
        vaultPath,
        adminLevel: request.adminLevel,
      });

      // Step 3: Create initial secret path structure
      await this.createAdminSecretPathStructure(vaultPath);

      // Step 4: Configure admin policies based on admin level
      await this.configureAdminPolicies({
        vaultId,
        vaultPath,
        adminLevel: request.adminLevel,
      });

      // Step 5: Enable audit logging (always enabled for admin vaults)
      await this.enableAdminAuditLogging(vaultId, vaultPath);

      // Step 6: Set up backup configuration
      if (request.features?.backupEnabled !== false) {
        await this.configureAdminBackup(vaultId, vaultPath);
      }

      logger.info('Admin vault provisioned successfully', {
        vaultId,
        vaultPath,
        adminLevel: request.adminLevel,
      });

      return {
        vaultId,
        vaultPath,
        apiEndpoint: this.VAULT_CLUSTER_ENDPOINTS[0], // Primary endpoint
        roleId,
        secretId,
        status: 'provisioned',
        metadata: {
          createdAt: new Date(),
          organizationId: orgId,
          adminLevel: request.adminLevel,
        },
      };
    } catch (error) {
      logger.error('Failed to provision admin vault', {
        organizationName: request.organizationName,
        error: error instanceof Error ? error.message : 'Unknown error',
      });
      throw new DbisError(
        ErrorCode.INTERNAL_ERROR,
        `Failed to provision admin vault: ${error instanceof Error ? error.message : 'Unknown error'}`
      );
    }
  }

  /**
   * Create AppRole for admin vault with elevated permissions
   */
  private async createAdminAppRole(params: {
    vaultId: string;
    vaultPath: string;
    adminLevel: string;
  }): Promise<{ roleId: string; secretId: string }> {
    const policyName = `admin-${params.vaultId}-policy`;
    const roleName = `admin-${params.vaultId}-role`;

    const vaultClient = await this.getVaultClient();

    // Create admin policy with elevated permissions
    const policy = this.generateAdminPolicy(params.vaultPath, params.adminLevel);
    await vaultClient.write(`sys/policies/acl/${policyName}`, { policy });

    // Create AppRole with extended TTL for admin access
    await vaultClient.write(`auth/approle/role/${roleName}`, {
      token_policies: policyName,
      bind_secret_id: true,
      secret_id_ttl: '168h', // 7 days for admin
      token_ttl: '8h', // 8 hours
      token_max_ttl: '24h', // 24 hours max
      token_num_uses: 0,
    });

    // Get Role ID
    const roleIdResponse = await vaultClient.read(`auth/approle/role/${roleName}/role-id`);
    const roleId = roleIdResponse.data.role_id;

    // Generate Secret ID
    const secretIdResponse = await vaultClient.write(`auth/approle/role/${roleName}/secret-id`, {});
    const secretId = secretIdResponse.data.secret_id;

    return { roleId, secretId };
  }

  /**
   * Generate admin policy with elevated permissions
   */
  private generateAdminPolicy(vaultPath: string, adminLevel: string): string {
    const basePolicy = `
# Admin Vault Policy - ${vaultPath}
# Admin Level: ${adminLevel}

# Full access to admin vault path
path "${vaultPath}/*" {
  capabilities = ["create", "read", "update", "delete", "list"]
}

path "${vaultPath.replace('/data/', '/metadata/')}/*" {
  capabilities = ["list", "read", "delete"]
}

# Health check access
path "sys/health" {
  capabilities = ["read"]
}
`;

    if (adminLevel === 'super_admin') {
      return basePolicy + `
# Super Admin: Additional system access
path "sys/policies/acl/*" {
  capabilities = ["list", "read"]
}

path "auth/approle/role/*" {
  capabilities = ["list", "read"]
}
`;
    }

    return basePolicy;
  }

  /**
   * Create admin secret path structure
   */
  private async createAdminSecretPathStructure(vaultPath: string): Promise<void> {
    const vaultClient = await this.getVaultClient();

    // Create initial placeholder secret to establish path
    await vaultClient.write(vaultPath.replace('/data/', '/'), {
      initialized: true,
      createdAt: new Date().toISOString(),
      adminVault: true,
    });

    // Create sub-paths for organization
    const subPaths = [
      'blockchain',
      'cloudflare',
      'database',
      'npm',
      'infrastructure',
      'api-keys',
      'certificates',
      'tokens',
    ];

    for (const subPath of subPaths) {
      try {
        await vaultClient.write(`${vaultPath.replace('/data/', '/')}/${subPath}`, {
          category: subPath,
          createdAt: new Date().toISOString(),
        });
      } catch (error) {
        // Path might already exist, continue
        logger.debug(`Sub-path ${subPath} may already exist`, { error });
      }
    }
  }

  /**
   * Configure admin policies
   */
  private async configureAdminPolicies(params: {
    vaultId: string;
    vaultPath: string;
    adminLevel: string;
  }): Promise<void> {
    logger.info('Admin policies configured', {
      vaultId: params.vaultId,
      adminLevel: params.adminLevel,
    });
  }

  /**
   * Enable admin audit logging
   */
  private async enableAdminAuditLogging(vaultId: string, vaultPath: string): Promise<void> {
    // In production, configure audit device for admin vault
    logger.info('Admin audit logging enabled', {
      vaultId,
      vaultPath,
    });
  }

  /**
   * Configure admin backup
   */
  private async configureAdminBackup(vaultId: string, vaultPath: string): Promise<void> {
    // Admin vaults are included in daily cluster backups
    logger.info('Admin backup configured', {
      vaultId,
      vaultPath,
    });
  }

  /**
   * Generate organization ID from name
   */
  private generateOrgId(organizationName: string): string {
    return organizationName
      .toLowerCase()
      .replace(/[^a-z0-9]/g, '-')
      .replace(/-+/g, '-')
      .substring(0, 32);
  }

  /**
   * Get Vault client
   */
  private async getVaultClient(): Promise<any> {
    const fetch = (await import('node-fetch')).default;
    
    return {
      write: async (path: string, data: any) => {
        const response = await fetch(`${this.VAULT_CLUSTER_ENDPOINTS[0]}/v1/${path}`, {
          method: 'POST',
          headers: {
            'X-Vault-Token': this.VAULT_ROOT_TOKEN,
            'Content-Type': 'application/json',
          },
          body: JSON.stringify(data),
        });
        if (!response.ok) {
          const errorText = await response.text();
          throw new Error(`Vault API error: ${response.status} ${errorText}`);
        }
        return { data: await response.json() };
      },
      read: async (path: string) => {
        const response = await fetch(`${this.VAULT_CLUSTER_ENDPOINTS[0]}/v1/${path}`, {
          method: 'GET',
          headers: {
            'X-Vault-Token': this.VAULT_ROOT_TOKEN,
          },
        });
        if (!response.ok) {
          const errorText = await response.text();
          throw new Error(`Vault API error: ${response.status} ${errorText}`);
        }
        return { data: await response.json() };
      },
      delete: async (path: string) => {
        const response = await fetch(`${this.VAULT_CLUSTER_ENDPOINTS[0]}/v1/${path}`, {
          method: 'DELETE',
          headers: {
            'X-Vault-Token': this.VAULT_ROOT_TOKEN,
          },
        });
        if (!response.ok && response.status !== 404) {
          const errorText = await response.text();
          throw new Error(`Vault API error: ${response.status} ${errorText}`);
        }
        return { success: true };
      },
    };
  }
}

export const adminVaultProvisioningService = new AdminVaultProvisioningService();
