import { Injectable, Logger } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';

/**
 * TenantPrismaService - Verwaltet dynamische Datenbankverbindungen pro Mandant.
 *
 * Jeder Tenant hat eine eigene Datenbank (tenant_{slug}).
 * Verbindungen werden gecacht und bei Inaktivitaet automatisch geschlossen.
 */
@Injectable()
export class TenantPrismaService {
  private readonly logger = new Logger(TenantPrismaService.name);
  private readonly clients = new Map<
    string,
    { client: PrismaClient; lastUsed: number }
  >();

  // Maximale Inaktivitaetszeit in Millisekunden (30 Minuten)
  private readonly MAX_IDLE_TIME = 30 * 60 * 1000;

  /**
   * Gibt einen PrismaClient fuer den angegebenen Tenant zurueck.
   * Erstellt eine neue Verbindung oder nutzt eine gecachte.
   */
  async getClient(tenantSlug: string): Promise<PrismaClient> {
    const existing = this.clients.get(tenantSlug);
    if (existing) {
      existing.lastUsed = Date.now();
      return existing.client;
    }

    const dbName = `tenant_${tenantSlug}`;
    const baseUrl = process.env.DATABASE_URL_DIRECT ?? process.env.DATABASE_URL;
    if (!baseUrl) {
      throw new Error('DATABASE_URL ist nicht konfiguriert');
    }

    // URL modifizieren: Datenbankname ersetzen
    const url = new URL(baseUrl);
    url.pathname = `/${dbName}`;

    const client = new PrismaClient({
      datasources: {
        db: { url: url.toString() },
      },
    });

    await client.$connect();
    this.logger.log(`Tenant-DB Verbindung hergestellt: ${dbName}`);

    this.clients.set(tenantSlug, {
      client,
      lastUsed: Date.now(),
    });

    return client;
  }

  /**
   * Schliesst eine bestimmte Tenant-Verbindung.
   */
  async disconnectTenant(tenantSlug: string): Promise<void> {
    const existing = this.clients.get(tenantSlug);
    if (existing) {
      await existing.client.$disconnect();
      this.clients.delete(tenantSlug);
      this.logger.log(`Tenant-DB Verbindung geschlossen: tenant_${tenantSlug}`);
    }
  }

  /**
   * Schliesst alle inaktiven Verbindungen.
   * Wird periodisch vom CleanupService aufgerufen.
   */
  async cleanupIdleConnections(): Promise<number> {
    const now = Date.now();
    let closed = 0;

    for (const [slug, entry] of this.clients.entries()) {
      if (now - entry.lastUsed > this.MAX_IDLE_TIME) {
        await entry.client.$disconnect();
        this.clients.delete(slug);
        this.logger.log(
          `Idle Tenant-DB Verbindung geschlossen: tenant_${slug}`,
        );
        closed++;
      }
    }

    return closed;
  }

  /**
   * Schliesst alle Tenant-Verbindungen (Shutdown).
   */
  async disconnectAll(): Promise<void> {
    for (const [slug, entry] of this.clients.entries()) {
      await entry.client.$disconnect();
      this.logger.log(`Tenant-DB Verbindung geschlossen: tenant_${slug}`);
    }
    this.clients.clear();
  }
}
