import { createClient } from '@supabase/supabase-js';
import dotenv from 'dotenv';
import { Pool } from 'pg';
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';

// Get the directory of the current module
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

// Load .env from backend root (parent directory of src)
dotenv.config({ path: join(__dirname, '..', '.env') });

// Check if using local database
const useLocalDb = process.env.USE_LOCAL_DB === 'true';

// Direct Postgres pool for heavy queries (local or remote)
let pgPool = null;

if (useLocalDb) {
  // Use local PostgreSQL database
  const localDbConfig = {
    host: process.env.LOCAL_DB_HOST || '192.168.8.151',
    port: parseInt(process.env.LOCAL_DB_PORT || '5432'),
    user: process.env.LOCAL_DB_USER || 'postgres',
    password: process.env.LOCAL_DB_PASSWORD || 'postgres',
    database: process.env.LOCAL_DB_NAME || 'institutional_trader'
  };

  if (!localDbConfig.password) {
    throw new Error(
      'Missing LOCAL_DB_PASSWORD for local database.\n' +
      'Please add to your .env file:\n' +
      'USE_LOCAL_DB=true\n' +
      'LOCAL_DB_PASSWORD=your_postgres_password\n' +
      'See LOCAL_DB_SETUP.md for setup instructions'
    );
  }

  pgPool = new Pool({
    host: localDbConfig.host,
    port: localDbConfig.port,
    user: localDbConfig.user,
    password: localDbConfig.password,
    database: localDbConfig.database,
    max: 20,
    idleTimeoutMillis: 30000,
    connectionTimeoutMillis: 10000,
  });

  pgPool.on('error', (err) => {
    console.error('Unexpected error on idle client', err);
  });

  console.log('📦 Using local PostgreSQL database');
} else if (process.env.DATABASE_URL) {
  // Use remote PostgreSQL via connection string
  try {
    pgPool = new Pool({
      connectionString: process.env.DATABASE_URL,
      max: 20,
      idleTimeoutMillis: 30000,
      connectionTimeoutMillis: 10000, // Increased timeout
    });

    pgPool.on('error', (err) => {
      console.error('Unexpected error on idle client', err);
    });
  } catch (err) {
    console.warn('Failed to create PostgreSQL pool:', err.message);
    console.warn('Will fall back to Supabase client');
  }
}

// Supabase client (only initialized if not using local DB)
let supabase = null;
let supabaseAnon = null;

if (!useLocalDb) {
  const supabaseUrl = process.env.SUPABASE_URL;
  const supabaseKey = process.env.SUPABASE_SERVICE_KEY || process.env.SUPABASE_KEY;
  const supabaseAnonKey = process.env.SUPABASE_ANON_KEY || process.env.SUPABASE_KEY;

  if (supabaseUrl && supabaseKey) {
    // Create Supabase client with service key for admin operations
    supabase = createClient(supabaseUrl, supabaseKey, {
      auth: {
        persistSession: false,
      },
      db: {
        schema: 'public',
      },
      global: {
        headers: { 'x-application-name': 'flow-platform' },
      },
    });

    // Create Supabase client with anon key for regular operations
    supabaseAnon = createClient(supabaseUrl, supabaseAnonKey);
  }
}

export { pgPool, supabase, supabaseAnon };

/**
 * Convert any date/timestamp to PostgreSQL-safe ISO 8601 format
 * Best practice: Normalize dates at the Node.js boundary before hitting PostgreSQL
 * 
 * @param {Date|string|number} date - Date object, ISO string, timestamp, or date string
 * @param {boolean} includeTime - If true, includes time component (for timestamps), default: false (date only)
 * @returns {string} PostgreSQL-safe format: YYYY-MM-DD or YYYY-MM-DD HH:MM:SS.000
 * 
 * @example
 * toPgTimestamp(new Date('2025-12-17 3:59:59 PM')) // "2025-12-17 15:59:59.000"
 * toPgTimestamp('2025-12-17 3:59:59 PM') // "2025-12-17 15:59:59.000"
 * toPgTimestamp('2025-12-17') // "2025-12-17"
 * toPgTimestamp(new Date('2025-12-17'), false) // "2025-12-17" (date only)
 */
