/**
 * 查看本地迁移文件与数据库 schema_migrations 的对齐状态。
 *
 * 用法：
 *   npm run db:migrate:status
 */
import fs from 'node:fs'
import path from 'node:path'
import process from 'node:process'
import { fileURLToPath } from 'node:url'

import { closeDb, query } from '../src/db/client.js'

const CURRENT_DIR = path.dirname(fileURLToPath(import.meta.url))
const MIGRATIONS_DIR = path.join(CURRENT_DIR, '../src/db/migrations')
const MIGRATION_FILE_PATTERN = /^(\d{3})_.+\.sql$/i

function listLocalMigrations(): string[] {
  if (!fs.existsSync(MIGRATIONS_DIR)) {
    return []
  }

  return fs
    .readdirSync(MIGRATIONS_DIR)
    .filter((name) => MIGRATION_FILE_PATTERN.test(name))
    .sort((a, b) => a.localeCompare(b, 'en'))
}

function normalizeMigrationName(value: unknown): string {
  const raw = String(value || '').trim()
  if (!raw) {
    return ''
  }
  return raw.replace(/\.sql$/i, '')
}

async function main() {
  const localFiles = listLocalMigrations()
  const localNames = localFiles.map((file) => file.replace(/\.sql$/i, ''))

  let appliedNames = new Set<string>()
  try {
    const result = await query<{
      name: string | null
      filename: string | null
      run_on: string | null
    }>(
      `
        SELECT name, filename, run_on
        FROM schema_migrations
        ORDER BY COALESCE(filename, name), id
      `,
    )

    appliedNames = new Set(
      result.rows.map((row) => normalizeMigrationName(row.filename || row.name)).filter(Boolean),
    )
  } catch (error) {
    const message = error instanceof Error ? error.message : String(error)
    if (/schema_migrations/i.test(message) && /does not exist|不存在/i.test(message)) {
      console.warn('[db:migrate:status] schema_migrations 尚不存在，视为尚未应用任何迁移')
    } else {
      throw error
    }
  }

  const pending = localNames.filter((name) => !appliedNames.has(name))
  const orphaned = [...appliedNames].filter((name) => !localNames.includes(name))

  console.info('[db:migrate:status] 本地迁移文件')
  if (localFiles.length === 0) {
    console.info('  (无)')
  } else {
    for (const file of localFiles) {
      const name = file.replace(/\.sql$/i, '')
      const mark = appliedNames.has(name) ? 'applied' : 'pending'
      console.info(`  [${mark}] ${file}`)
    }
  }

  console.info(`[db:migrate:status] 已应用 ${appliedNames.size} 个，待应用 ${pending.length} 个`)
  if (pending.length > 0) {
    console.info('[db:migrate:status] 待应用:')
    for (const name of pending) {
      console.info(`  - ${name}.sql`)
    }
  }

  if (orphaned.length > 0) {
    console.warn('[db:migrate:status] 数据库中存在本地没有的迁移记录（可能是旧环境残留）:')
    for (const name of orphaned) {
      console.warn(`  - ${name}`)
    }
  }
}

main()
  .catch((error) => {
    console.error(error)
    process.exitCode = 1
  })
  .finally(async () => {
    await closeDb()
  })
