#!/usr/bin/env node
/**
 * Script de migracao SQLite -> PostgreSQL
 * Executa com acesso ao SQLite e PostgreSQL para migrar todos os dados
 *
 * Uso:
 *   SQLITE_PATH=/path/to/db.sqlite POSTGRES_URL=postgresql://... node scripts/migrate-sqlite-to-postgres.mjs
 */

import Database from "better-sqlite3"
import pg from "pg"

const SQLITE_PATH = process.env.SQLITE_PATH || "/app/data/db.sqlite"
const POSTGRES_URL = process.env.POSTGRES_URL || process.env.DATABASE_URL

if (!POSTGRES_URL) {
  console.error("ERRO: POSTGRES_URL ou DATABASE_URL e obrigatorio")
  process.exit(1)
}

console.log("=".repeat(60))
console.log("MIGRACAO SQLite -> PostgreSQL")
console.log("=".repeat(60))
console.log(`SQLite: ${SQLITE_PATH}`)
console.log(`PostgreSQL: ${POSTGRES_URL.replace(/:[^:@]+@/, ":***@")}`)
console.log("")

// Ordem das tabelas respeitando foreign keys
const TABLES_ORDER = [
  // Tabelas sem dependencias
  "Team",
  "SlaPolicy",
  "Company",
  // Tabelas com dependencias simples
  "User",
  "Queue",
  "AuthUser",
  // Tabelas com chave composta
  "TeamMember",
  // Tabelas principais
  "Ticket",
  // Tabelas dependentes de Ticket
  "TicketEvent",
  "TicketComment",
  "TicketRating",
  "TicketAccessToken",
  // Tabelas de usuario
  "NotificationPreferences",
  // Tabelas de relatorios
  "ReportExportSchedule",
  "ReportExportRun",
  // Tabelas de autenticacao
  "AuthSession",
  "AuthAccount",
  "AuthInvite",
  "AuthInviteEvent",
  "AuthVerification",
]

let sqlite
let pgClient

async function connect() {
  console.log("[1/4] Conectando aos bancos de dados...")

  try {
    sqlite = new Database(SQLITE_PATH, { readonly: true })
    console.log("  SQLite: conectado")
  } catch (error) {
    console.error("  SQLite: ERRO -", error.message)
    process.exit(1)
  }

  try {
    pgClient = new pg.Client({ connectionString: POSTGRES_URL })
    await pgClient.connect()
    console.log("  PostgreSQL: conectado")
  } catch (error) {
    console.error("  PostgreSQL: ERRO -", error.message)
    process.exit(1)
  }
}

async function migrateTable(tableName) {
  let rows
  try {
    rows = sqlite.prepare(`SELECT * FROM "${tableName}"`).all()
  } catch (error) {
    console.log(`  ${tableName}: tabela nao existe no SQLite, pulando`)
    return { table: tableName, migrated: 0, skipped: true }
  }

  if (rows.length === 0) {
    console.log(`  ${tableName}: 0 registros`)
    return { table: tableName, migrated: 0 }
  }

  const columns = Object.keys(rows[0])
  const quotedColumns = columns.map(c => `"${c}"`).join(", ")
  const placeholders = columns.map((_, i) => `$${i + 1}`).join(", ")
  const insertSql = `INSERT INTO "${tableName}" (${quotedColumns}) VALUES (${placeholders}) ON CONFLICT DO NOTHING`

  let migrated = 0
  let errors = 0

  for (const row of rows) {
    const values = columns.map(col => {
      let val = row[col]

      // Converter JSON string para objeto se necessario (PostgreSQL usa JSONB)
      if (typeof val === "string") {
        // Detectar campos JSON pelo conteudo
        if ((val.startsWith("{") && val.endsWith("}")) || (val.startsWith("[") && val.endsWith("]"))) {
          try {
            val = JSON.parse(val)
          } catch {
            // Manter como string se nao for JSON valido
          }
        }
      }

      // SQLite usa 0/1 para boolean, PostgreSQL usa true/false
      // Prisma ja trata isso, mas vamos garantir
      if (val === 0 || val === 1) {
        // Detectar campos boolean pelo nome
        const booleanFields = ["emailVerified", "isLead", "isAvulso", "emailEnabled", "hasBranches", "privacyPolicyAccepted"]
        if (booleanFields.includes(col)) {
          val = val === 1
        }
      }

      return val
    })

    try {
      await pgClient.query(insertSql, values)
      migrated++
    } catch (error) {
      errors++
      if (errors <= 3) {
        console.error(`    Erro ao inserir em ${tableName}:`, error.message)
      }
    }
  }

  console.log(`  ${tableName}: ${migrated}/${rows.length} registros migrados${errors > 0 ? ` (${errors} erros)` : ""}`)
  return { table: tableName, migrated, total: rows.length, errors }
}