export function toPgTimestamp(date, includeTime = false) {
  if (!date) return null;
  
  // Handle Date objects
  if (date instanceof Date) {
    if (includeTime) {
      // Return ISO format with space instead of T, remove Z, add milliseconds
      return date.toISOString().replace('T', ' ').replace('Z', '');
    } else {
      // Return date only (YYYY-MM-DD)
      return date.toISOString().split('T')[0];
    }
  }
  
  // Handle timestamps (numbers)
  if (typeof date === 'number') {
    const d = new Date(date);
    if (includeTime) {
      return d.toISOString().replace('T', ' ').replace('Z', '');
    } else {
      return d.toISOString().split('T')[0];
    }
  }
  
  // Handle strings
  if (typeof date === 'string') {
    // If it's already in YYYY-MM-DD format and no time needed, return as-is
    if (!includeTime && /^\d{4}-\d{2}-\d{2}$/.test(date)) {
      return date;
    }
    
    // Try to parse the string as a date
    // Handle common formats: "2025-12-17 3:59:59 PM", "2025-12-17T15:59:59Z", etc.
    const parsed = new Date(date);
    
    // Check if parsing was successful
    if (isNaN(parsed.getTime())) {
      // If parsing failed, try to extract just the date part if it looks like a date
      const dateMatch = date.match(/^\d{4}-\d{2}-\d{2}/);
      if (dateMatch) {
        return dateMatch[0];
      }
      // If we can't parse it, return the original (might cause an error, but that's better than corrupting data)
      console.warn(`Warning: Could not parse date string "${date}", returning as-is`);
      return date;
    }
    
    if (includeTime) {
      return parsed.toISOString().replace('T', ' ').replace('Z', '');
    } else {
      return parsed.toISOString().split('T')[0];
    }
  }
  
  // Unknown type
  console.warn(`Warning: Unknown date type: ${typeof date}, returning as-is`);
  return String(date);
}

/**
 * Convert date to PostgreSQL date format (YYYY-MM-DD)
 * Alias for toPgTimestamp(date, false)
 * 
 * @param {Date|string|number} date - Date to convert
 * @returns {string} YYYY-MM-DD format
 */
export function toPgDate(date) {
  return toPgTimestamp(date, false);
}

/**
 * Raw SQL query helper
 * Uses direct PostgreSQL connection if available, otherwise falls back to Supabase RPC
 * 
 * @param {string} sql - SQL query with parameterized placeholders ($1, $2, etc.)
 * @param {Array} params - Array of parameter values
 * @returns {Promise<any>} Query results
 */
export async function rawQuery(sql, params = []) {
  // Use direct PostgreSQL connection if available (faster for heavy queries)
  if (pgPool) {
    const client = await pgPool.connect();
    try {
      const result = await client.query(sql, params);
      return result.rows;
    } finally {
      client.release();
    }
  }

  // Fallback to Supabase RPC method (only if Supabase client is available)
  if (supabase) {
    try {
      const paramsJsonb = JSON.stringify(params);
      
      const { data, error } = await supabase.rpc('exec_sql', {
        query: sql,
        params: paramsJsonb
      });

      if (error) {
        console.error('Raw SQL query error:', error);
        throw new Error(`SQL query failed: ${error.message}`);
      }

      return data;
    } catch (err) {
      // Fallback: if RPC doesn't exist, throw helpful error
      if (err.message?.includes('function exec_sql') || err.code === '42883') {
        throw new Error(
          'exec_sql RPC function not found. Please create it in Supabase SQL Editor or set DATABASE_URL for direct connection. ' +
          'See db.js comments for the SQL function definition.'
        );
      }
      throw err;
    }
  }

  // No database connection available
  throw new Error(
    'No database connection available. Please set:\n' +
    '  - USE_LOCAL_DB=true with LOCAL_DB_* variables (for local PostgreSQL)\n' +
    '  - OR DATABASE_URL (for remote PostgreSQL)\n' +
    '  - OR SUPABASE_URL + SUPABASE_SERVICE_KEY (for Supabase)'
  );
}

