import { MongoClient, Db, Collection, Document, MongoClientOptions, ServerApiVersion } from "mongodb";

// MongoDB Atlas connection string
// Default to MongoDB Atlas connection if MONGODB_URI is not set
const envUri = process.env.MONGODB_URI;
const uri = envUri || 'mongodb+srv://irshukdy:Irshad00691@cluster0.64popug.mongodb.net/cratis?retryWrites=true&w=majority';

// Validate MongoDB URI (only warn, don't throw at module load time)
function validateMongoDBUri(uri: string, envUri: string | undefined): void {
  // Warn if using default connection (environment variable not set)
  if (!envUri) {
    console.warn(
      "⚠️  WARNING: MONGODB_URI environment variable is not set. " +
      "Using default MongoDB Atlas connection. " +
      "Please set MONGODB_URI in your .env.local file for production use."
    );
  }

  // Warn if using local MongoDB (but don't block the app)
  if (uri.startsWith("mongodb://127.0.0.1") || uri.startsWith("mongodb://localhost")) {
    console.warn(
      "⚠️  WARNING: Local MongoDB connections are detected. " +
      "This application is configured to use MongoDB Atlas only. " +
      "Please update your MONGODB_URI to use MongoDB Atlas (mongodb+srv://...)."
    );
  }
}

// Validate URI (warning only, not blocking)
validateMongoDBUri(uri, envUri);

// MongoDB client options with Stable API version
const options: MongoClientOptions = {
  serverApi: {
    version: ServerApiVersion.v1,
    strict: true,
    deprecationErrors: true,
  },
  maxPoolSize: 10, // Maintain up to 10 socket connections
  serverSelectionTimeoutMS: 10000, // Increase timeout to 10 seconds
  socketTimeoutMS: 45000, // Close sockets after 45 seconds of inactivity
  connectTimeoutMS: 10000, // Connection timeout
  retryWrites: true,
  retryReads: true,
  // SSL/TLS options for better compatibility
  tls: true,
  tlsAllowInvalidCertificates: false,
  tlsAllowInvalidHostnames: false,
};

declare global {
  // eslint-disable-next-line no-var
  var _mongoClientPromise: Promise<MongoClient> | undefined;
}

let clientPromise: Promise<MongoClient>;

// Initialize MongoDB connection
function initializeMongoClient(): Promise<MongoClient> {
  if (!global._mongoClientPromise) {
    try {
      const client = new MongoClient(uri, options);
      global._mongoClientPromise = client.connect().catch((error: any) => {
        console.error("❌ Failed to connect to MongoDB Atlas");
        console.error("   Error:", error.message);
        
        // Provide specific error messages based on error type
        if (error.message.includes('SSL') || error.message.includes('TLS') || error.message.includes('alert')) {
          console.error("\n💡 SSL/TLS Error - Common solutions:");
          console.error("   1. Your IP address is NOT whitelisted in MongoDB Atlas");
          console.error("   2. Go to MongoDB Atlas → Network Access → Add IP Address");
          console.error("   3. Add your current IP address (or use 0.0.0.0/0 for all IPs - less secure)");
          console.error("   4. Wait 1-2 minutes after adding IP for changes to take effect");
        } else if (error.message.includes('Authentication failed') || error.message.includes('bad auth')) {
          console.error("\n💡 Authentication Error:");
          console.error("   1. Check your MongoDB username and password");
          console.error("   2. Verify your connection string is correct");
          console.error("   3. Make sure special characters in password are URL-encoded");
        } else if (error.message.includes('timeout') || error.message.includes('ECONNREFUSED')) {
          console.error("\n💡 Connection Timeout:");
          console.error("   1. Check your internet connection");
          console.error("   2. Verify MongoDB Atlas cluster is running");
          console.error("   3. Check if firewall is blocking the connection");
        } else {
          console.error("\n💡 General Connection Error:");
          console.error("   1. Verify MONGODB_URI is correct in .env.local");
          console.error("   2. Check MongoDB Atlas cluster status");
          console.error("   3. Verify your IP is whitelisted");
          console.error("   4. Check MongoDB Atlas logs for more details");
        }
        
        console.error("\n📝 To find your IP address:");
        console.error("   - Visit: https://www.whatismyip.com/");
        console.error("   - Or run: curl https://api.ipify.org");
        
        // Don't throw - let the error be handled by the calling function
        throw error;
      });
    } catch (error) {
      console.error("❌ Error creating MongoDB client:", error);
      throw error;
    }
  }
  return global._mongoClientPromise;
}

// Initialize connection
clientPromise = initializeMongoClient();

function getDbNameFromUri(uri: string): string {
  // Extract the database name as mapped in Mongo's official URI spec
  // Mongo URI format: mongodb://.../dbname?... or mongodb+srv://.../dbname?... 
  // If not present fallback to 'cratis'
  try {
    // Find the path after the last slash that's not followed by ? or \
    // Also ignore any trailing query string/params
    const withoutParams = uri.split("?")[0];
    const afterLastSlash = withoutParams.substring(withoutParams.lastIndexOf("/") + 1);
    return afterLastSlash ? afterLastSlash : "cratis";
  } catch {
    return "cratis";
  }
}

export async function getDb(): Promise<Db> {
  const client = await clientPromise;
  const dbName = getDbNameFromUri(uri);
  return client.db(dbName);
}

export async function getCollection<T extends Document>(name: string): Promise<Collection<T>> {
  try {
    const db = await getDb();
    
    // Ensure the name is exactly as expected (case-sensitive, no accidental whitespace)
    const actualName = name.trim();
    
    // Only log warnings in development mode
    if (process.env.NODE_ENV === 'development') {
      try {
        const collections = await db.listCollections().toArray();
        const colNames = collections.map(col => col.name);
        if (!colNames.includes(actualName)) {
          console.warn(`[mongodb] Collection "${actualName}" does not exist yet. It will be created on first insert.`);
        }
      } catch (error) {
        // Ignore errors when listing collections (might not have permissions)
      }
    }
    
    return db.collection<T>(actualName);
  } catch (error) {
    console.error(`[mongodb] Error getting collection "${name}":`, error);
    throw error;
  }
}