async function updateSequences() {
  console.log("\n[3/4] Atualizando sequences do PostgreSQL...")

  // PostgreSQL precisa atualizar sequences para auto-increment funcionar corretamente
  // Mas como usamos CUIDs, isso geralmente nao e necessario
  // Vamos apenas verificar se ha sequences e atualiza-las se existirem

  const sequenceQuery = `
    SELECT
      t.relname as table_name,
      a.attname as column_name,
      pg_get_serial_sequence(t.relname::text, a.attname::text) as sequence_name
    FROM pg_class t
    JOIN pg_attribute a ON a.attrelid = t.oid
    WHERE t.relkind = 'r'
    AND pg_get_serial_sequence(t.relname::text, a.attname::text) IS NOT NULL
  `

  try {
    const result = await pgClient.query(sequenceQuery)
    for (const row of result.rows) {
      const updateSeq = `
        SELECT setval('${row.sequence_name}',
          COALESCE((SELECT MAX("${row.column_name}") FROM "${row.table_name}"), 0) + 1, false)
      `
      try {
        await pgClient.query(updateSeq)
        console.log(`  Sequence ${row.sequence_name} atualizada`)
      } catch {
        // Ignorar erros de sequence
      }
    }
  } catch {
    console.log("  Nenhuma sequence encontrada (usando CUIDs)")
  }
}

async function validateMigration() {
  console.log("\n[4/4] Validando migracao...")

  const validation = []

  for (const tableName of TABLES_ORDER) {
    let sqliteCount = 0
    let pgCount = 0

    try {
      const sqliteResult = sqlite.prepare(`SELECT COUNT(*) as count FROM "${tableName}"`).get()
      sqliteCount = sqliteResult?.count || 0
    } catch {
      // Tabela nao existe no SQLite
      continue
    }

    try {
      const pgResult = await pgClient.query(`SELECT COUNT(*) as count FROM "${tableName}"`)
      pgCount = parseInt(pgResult.rows[0]?.count || 0)
    } catch {
      pgCount = 0
    }

    const match = sqliteCount === pgCount
    validation.push({ table: tableName, sqlite: sqliteCount, postgres: pgCount, match })

    const status = match ? "OK" : "DIFF"
    console.log(`  ${tableName}: SQLite=${sqliteCount}, PostgreSQL=${pgCount} [${status}]`)
  }

  const allMatch = validation.every(v => v.match)
  return allMatch
}

async function main() {
  await connect()

  console.log("\n[2/4] Migrando tabelas...")

  try {
    await pgClient.query("BEGIN")

    for (const tableName of TABLES_ORDER) {
      await migrateTable(tableName)
    }

    await pgClient.query("COMMIT")
    console.log("\n  Transacao commitada com sucesso!")

  } catch (error) {
    await pgClient.query("ROLLBACK")
    console.error("\nERRO: Rollback executado -", error.message)
    process.exit(1)
  }

  await updateSequences()

  const valid = await validateMigration()

  console.log("\n" + "=".repeat(60))
  if (valid) {
    console.log("MIGRACAO CONCLUIDA COM SUCESSO!")
  } else {
    console.log("MIGRACAO CONCLUIDA COM DIFERENCAS (verifique os logs)")
  }
  console.log("=".repeat(60))

  sqlite.close()
  await pgClient.end()

  process.exit(valid ? 0 : 1)
}

main().catch(error => {
  console.error("Erro fatal:", error)
  process.exit(1)
})