// Test connection
export async function testConnection() {
  try {
    // Prefer direct PostgreSQL connection if available
    if (pgPool) {
      try {
        await Promise.race([
          pgPool.query('SELECT 1'),
          new Promise((_, reject) => 
            setTimeout(() => reject(new Error('Connection timeout')), 10000)
          )
        ]);
        console.log('✅ Database connection successful (PostgreSQL direct)');
        return true;
      } catch (pgErr) {
        if (pgErr.code === 'ENOTFOUND' || pgErr.message?.includes('ENOTFOUND')) {
          console.error('❌ Database connection error: Hostname not found');
          console.error('\nTroubleshooting:');
          console.error('1. Verify your DATABASE_URL hostname is correct');
          console.error('2. Check if your Supabase project is active (not paused)');
          console.error('3. Check if project has exceeded quota (see error message)');
          console.error('4. Try using the Pooler connection string instead:');
          console.error('   - Go to Supabase Dashboard > Settings > Database');
          console.error('   - Use "Connection Pooling" tab instead of "URI" tab');
          console.error('   - Format: postgresql://postgres:[password]@[project-ref].pooler.supabase.com:6543/postgres');
          console.error('5. Or use Supabase client with API keys (set SUPABASE_URL and SUPABASE_SERVICE_KEY)');
          console.error('\nError details:', pgErr.message);
          // Fall through to try Supabase client
        } else if (pgErr.message?.includes('exceed_db_size_quota') || pgErr.message?.includes('restricted')) {
          console.error('❌ Database connection error: Project quota exceeded');
          console.error('\nYour Supabase project has exceeded the database size quota.');
          console.error('\nSolutions:');
          console.error('1. Contact Supabase support: https://supabase.help');
          console.error('2. Upgrade your plan in Supabase Dashboard > Settings > Billing');
          console.error('3. Clean up old data to reduce database size');
          console.error('4. See DATABASE_QUOTA_FIX.md for detailed steps');
          console.error('\nError details:', pgErr.message);
          return false;
        } else {
          throw pgErr;
        }
      }
    }
    
    // Fallback to Supabase client (only if available)
    if (!supabase) {
      console.error('❌ No database connection available');
      console.error('Please set either:');
      console.error('  - USE_LOCAL_DB=true with LOCAL_DB_* variables (for local PostgreSQL)');
      console.error('  - OR DATABASE_URL (for remote PostgreSQL)');
      console.error('  - OR SUPABASE_URL + SUPABASE_SERVICE_KEY (for Supabase client)');
      return false;
    }
    
    const { data, error } = await supabase.from('options_flow').select('count').limit(1);
    if (error) {
      // PGRST116 = table doesn't exist (ok for setup)
      // PGRST301 = invalid API key
      if (error.code === 'PGRST116') {
        console.log('✅ Database connection successful (table may not exist yet)');
        return true;
      }
      if (error.code === 'PGRST301' || error.message?.includes('Invalid API key')) {
        console.error('❌ Database connection error: Invalid API key');
        console.error('\nTroubleshooting:');
        console.error('1. Check your .env file has the correct SUPABASE_SERVICE_KEY');
        console.error('2. Get the service_role key from: Supabase Dashboard > Settings > API');
        console.error('3. Make sure you\'re using the service_role key (not anon key) for backend');
        console.error('4. Alternatively, use DATABASE_URL for direct PostgreSQL connection');
        console.error('\nError details:', error);
        return false;
      }
      if (error.message?.includes('exceed_db_size_quota') || error.message?.includes('restricted')) {
        console.error('❌ Database connection error: Project quota exceeded');
        console.error('\nYour Supabase project has exceeded the database size quota.');
        console.error('\nSolutions:');
        console.error('1. Contact Supabase support: https://supabase.help');
        console.error('2. Upgrade your plan in Supabase Dashboard > Settings > Billing');
        console.error('3. Clean up old data to reduce database size');
        console.error('4. See DATABASE_QUOTA_FIX.md for detailed steps');
        console.error('\nError details:', error);
        return false;
      }
      console.error('Database connection error:', error);
      return false;
    }
    console.log('✅ Database connection successful (Supabase)');
    return true;
  } catch (err) {
    console.error('Database connection failed:', err);
    if (err.message?.includes('Invalid API key')) {
      console.error('\nTroubleshooting:');
      console.error('1. Verify SUPABASE_URL and SUPABASE_SERVICE_KEY in your .env file');
      console.error('2. Get keys from: Supabase Dashboard > Settings > API');
      console.error('3. Consider using local database: set USE_LOCAL_DB=true');
      console.error('4. Or use DATABASE_URL for direct PostgreSQL connection');
    } else if (useLocalDb) {
      console.error('\nTroubleshooting for local database:');
      console.error('1. Verify PostgreSQL is running');
      console.error('2. Check LOCAL_DB_* variables in .env file');
      console.error('3. See LOCAL_DB_SETUP.md for setup instructions');
    }
    return false;
  }
}

