/**
 * Service for managing per-tenant Agent SDK configuration.
 *
 * Handles CRUD operations for TenantAgentConfig with:
 * - API key encryption/decryption using CryptoUtil (AES-256-GCM, same pattern as CredentialVaultService)
 * - Upsert semantics (create if not exists, update if exists)
 * - API key removal with automatic revert to subscription billing
 */
import { Injectable, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { CryptoUtil } from '@it0/common';
import { TenantAgentConfigRepository } from '../repositories/tenant-agent-config.repository';
import { TenantAgentConfig } from '../../domain/entities/tenant-agent-config.entity';

export interface UpdateTenantAgentConfigDto {
  billingMode?: 'subscription' | 'api_key';
  apiKey?: string;
  approvalTimeoutSeconds?: number;
  toolWhitelist?: string[];
  toolBlacklist?: string[];
}

@Injectable()
export class TenantAgentConfigService {
  private readonly logger = new Logger(TenantAgentConfigService.name);

  constructor(
    private readonly repo: TenantAgentConfigRepository,
    private readonly configService: ConfigService,
  ) {}

  private get masterKey(): string {
    return this.configService.get<string>('VAULT_MASTER_KEY', 'dev-vault-key');
  }

  async findByTenantId(tenantId: string): Promise<TenantAgentConfig | null> {
    return this.repo.findByTenantId(tenantId);
  }

  async upsert(tenantId: string, dto: UpdateTenantAgentConfigDto): Promise<TenantAgentConfig> {
    let config = await this.repo.findByTenantId(tenantId);

    if (!config) {
      config = new TenantAgentConfig();
      config.tenantId = tenantId;
    }

    if (dto.billingMode !== undefined) {
      config.billingMode = dto.billingMode;
    }

    if (dto.apiKey !== undefined) {
      const { encrypted, iv } = CryptoUtil.encrypt(dto.apiKey, this.masterKey);
      config.encryptedApiKey = encrypted;
      config.apiKeyIv = iv;
    }

    if (dto.approvalTimeoutSeconds !== undefined) {
      config.approvalTimeoutSeconds = dto.approvalTimeoutSeconds;
    }

    if (dto.toolWhitelist !== undefined) {
      config.toolWhitelist = dto.toolWhitelist;
    }

    if (dto.toolBlacklist !== undefined) {
      config.toolBlacklist = dto.toolBlacklist;
    }

    return this.repo.save(config);
  }

  async removeApiKey(tenantId: string): Promise<TenantAgentConfig | null> {
    const config = await this.repo.findByTenantId(tenantId);
    if (!config) return null;

    config.billingMode = 'subscription';
    config.encryptedApiKey = null;
    config.apiKeyIv = null;
    return this.repo.save(config);
  }

  decryptApiKey(config: TenantAgentConfig): string {
    if (!config.encryptedApiKey || !config.apiKeyIv) {
      throw new Error('No API key configured for this tenant');
    }
    return CryptoUtil.decrypt(config.encryptedApiKey, config.apiKeyIv, this.masterKey);
  }
}
