import { DataSource } from "typeorm"
import { config as dotenvConfig } from "dotenv"
import * as process from "node:process"
import { randomInt } from "crypto"

// Load environment variables
dotenvConfig({
  path: process.env.NODE_ENV ? `.env.${process.env.NODE_ENV}` : ".env",
})

// Create DataSource connection
const AppDataSource = new DataSource({
  type: "postgres",
  host: process.env.DATABASE_HOST,
  port: parseInt(process.env.DATABASE_PORT || "5432", 10),
  username: process.env.DATABASE_USERNAME,
  password: process.env.DATABASE_PASSWORD,
  database: process.env.DATABASE_NAME,
  entities: ["src/**/*.entity{.ts,.js}"],
  synchronize: false,
  logging: true,
})

/**
 * Convert 6-digit OTP to 4-digit
 * - Takes first 4 digits if OTP is 6-digit
 * - Returns same OTP if already valid 4-digit
 * - Generates new 4-digit OTP if null/invalid
 */
const convertTo4DigitOtp = (
  otp: string | number | null | undefined,
): number => {
  const otpString = otp ? otp.toString() : null

  // Generate new OTP if empty/null
  if (!otpString || otpString.length === 0) {
    return randomInt(1000, 10000)
  }

  // Convert 6-digit → 4-digit
  if (otpString.length === 6) {
    return parseInt(otpString.substring(0, 4), 10)
  }

  // Already 4-digit
  if (otpString.length === 4) {
    const parsed = parseInt(otpString, 10)
    if (!isNaN(parsed) && parsed >= 1000 && parsed <= 9999) {
      return parsed
    }
  }

  // Fallback: generate new
  return randomInt(1000, 10000)
}

/**
 * Main script
 */
const convertTripOtps = async (): Promise<void> => {
  try {
    console.log("🔄 Starting Trip OTP conversion script...")
    console.log("Connecting to database...")

    await AppDataSource.initialize()
    console.log("✅ Database connected successfully")

    const queryRunner = AppDataSource.createQueryRunner()
    await queryRunner.connect()

    try {
      const trips = await queryRunner.query(`
        SELECT id, trip_otp, is_trip_otp_required
        FROM trips
        WHERE (trip_otp IS NULL OR LENGTH(trip_otp) = 6)
          AND (is_trip_otp_required IS NULL OR is_trip_otp_required = true)
        ORDER BY id
      `)

      console.log(`📊 Found ${trips.length} trips to process`)

      if (trips.length === 0) {
        console.log("✅ No trips need conversion.")
        return
      }

      let updatedCount = 0
      let errorCount = 0
      const batchSize = 100

      for (let i = 0; i < trips.length; i += batchSize) {
        const batch = trips.slice(i, i + batchSize)

        for (const trip of batch) {
          try {
            if (trip.is_trip_otp_required === false) {
              continue
            }

            const newOtp = convertTo4DigitOtp(trip.trip_otp)

            await queryRunner.query(
              `UPDATE trips SET trip_otp = $1 WHERE id = $2`,
              [newOtp, trip.id],
            )

            updatedCount++

            if (updatedCount % 50 === 0) {
              console.log(
                `⏳ Processed ${updatedCount}/${trips.length} trips...`,
              )
            }
          } catch (error) {
            errorCount++
            console.error(
              `❌ Error updating trip ID ${trip.id}:`,
              error instanceof Error ? error.message : error,
            )
          }
        }
      }

      console.log("\n" + "=".repeat(50))
      console.log("📈 Conversion Summary")
      console.log(`   Total trips found : ${trips.length}`)
      console.log(`   ✅ Updated        : ${updatedCount}`)
      console.log(`   ❌ Errors         : ${errorCount}`)
      console.log("=".repeat(50))
      console.log("✅ Trip OTP conversion completed!")
    } finally {
      await queryRunner.release()
    }
  } catch (error) {
    console.error("❌ Fatal error during OTP conversion:", error)
    throw error
  } finally {
    if (AppDataSource.isInitialized) {
      await AppDataSource.destroy()
      console.log("🔌 Database connection closed")
    }
  }
}

// Execute script
convertTripOtps()
  .then(() => {
    console.log("🎉 Script execution completed successfully")
    process.exit(0)
  })
  .catch((error) => {
    console.error("💥 Script execution failed:", error)
    process.exit(1)
  })
