import path from "node:path";
import Database from "better-sqlite3";
import { createChildLogger } from "../src/logger";
import * as postgres from "../src/database/postgres";

const logger = createChildLogger("migrate-data");

interface MuxerJob {
  id: string;
  data: string;
  status: string;
  attempts: number;
  maxAttempts: number;
  createdAt: number;
  updatedAt: number;
  error?: string;
}

interface Message {
  id: string;
  guild_id: string;
  channel_id: string;
  thread_id?: string;
  user_id: string;
  username: string;
  avatar_url?: string;
  content: string;
  edited_content?: string;
  created_at: number;
  edited_at?: number;
  deleted_at?: number;
  type: string;
  metadata?: string;
  ai_status: string;
  ai_moderation_flags?: string;
  ai_moderation_score?: number;
  ai_moderation_raw?: string;
  ai_analysis?: string;
  ai_analyzed_at?: number;
  ai_error?: string;
}

interface Attachment {
  id: string;
  message_id: string;
  guild_id: string;
  channel_id: string;
  thread_id?: string;
  user_id: string;
  filename: string;
  size: number;
  type: string;
  discord_url: string;
  uploaded_url?: string;
  upload_status: string;
  upload_error?: string;
  created_at: number;
  uploaded_at?: number;
}

interface UiState {
  key: string;
  value: string;
  updated_at: number;
}

async function migrateData(): Promise<void> {
  let sqliteDb: Database.Database | null = null;

  try {
    logger.info("Starting data migration from SQLite to PostgreSQL");

    // Open SQLite database
    const dbPath = path.join(process.cwd(), ".muxer-queue.db");
    sqliteDb = new Database(dbPath);
    logger.info({ dbPath }, "SQLite database opened");

    // Initialize PostgreSQL pool
    const pool = postgres.getPool();
    logger.info("PostgreSQL connection pool initialized");

    // Migrate muxer_jobs table
    logger.info("Migrating muxer_jobs table...");
    const muxerJobsStmt = sqliteDb.prepare("SELECT * FROM muxer_jobs");
    const muxerJobs = muxerJobsStmt.all() as MuxerJob[];

    for (const job of muxerJobs) {
      await postgres.query(
        `INSERT INTO muxer_jobs (id, data, status, attempts, maxAttempts, createdAt, updatedAt, error)
         VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
         ON CONFLICT (id) DO NOTHING`,
        [
          job.id,
          job.data,
          job.status,
          job.attempts,
          job.maxAttempts,
          job.createdAt,
          job.updatedAt,
          job.error || null,
        ],
      );
    }
    logger.info({ count: muxerJobs.length }, "Migrated muxer_jobs");

    // Migrate messages table
    logger.info("Migrating messages table...");
    const messagesStmt = sqliteDb.prepare("SELECT * FROM messages");
    const messages = messagesStmt.all() as Message[];

    for (const msg of messages) {
      await postgres.query(
        `INSERT INTO messages (
          id, guild_id, channel_id, thread_id, user_id, username, avatar_url,
          content, edited_content, created_at, edited_at, deleted_at, type,
          metadata, ai_status, ai_moderation_flags, ai_moderation_score,
          ai_moderation_raw, ai_analysis, ai_analyzed_at, ai_error
        ) VALUES (
          $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15,
          $16, $17, $18, $19, $20, $21
        )
        ON CONFLICT (id) DO NOTHING`,
        [
          msg.id,
          msg.guild_id,
          msg.channel_id,
          msg.thread_id || null,
          msg.user_id,
          msg.username,
          msg.avatar_url || null,
          msg.content,
          msg.edited_content || null,
          msg.created_at,
          msg.edited_at || null,
          msg.deleted_at || null,
          msg.type,
          msg.metadata || null,
          msg.ai_status,
          msg.ai_moderation_flags || null,
          msg.ai_moderation_score || null,
          msg.ai_moderation_raw || null,
          msg.ai_analysis || null,
          msg.ai_analyzed_at || null,
          msg.ai_error || null,
        ],
      );
    }
    logger.info({ count: messages.length }, "Migrated messages");

    // Migrate attachments table
    logger.info("Migrating attachments table...");
    const attachmentsStmt = sqliteDb.prepare("SELECT * FROM attachments");
    const attachments = attachmentsStmt.all() as Attachment[];

    for (const att of attachments) {
      await postgres.query(
        `INSERT INTO attachments (
          id, message_id, guild_id, channel_id, thread_id, user_id, filename,
          size, type, discord_url, uploaded_url, upload_status, upload_error,
          created_at, uploaded_at
        ) VALUES (
          $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15
        )
        ON CONFLICT (id) DO NOTHING`,
        [
          att.id,
          att.message_id,
          att.guild_id,
          att.channel_id,
          att.thread_id || null,
          att.user_id,
          att.filename,
          att.size,
          att.type,
          att.discord_url,
          att.uploaded_url || null,
          att.upload_status,
          att.upload_error || null,
          att.created_at,
          att.uploaded_at || null,
        ],
      );
    }
    logger.info({ count: attachments.length }, "Migrated attachments");

    // Migrate ui_state table
    logger.info("Migrating ui_state table...");
    const uiStateStmt = sqliteDb.prepare("SELECT * FROM ui_state");
    const uiStates = uiStateStmt.all() as UiState[];

    for (const state of uiStates) {
      await postgres.query(
        `INSERT INTO ui_state (key, value, updated_at)
         VALUES ($1, $2, $3)
         ON CONFLICT (key) DO UPDATE SET value = excluded.value, updated_at = excluded.updated_at`,
        [state.key, state.value, state.updated_at],
      );
    }
    logger.info({ count: uiStates.length }, "Migrated ui_state");

    logger.info(
      {
        muxerJobs: muxerJobs.length,
        messages: messages.length,
        attachments: attachments.length,
        uiState: uiStates.length,
      },
      "Data migration completed successfully",
    );
  } catch (error) {
    logger.error(
      {
        error: error instanceof Error ? error.message : String(error),
        stack: error instanceof Error ? error.stack : undefined,
      },
      "Data migration failed",
    );
    process.exit(1);
  } finally {
    // Close SQLite connection
    if (sqliteDb) {
      sqliteDb.close();
      logger.info("SQLite database closed");
    }

    // Close PostgreSQL pool
    await postgres.closePool();
    logger.info("PostgreSQL connection pool closed");
  }
}

// Run migration
migrateData().catch((error) => {
  logger.error(
    {
      error: error instanceof Error ? error.message : String(error),
    },
    "Unhandled error in migration",
  );
  process.exit(1);
});
