import { Injectable, InternalServerErrorException } from '@nestjs/common';
import { DataSource } from 'typeorm';

/**
 * MigrationService - Service for database migration operations
 *
 * This service provides methods for executing database migrations in a
 * controlled manner through the application. It wraps TypeORM's migration
 * functionality with proper error handling and logging.
 *
 * Features:
 * - Execute pending migrations (migrateUp)
 * - Rollback the last migration (migrateDown)
 * - Data source availability validation
 * - Structured logging for audit purposes
 *
 * Security considerations:
 * - These operations should be heavily restricted in production
 * - Consider implementing backup mechanisms before migrations
 * - Add confirmation steps for destructive operations
 *
 * @example
 * // Run pending migrations
 * await migrationService.migrateUp();
 *
 * @example
 * // Rollback last migration (use with caution)
 * await migrationService.migrateDown();
 */
@Injectable()
export class MigrationService {
  constructor(private dataSource: DataSource) {}

  /**
   * Execute pending database migrations (up)
   *
   * Applies all pending migrations to bring the database schema
   * up to date with the latest version defined in migration files.
   *
   * Process:
   * 1. Validates data source availability
   * 2. Executes runMigrations() to apply pending migrations
   * 3. Logs successful execution
   * 4. Returns success message
   *
   * @returns Success message string
   * @throws InternalServerErrorException if data source is unavailable
   * @throws TypeORM migration errors if migration scripts fail
   *
   * @note Consider adding transaction support for migration batches
   * @note Add detailed logging of which migrations were executed
   */
  async migrateUp(): Promise<string> {
    // Validate data source is available
    if (this.dataSource) {
      try {
        // Execute all pending migrations
        await this.dataSource.runMigrations();

        // Log success
        console.log(`Migration up executed successfully`);

        return 'migrateUp successfully';
      } catch (error) {
        // Log detailed error information
        console.error('Migration up failed:', error);

        // Re-throw with more context
        throw new InternalServerErrorException(
          `Migration failed: ${error.message}`,
        );
      }
    }

    // Data source is not available
    throw new InternalServerErrorException('Datasource is not available');
  }

  /**
   * Rollback the last database migration (down)
   *
   * Reverts the most recently applied migration. This is a destructive
   * operation that should be used with extreme caution, typically only
   * in development or for emergency rollbacks.
   *
   * WARNING: This can cause data loss if the migration involved
   * data manipulation or irreversible schema changes.
   *
   * @returns Success message string
   * @throws InternalServerErrorException if data source is unavailable
   * @throws TypeORM errors if rollback fails
   *
   * @note Consider implementing additional safeguards:
   *       - Backup creation before rollback
   *       - Confirmation requirements
   *       - Environment restrictions (never in production)
   */
  async migrateDown(): Promise<string> {
    // Validate data source is available
    if (this.dataSource) {
      try {
        // Revert the last migration
        await this.dataSource.undoLastMigration();

        // Log success
        console.log(`Migration down executed successfully`);

        return 'migrateDown successfully';
      } catch (error) {
        // Log detailed error information
        console.error('Migration down failed:', error);

        // Re-throw with more context
        throw new InternalServerErrorException(
          `Migration rollback failed: ${error.message}`,
        );
      }
    }

    // Data source is not available
    throw new InternalServerErrorException('Datasource is not available');
  }

  /**
   * Enhanced methods that could be added:
   *
   * async getMigrationStatus(): Promise<MigrationStatus> {
   *   // Return information about applied and pending migrations
   *   const executedMigrations = await this.dataSource.showMigrations();
   *   const pendingMigrations = await this.dataSource.showMigrations();
   *   return { executedMigrations, pendingMigrations };
   * }
   *
   * async migrateTo(targetMigration: string): Promise<string> {
   *   // Migrate to a specific version
   *   await this.dataSource.runMigrations({ transaction: 'all' });
   *   return `Migrated to ${targetMigration}`;
   * }
   *
   * async createMigration(name: string): Promise<string> {
   *   // Generate a new migration file
   *   const timestamp = new Date().getTime();
   *   const fileName = `${timestamp}-${name}.ts`;
   *   // ... create migration file logic
   *   return `Created migration: ${fileName}`;
   * }
   */
}
