import { Injectable, Logger, OnModuleDestroy, OnModuleInit } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';
import { envs } from 'src/config';

/**
 * Cliente DB dedicado al Chat IA con usuario PostgreSQL de SOLO LECTURA.
 *
 * Estrategia de arranque:
 *  1. Si AI_READONLY_DATABASE_URL está configurado, intenta conectarse.
 *  2. Si la conexión falla (usuario no existe aún, password incorrecto, etc.),
 *     hace fallback silencioso al DATABASE_URL principal con un warning.
 *  3. Si AI_READONLY_DATABASE_URL no está configurado, usa DATABASE_URL directamente.
 *
 * Esto permite arrancar el servidor antes de correr el script SQL del usuario readonly.
 */
@Injectable()
export class AiReadonlyDbService implements OnModuleInit, OnModuleDestroy {
  private readonly logger = new Logger(AiReadonlyDbService.name);
  private client!: PrismaClient;
  private _usingReadonlyUser = false;

  async onModuleInit() {
    const readonlyUrl = envs.aiReadonlyDatabaseUrl?.trim();

    if (readonlyUrl) {
      // Intentar conectar con el usuario read-only
      const readonlyClient = new PrismaClient({
        datasources: { db: { url: readonlyUrl } },
        log: ['warn', 'error'],
      });
      try {
        await readonlyClient.$connect();
        // Verificar con una query trivial que el usuario tiene acceso
        await readonlyClient.$queryRaw`SELECT 1`;
        this.client = readonlyClient;
        this._usingReadonlyUser = true;
        this.logger.log('Chat IA: usando usuario PostgreSQL de SOLO LECTURA ✔');
        return;
      } catch (err) {
        await readonlyClient.$disconnect().catch(() => undefined);
        this.logger.warn(
          `Chat IA: no se pudo conectar con AI_READONLY_DATABASE_URL (${err instanceof Error ? err.message : String(err)}). ` +
            'Usando DATABASE_URL principal como fallback. ' +
            'Ejecutá el script prisma/migrations/20260623_ai_readonly_user.sql para habilitar el usuario read-only.',
        );
      }
    } else {
      this.logger.warn(
        'Chat IA: AI_READONLY_DATABASE_URL no configurado. Usando DATABASE_URL principal. ' +
          'RIESGO: configurar el usuario read-only es recomendado para mayor seguridad.',
      );
    }

    // Fallback: usar pool principal
    this.client = new PrismaClient({
      datasources: { db: { url: envs.databaseUrl } },
      log: ['warn', 'error'],
    });
    await this.client.$connect();
    this._usingReadonlyUser = false;
  }

  async onModuleDestroy() {
    await this.client?.$disconnect().catch(() => undefined);
  }

  get isReadonlyEnforced(): boolean {
    return this._usingReadonlyUser;
  }

  // ── Delegación de métodos usados por chat.service ─────────────────

  $queryRawUnsafe<T = unknown>(query: string, ...values: unknown[]): Promise<T> {
    return this.client.$queryRawUnsafe<T>(query, ...values);
  }

  /**
   * Ejecuta una consulta con aislamiento por empresa reforzado a nivel base de
   * datos (Row Level Security). Corre dentro de una transacción y setea el GUC
   * `app.empresa_id` (transaction-local) ANTES de la query; las policies RLS del
   * rol `novasis_ai_readonly` filtran cada tabla con
   * `empresa_id = current_setting('app.empresa_id', true)::uuid`.
   *
   * Así, aunque el SQL generado por el LLM omita (o falsee vía prompt injection)
   * el filtro `WHERE empresa_id = $1`, la DB nunca devuelve filas de otro tenant.
   * `set_config(..., true)` garantiza que el GUC viva solo en esta transacción y
   * sobre la MISMA conexión que ejecuta la consulta.
   *
   * Nota: RLS solo se aplica si la conexión usa el rol read-only (no superusuario).
   * En el fallback a DATABASE_URL (superusuario) RLS se bypassa; por eso el binding
   * de `$1` en el SQL se mantiene como defensa adicional.
   */
  async runTenantScoped<T = unknown>(
    empresaId: string,
    query: string,
    ...values: unknown[]
  ): Promise<T> {
    return this.client.$transaction(async (tx) => {
      await tx.$queryRawUnsafe(`SELECT set_config('app.empresa_id', $1, true)`, empresaId);
      return tx.$queryRawUnsafe<T>(query, ...values);
    });
  }
}
