import mongoose from "mongoose";
import { EventEmitter } from "events";

interface DbConnectionOptions {
  mongoUri: string;
  maxRetries?: number;
  retryDelay?: number;
}

class DatabaseConnection extends EventEmitter {
  private mongoUri: string;
  private maxRetries: number;
  private retryDelay: number;
  private retryCount: number = 0;
  private isConnected: boolean = false;

  constructor(options: DbConnectionOptions) {
    super();
    this.mongoUri = options.mongoUri;
    this.maxRetries = options.maxRetries || 5;
    this.retryDelay = options.retryDelay || 5000;

    // Configure mongoose for high performance
    mongoose.set("strictQuery", true);
  }

  /**
   * Connect to MongoDB with retry capability
   */
  async connect(): Promise<boolean> {
    try {
      if (this.isConnected) {
        return true;
      }

      // Optimized connection options for high throughput
      await mongoose.connect(this.mongoUri, {
        serverSelectionTimeoutMS: 5000,
        maxPoolSize: 100, // Increased connection pool for high throughput
      });

      this.isConnected = true;
      this.retryCount = 0;
      this.emit("connected");

      // Handle connection events
      mongoose.connection.on("error", (err) => {
        console.error("MongoDB connection error:", err);
        this.isConnected = false;
        this.emit("error", err);
        this.retryConnection();
      });

      mongoose.connection.on("disconnected", () => {
        this.isConnected = false;
        this.emit("disconnected");
        this.retryConnection();
      });

      return true;
    } catch (error) {
      console.error("Failed to connect to MongoDB:", error);
      this.emit("error", error);

      return this.retryConnection();
    }
  }

  /**
   * Retry connection with exponential backoff
   */
  private retryConnection(): boolean {
    if (this.retryCount < this.maxRetries) {
      this.retryCount++;

      // Exponential backoff
      const delay = this.retryDelay * Math.pow(2, this.retryCount - 1);
      console.log(
        `Retrying connection in ${delay}ms (attempt ${this.retryCount}/${this.maxRetries})`
      );

      setTimeout(() => {
        this.connect();
      }, delay);

      return true;
    } else {
      this.emit("maxRetriesReached");
      return false;
    }
  }

  /**
   * Disconnect from MongoDB
   */
  async disconnect(): Promise<void> {
    if (mongoose.connection.readyState !== 0) {
      await mongoose.disconnect();
      this.isConnected = false;
      this.emit("disconnected");
    }
  }

  /**
   * Get connection status
   */
  getStatus(): string {
    const states = ["disconnected", "connected", "connecting", "disconnecting"];
    return states[mongoose.connection.readyState];
  }
}

export default DatabaseConnection;
