import db from '../config/database';
import { CredentialType } from '../models/CredentialVault';
import { VaultCrypto } from '../utils/VaultCrypto';
import { AuditService } from './AuditService';

/**
 * [CORE_SEC_01] 凭证保险库服务
 * 提供凭证的加密存储、短时解密与生命周期管理
 */
export class VaultService {
  private static TABLE_NAME = 'cf_credential_vault';

  /**
   * 初始化数据库表
   */
  static async initTable() {
    const hasVaultTable = await db.schema.hasTable(this.TABLE_NAME);
    if (!hasVaultTable) {
      console.log(`📦 Creating ${this.TABLE_NAME} table...`);
      await db.schema.createTable(this.TABLE_NAME, (table) => {
        table.increments('id').primary();
        table.string('tenant_id', 64).notNullable();
        table.string('shop_id', 64);
        table.string('platform', 32).notNullable();
        table.string('credential_type', 16).notNullable();
        table.string('account_name', 128).notNullable();
        table.text('encrypted_data').notNullable();
        table.string('iv', 32).notNullable();
        table.string('tag', 32).notNullable();
        table.timestamp('expires_at');
        table.json('metadata');
        table.timestamps(true, true);

        table.index(['tenant_id', 'shop_id', 'platform']);
        table.index(['account_name']);
      });
      console.log(`✅ Table ${this.TABLE_NAME} created`);
    }

    const hasSecretSessionsTable = await db.schema.hasTable('cf_secret_sessions');
    if (!hasSecretSessionsTable) {
      console.log('📦 Creating cf_secret_sessions table...');
      await db.schema.createTable('cf_secret_sessions', (table) => {
        table.string('session_id', 64).primary();
        table.string('node_id', 64).notNullable();
        table.string('shop_id', 64).notNullable();
        table.string('task_id', 64).notNullable();
        table.string('session_key', 128).notNullable();
        table.timestamp('expires_at').notNullable();
        table.timestamps(true, true);

        table.index(['node_id', 'task_id']);
      });
      console.log('✅ Table cf_secret_sessions created');
    }
  }

  /**
   * 保存或更新凭证
   */
  static async saveCredential(
    context: { tenantId: string; userId: string; traceId: string; shopId?: string },
    data: {
      platform: string;
      credentialType: CredentialType;
      accountName: string;
      plainText: string;
      expiresAt?: Date;
      metadata?: any;
    }
  ) {
    const { encryptedData, iv, tag } = VaultCrypto.encrypt(data.plainText);

    const existing = await db(this.TABLE_NAME)
      .where({
        tenant_id: context.tenantId,
        platform: data.platform,
        credential_type: data.credentialType,
        account_name: data.accountName,
      })
      .first();

    const vaultData = {
      tenant_id: context.tenantId,
      shop_id: context.shopId,
      platform: data.platform,
      credential_type: data.credentialType,
      account_name: data.accountName,
      encrypted_data: encryptedData,
      iv,
      tag,
      expires_at: data.expiresAt,
      metadata: data.metadata ? JSON.stringify(data.metadata) : null,
      updated_at: new Date(),
    };

    if (existing) {
      await db(this.TABLE_NAME).where({ id: existing.id }).update(vaultData);
      
      await AuditService.log({
        ...context,
        module: 'SECURITY',
        action: 'VAULT_UPDATE',
        resourceType: 'vault',
        resourceId: String(existing.id),
        beforeSnapshot: { accountName: existing.account_name },
        afterSnapshot: { accountName: data.accountName },
        result: 'success',
        source: 'console',
      });
      
      return existing.id;
    } else {
      const [newId] = await db(this.TABLE_NAME).insert({
        ...vaultData,
        created_at: new Date(),
      });

      await AuditService.log({
        ...context,
        module: 'SECURITY',
        action: 'VAULT_CREATE',
        resourceType: 'vault',
        resourceId: String(newId),
        beforeSnapshot: null,
        afterSnapshot: { accountName: data.accountName, platform: data.platform },
        result: 'success',
        source: 'console',
      });

      return newId;
    }
  }

  /**
   * 获取解密后的凭证 (JIT - Just In Time)
   */
  static async getDecryptedCredential(
    context: { tenantId: string; userId: string; traceId: string },
    id: number
  ): Promise<string | null> {
    const record = await db(this.TABLE_NAME).where({ id, tenant_id: context.tenantId }).first();
    if (!record) return null;

    // 记录解密审计 (谁在何时访问了敏感数据)
    await AuditService.log({
      ...context,
      module: 'SECURITY',
      action: 'VAULT_DECRYPT_ACCESS',
      resourceType: 'vault',
      resourceId: String(id),
      afterSnapshot: { accountName: record.account_name, platform: record.platform },
      result: 'success',
      source: 'node',
    });

    return VaultCrypto.decrypt(record.encrypted_data, record.iv, record.tag);
  }

  /**
   * 获取原始加密记录 (内部使用)
   */
  static async getRawRecord(tenantId: string, id: number) {
    return await db(this.TABLE_NAME).where({ id, tenant_id: tenantId }).first();
  }

  /**
   * 获取凭证列表 (仅脱敏信息)
   */
  static async listCredentials(tenantId: string, shopId?: string): Promise<any[]> {
    const query = db(this.TABLE_NAME).where({ tenant_id: tenantId });
    if (shopId) query.andWhere({ shop_id: shopId });

    const records = await query.select(
      'id',
      'platform',
      'credential_type',
      'account_name',
      'expires_at',
      'updated_at'
    );

    return records;
  }

  /**
   * [CORE_SEC_02] 凭据轮换逻辑
   */
  static async rotateCredential(
    context: { tenantId: string; userId: string; traceId: string },
    id: number,
    newPlainText: string
  ) {
    const record = await db(this.TABLE_NAME).where({ id, tenant_id: context.tenantId }).first();
    if (!record) throw new Error('Credential not found');

    const { encryptedData, iv, tag } = VaultCrypto.encrypt(newPlainText);

    await db(this.TABLE_NAME).where({ id }).update({
      encrypted_data: encryptedData,
      iv,
      tag,
      updated_at: new Date()
    });

    await AuditService.log({
      ...context,
      module: 'SECURITY',
      action: 'VAULT_ROTATE',
      resourceType: 'vault',
      resourceId: String(id),
      beforeSnapshot: { accountName: record.account_name, lastUpdatedAt: record.updated_at },
      afterSnapshot: { accountName: record.account_name, status: 'rotated' },
      result: 'success',
      source: 'console'
    });
  }
}
