import fs from 'fs';
import path from 'path';
import { getSupabaseServiceClient } from '../config/supabase';
import logger from '../utils/logger';

interface Migration {
  id: string;
  name: string;
  sql: string;
}

class DatabaseMigrator {
  private migrationsDir: string;

  constructor() {
    this.migrationsDir = path.join(__dirname, 'migrations');
  }

  private async getMigrationFiles(): Promise<string[]> {
    try {
      const files = await fs.promises.readdir(this.migrationsDir);
      return files
        .filter(file => file.endsWith('.sql'))
        .sort();
    } catch (error) {
      logger.error('Error reading migrations directory:', error);
      throw error;
    }
  }

  private async loadMigration(fileName: string): Promise<Migration> {
    const filePath = path.join(this.migrationsDir, fileName);
    const sql = await fs.promises.readFile(filePath, 'utf-8');
    
    return {
      id: fileName.replace('.sql', ''),
      name: fileName,
      sql
    };
  }

  private async createMigrationsTable(): Promise<void> {
    const supabase = getSupabaseServiceClient();
    const { error } = await supabase.rpc('exec_sql', {
      sql: `
        CREATE TABLE IF NOT EXISTS migrations (
          id VARCHAR(255) PRIMARY KEY,
          name VARCHAR(255) NOT NULL,
          executed_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
        );
      `
    });

    if (error) {
      logger.error('Error creating migrations table:', error);
      throw error;
    }

    logger.info('Migrations table created or already exists');
  }

  private async isMigrationExecuted(migrationId: string): Promise<boolean> {
    const supabase = getSupabaseServiceClient();
    const { data, error } = await supabase
      .from('migrations')
      .select('id')
      .eq('id', migrationId);

    if (error) {
      logger.error('Error checking migration status:', error);
      throw error;
    }

    return data.length > 0;
  }

  private async markMigrationExecuted(migrationId: string, name: string): Promise<void> {
    const supabase = getSupabaseServiceClient();
    const { error } = await supabase
      .from('migrations')
      .insert([{ id: migrationId, name }]);

    if (error) {
      logger.error('Error marking migration as executed:', error);
      throw error;
    }

    logger.info(`Migration marked as executed: ${name}`);
  }

  private async executeMigration(migration: Migration): Promise<void> {
    try {
      logger.info(`Executing migration: ${migration.name}`);
      
      const supabase = getSupabaseServiceClient();
      const { error } = await supabase.rpc('exec_sql', { sql: migration.sql });

      if (error) {
        throw error;
      }
      
      await this.markMigrationExecuted(migration.id, migration.name);
      
      logger.info(`Migration completed: ${migration.name}`);
    } catch (error) {
      logger.error(`Migration failed: ${migration.name}`, error);
      throw error;
    }
  }

  async migrate(): Promise<void> {
    try {
      logger.info('Starting database migration...');
      
      await this.createMigrationsTable();
      
      const migrationFiles = await this.getMigrationFiles();
      logger.info(`Found ${migrationFiles.length} migration files`);
      
      for (const fileName of migrationFiles) {
        const migration = await this.loadMigration(fileName);
        
        const isExecuted = await this.isMigrationExecuted(migration.id);
        
        if (!isExecuted) {
          await this.executeMigration(migration);
        } else {
          logger.info(`Migration already executed: ${migration.name}`);
        }
      }
      
      logger.info('Database migration completed successfully');
    } catch (error) {
      logger.error('Database migration failed:', error);
      throw error;
    }
  }
}

export default DatabaseMigrator;