import { Injectable, Logger } from "@nestjs/common";
import type { OnModuleInit, OnModuleDestroy } from "@nestjs/common";
import { PrismaClient } from "@prisma/client";
import { Pool } from "pg";
import { PrismaPg } from "@prisma/adapter-pg";

/**
 * Prisma Service
 *
 * Prisma 7+ requires passing an adapter for database connections instead of
 * specifying the URL in the schema file. This service creates a PostgreSQL
 * connection pool and passes it to the PrismaClient via the PrismaPg adapter.
 *
 * @see https://pris.ly/d/prisma7-client-config
 */
@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy {
  private readonly logger = new Logger(PrismaService.name);
  private readonly pool: Pool;
  private destroyCalls = 0;
  private poolEnded = false;

  constructor() {
    const connectionString = process.env["DATABASE_URL"];
    if (!connectionString) {
      throw new Error("DATABASE_URL environment variable is required");
    }

    // Create a connection pool for PostgreSQL
    const pool = new Pool({
      connectionString,
      // Connection pool settings optimized for NestJS
      max: 10, // Maximum number of clients in the pool
      idleTimeoutMillis: 30000, // Close idle clients after 30 seconds
      connectionTimeoutMillis: 5000, // Return an error after 5 seconds if connection fails
    });

    // Create the Prisma PostgreSQL adapter
    const adapter = new PrismaPg(pool);

    // Initialize PrismaClient with the adapter
    super({ adapter });

    this.pool = pool;
  }

  async onModuleInit() {
    await this.$connect();
    this.logger.log("Database connection established");
  }

  async onModuleDestroy() {
    this.destroyCalls += 1;

    // Make shutdown idempotent: Nest can call destroy hooks more than once during restarts.
    if (this.poolEnded) {
      this.logger.warn("Database pool already closed; skipping duplicate shutdown");
      return;
    }
    this.poolEnded = true;

    await this.$disconnect();
    await this.pool.end();
    this.logger.log("Database connection closed");
  }
}
