/**
 * Data Migration: Directus → Custom Backend
 *
 * Migrates data from Directus tables to the new schema.
 * Run with: tsx src/scripts/data-migration.ts
 *
 * Environment variables:
 *   DATABASE_URL        - PostgreSQL connection (same DB)
 *   OLD_UPLOAD_DIR      - Path to Directus uploads (e.g. /old-uploads)
 *   NEW_UPLOAD_DIR      - Path to new upload dir (e.g. /data/uploads)
 */

import { Pool } from "pg";
import fs from "fs";
import path from "path";

const DATABASE_URL = process.env.DATABASE_URL || "postgresql://sexy:sexy@localhost:5432/sexy";
const OLD_UPLOAD_DIR = process.env.OLD_UPLOAD_DIR || "/old-uploads";
const NEW_UPLOAD_DIR = process.env.NEW_UPLOAD_DIR || "/data/uploads";

const pool = new Pool({ connectionString: DATABASE_URL });

async function query(sql: string, params: unknown[] = []) {
  const client = await pool.connect();
  try {
    return await client.query(sql, params);
  } finally {
    client.release();
  }
}

function copyFile(src: string, dest: string) {
  const dir = path.dirname(dest);
  if (!fs.existsSync(dir)) {
    fs.mkdirSync(dir, { recursive: true });
  }
  if (fs.existsSync(src)) {
    fs.copyFileSync(src, dest);
    return true;
  }
  return false;
}

async function migrateFiles() {
  console.log("📁 Migrating files...");
  const { rows } = await query(
    `SELECT id, title, description, filename_disk, type, filesize, duration, uploaded_by, uploaded_on as date_created
     FROM directus_files`,
  );

  let migrated = 0;
  let skipped = 0;

  for (const file of rows) {
    // Check if already migrated
    const existing = await query("SELECT id FROM files WHERE id = $1", [file.id]);
    if (existing.rows.length > 0) {
      skipped++;
      continue;
    }

    await query(
      `INSERT INTO files (id, title, description, filename, mime_type, filesize, duration, uploaded_by, date_created)
       VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
       ON CONFLICT (id) DO NOTHING`,
      [
        file.id,
        file.title,
        file.description,
        file.filename_disk || `${file.id}`,
        file.type,
        file.filesize,
        file.duration,
        file.uploaded_by,
        file.date_created,
      ],
    );

    // Copy file to new location
    const srcPath = path.join(OLD_UPLOAD_DIR, file.filename_disk || "");
    const destPath = path.join(NEW_UPLOAD_DIR, file.id, file.filename_disk || `${file.id}`);
    const copied = copyFile(srcPath, destPath);

    if (!copied) {
      console.warn(`  ⚠️  File not found on disk: ${file.filename_disk}`);
    }

    migrated++;
  }

  console.log(`  ✅ Files: ${migrated} migrated, ${skipped} already existed`);
}

async function migrateUsers() {
  console.log("👥 Migrating users...");
  const { rows } = await query(
    `SELECT u.id, u.email, u.password, u.first_name, u.last_name,
            u.description, u.avatar, u.join_date as date_created,
            u.artist_name, u.slug,
            r.name as role_name
     FROM directus_users u
     LEFT JOIN directus_roles r ON u.role = r.id
     WHERE u.status = 'active'`,
  );

  let migrated = 0;

  for (const user of rows) {
    const existing = await query("SELECT id FROM users WHERE id = $1", [user.id]);
    if (existing.rows.length > 0) {
      migrated++;
      continue;
    }

    const role =
      user.role_name === "Model"
        ? "model"
        : user.role_name === "Administrator"
          ? "admin"
          : "viewer";

    // Fetch tags from custom user fields if they exist
    let tags: string[] = [];
    try {
      const tagsRes = await query("SELECT tags FROM directus_users WHERE id = $1", [user.id]);
      if (tagsRes.rows[0]?.tags) {
        tags = Array.isArray(tagsRes.rows[0].tags)
          ? tagsRes.rows[0].tags
          : JSON.parse(String(tagsRes.rows[0].tags || "[]"));
      }
    } catch {
      /* tags column may not exist on older Directus installs */
    }

    await query(
      `INSERT INTO users (id, email, password_hash, first_name, last_name, artist_name, slug,
                          description, tags, role, avatar, email_verified, date_created)
       VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)
       ON CONFLICT (id) DO NOTHING`,
      [
        user.id,
        user.email,
        user.password || "MIGRATED_NO_PASSWORD",
        user.first_name,
        user.last_name,
        user.artist_name,
        user.slug,
        user.description,
        tags,
        role,
        user.avatar,
        true,
        user.date_created,
      ],
    );
    migrated++;
  }

  console.log(`  ✅ Users: ${migrated} migrated`);
}

async function migrateUserPhotos() {
  console.log("🖼️  Migrating user photos...");
  const { rows } = await query(
    `SELECT directus_users_id as user_id, directus_files_id as file_id
     FROM junction_directus_users_files`,
  );

  let migrated = 0;
  for (const row of rows) {
    const userExists = await query("SELECT id FROM users WHERE id = $1", [row.user_id]);
    const fileExists = await query("SELECT id FROM files WHERE id = $1", [row.file_id]);
    if (!userExists.rows.length || !fileExists.rows.length) continue;

    await query(
      `INSERT INTO user_photos (user_id, file_id, sort) VALUES ($1, $2, $3)
       ON CONFLICT DO NOTHING`,
      [row.user_id, row.file_id, 0],
    );
    migrated++;
  }

  console.log(`  ✅ User photos: ${migrated} migrated`);
}

async function migrateArticles() {
  console.log("📰 Migrating articles...");
  const { rows } = await query(
    `SELECT id, slug, title, excerpt, content, image, tags, publish_date,
            author, category, featured, date_created, date_updated
     FROM sexy_articles`,
  );

  let migrated = 0;
  for (const article of rows) {
    await query(
      `INSERT INTO articles (id, slug, title, excerpt, content, image, tags, publish_date,
                             author, category, featured, date_created, date_updated)
       VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)
       ON CONFLICT (id) DO NOTHING`,
      [
        article.id,
        article.slug,
        article.title,
        article.excerpt,
        article.content,
        article.image,
        Array.isArray(article.tags) ? article.tags : JSON.parse(String(article.tags || "[]")),
        article.publish_date,
        article.author,
        article.category,
        article.featured,
        article.date_created,
        article.date_updated,
      ],
    );
    migrated++;
  }

  console.log(`  ✅ Articles: ${migrated} migrated`);
}

async function migrateVideos() {
  console.log("🎬 Migrating videos...");
  const { rows } = await query(
    `SELECT id, slug, title, description, image, movie, tags, upload_date,
            premium, featured
     FROM sexy_videos`,
  );

  let migrated = 0;
  for (const video of rows) {
    await query(
      `INSERT INTO videos (id, slug, title, description, image, movie, tags, upload_date,
                           premium, featured, likes_count, plays_count)
       VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)
       ON CONFLICT (id) DO NOTHING`,
      [
        video.id,
        video.slug,
        video.title,
        video.description,
        video.image,
        video.movie,
        Array.isArray(video.tags) ? video.tags : JSON.parse(String(video.tags || "[]")),
        video.upload_date,
        video.premium,
        video.featured,
        0,
        0,
      ],
    );
    migrated++;
  }

  console.log(`  ✅ Videos: ${migrated} migrated`);
}

async function migrateVideoModels() {
  console.log("🔗 Migrating video models...");
  const { rows } = await query(
    `SELECT sexy_videos_id as video_id, directus_users_id as user_id
     FROM sexy_videos_models`,
  );

  let migrated = 0;
  for (const row of rows) {
    const videoExists = await query("SELECT id FROM videos WHERE id = $1", [row.video_id]);
    const userExists = await query("SELECT id FROM users WHERE id = $1", [row.user_id]);
    if (!videoExists.rows.length || !userExists.rows.length) continue;

    await query(
      `INSERT INTO video_models (video_id, user_id) VALUES ($1, $2) ON CONFLICT DO NOTHING`,
      [row.video_id, row.user_id],
    );
    migrated++;
  }

  console.log(`  ✅ Video models: ${migrated} migrated`);
}

async function migrateVideoLikes() {
  console.log("❤️  Migrating video likes...");
  const { rows } = await query(`SELECT id, video_id, user_id, date_created FROM sexy_video_likes`);

  let migrated = 0;
  for (const row of rows) {
    await query(
      `INSERT INTO video_likes (id, video_id, user_id, date_created) VALUES ($1, $2, $3, $4)
       ON CONFLICT (id) DO NOTHING`,
      [row.id, row.video_id, row.user_id, row.date_created],
    );
    migrated++;
  }

  console.log(`  ✅ Video likes: ${migrated} migrated`);
}

async function migrateVideoPlays() {
  console.log("▶️  Migrating video plays...");
  const { rows } = await query(
    `SELECT id, video_id, user_id, session_id, duration_watched, completed, date_created
     FROM sexy_video_plays`,
  );

  let migrated = 0;
  for (const row of rows) {
    await query(
      `INSERT INTO video_plays (id, video_id, user_id, session_id, duration_watched, completed, date_created)
       VALUES ($1, $2, $3, $4, $5, $6, $7)
       ON CONFLICT (id) DO NOTHING`,
      [
        row.id,
        row.video_id,
        row.user_id,
        row.session_id,
        row.duration_watched,
        row.completed,
        row.date_created,
      ],
    );
    migrated++;
  }

  console.log(`  ✅ Video plays: ${migrated} migrated`);
}

async function migrateRecordings() {
  console.log("🎙️  Migrating recordings...");
  const { rows } = await query(
    `SELECT id, title, description, slug, duration, events, device_info,
            user_created as user_id, status, tags, linked_video, public,
            original_recording_id, date_created, date_updated
     FROM sexy_recordings`,
  );

  let migrated = 0;
  for (const recording of rows) {
    await query(
      `INSERT INTO recordings (id, title, description, slug, duration, events, device_info,
                               user_id, status, tags, linked_video, public,
                               original_recording_id, date_created, date_updated)
       VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15)
       ON CONFLICT (id) DO NOTHING`,
      [
        recording.id,
        recording.title,
        recording.description,
        recording.slug,
        recording.duration != null ? Math.round(Number(recording.duration)) : null,
        typeof recording.events === "string" ? recording.events : JSON.stringify(recording.events),
        typeof recording.device_info === "string"
          ? recording.device_info
          : JSON.stringify(recording.device_info),
        recording.user_id,
        recording.status,
        Array.isArray(recording.tags) ? recording.tags : JSON.parse(String(recording.tags || "[]")),
        recording.linked_video,
        recording.public,
        recording.original_recording_id,
        recording.date_created,
        recording.date_updated,
      ],
    );
    migrated++;
  }

  console.log(`  ✅ Recordings: ${migrated} migrated`);
}

async function migrateRecordingPlays() {
  console.log("▶️  Migrating recording plays...");
  const { rows } = await query(
    `SELECT id, user_id, recording_id, duration_played, completed, date_created
     FROM sexy_recording_plays`,
  );

  let migrated = 0;
  for (const row of rows) {
    await query(
      `INSERT INTO recording_plays (id, recording_id, user_id, duration_played, completed, date_created)
       VALUES ($1, $2, $3, $4, $5, $6)
       ON CONFLICT (id) DO NOTHING`,
      [row.id, row.recording_id, row.user_id, row.duration_played, row.completed, row.date_created],
    );
    migrated++;
  }

  console.log(`  ✅ Recording plays: ${migrated} migrated`);
}

async function migrateComments() {
  console.log("💬 Migrating comments...");
  const { rows } = await query(
    `SELECT id, collection, item, comment, user_created as user_id, date_created
     FROM directus_comments
     WHERE collection IN ('sexy_videos', 'sexy_recordings')`,
  );

  let migrated = 0;
  for (const row of rows) {
    // Map collection names
    const collection = row.collection === "sexy_videos" ? "videos" : "recordings";

    await query(
      `INSERT INTO comments (collection, item_id, comment, user_id, date_created)
       VALUES ($1, $2, $3, $4, $5)`,
      [collection, row.item, row.comment, row.user_id, row.date_created],
    );
    migrated++;
  }

  console.log(`  ✅ Comments: ${migrated} migrated`);
}

async function migrateAchievements() {
  console.log("🏆 Migrating achievements...");
  const { rows } = await query(
    `SELECT id, code, name, description, icon, category, required_count, points_reward, status, sort
     FROM sexy_achievements`,
  );

  let migrated = 0;
  for (const row of rows) {
    await query(
      `INSERT INTO achievements (id, code, name, description, icon, category, required_count, points_reward, status, sort)
       VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
       ON CONFLICT (id) DO NOTHING`,
      [
        row.id,
        row.code,
        row.name,
        row.description,
        row.icon,
        row.category,
        row.required_count,
        row.points_reward,
        row.status,
        row.sort,
      ],
    );
    migrated++;
  }

  console.log(`  ✅ Achievements: ${migrated} migrated`);
}

async function migrateUserAchievements() {
  console.log("🎖️  Migrating user achievements...");
  const { rows } = await query(
    `SELECT user_id, achievement_id, progress, date_unlocked FROM sexy_user_achievements`,
  );

  let migrated = 0;
  for (const row of rows) {
    const userExists = await query("SELECT id FROM users WHERE id = $1", [row.user_id]);
    const achievementExists = await query("SELECT id FROM achievements WHERE id = $1", [
      row.achievement_id,
    ]);
    if (!userExists.rows.length || !achievementExists.rows.length) continue;

    await query(
      `INSERT INTO user_achievements (user_id, achievement_id, progress, date_unlocked)
       VALUES ($1, $2, $3, $4)
       ON CONFLICT (user_id, achievement_id) DO NOTHING`,
      [row.user_id, row.achievement_id, row.progress, row.date_unlocked],
    );
    migrated++;
  }

  console.log(`  ✅ User achievements: ${migrated} migrated`);
}

async function migrateUserPoints() {
  console.log("💎 Migrating user points...");
  const { rows } = await query(
    `SELECT user_id, action, points, recording_id, date_created FROM sexy_user_points`,
  );

  let migrated = 0;
  for (const row of rows) {
    const userExists = await query("SELECT id FROM users WHERE id = $1", [row.user_id]);
    if (!userExists.rows.length) continue;

    await query(
      `INSERT INTO user_points (user_id, action, points, recording_id, date_created)
       VALUES ($1, $2, $3, $4, $5)`,
      [row.user_id, row.action, row.points, row.recording_id, row.date_created],
    );
    migrated++;
  }

  console.log(`  ✅ User points: ${migrated} migrated`);
}

async function migrateUserStats() {
  console.log("📊 Migrating user stats...");
  const { rows } = await query(
    `SELECT user_id, total_raw_points, total_weighted_points, recordings_count,
            playbacks_count, comments_count, achievements_count, last_updated
     FROM sexy_user_stats`,
  );

  let migrated = 0;
  for (const row of rows) {
    const userExists = await query("SELECT id FROM users WHERE id = $1", [row.user_id]);
    if (!userExists.rows.length) continue;

    await query(
      `INSERT INTO user_stats (user_id, total_raw_points, total_weighted_points, recordings_count,
                               playbacks_count, comments_count, achievements_count, last_updated)
       VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
       ON CONFLICT (user_id) DO NOTHING`,
      [
        row.user_id,
        row.total_raw_points,
        row.total_weighted_points,
        row.recordings_count,
        row.playbacks_count,
        row.comments_count,
        row.achievements_count,
        row.last_updated,
      ],
    );
    migrated++;
  }

  console.log(`  ✅ User stats: ${migrated} migrated`);
}

async function main() {
  console.log("🚀 Starting data migration from Directus to custom backend...\n");

  try {
    // Verify connection
    await query("SELECT 1");
    console.log("✅ Database connected\n");

    // Migration order respects FK dependencies
    await migrateFiles();
    await migrateUsers();
    await migrateUserPhotos();
    await migrateArticles();
    await migrateVideos();
    await migrateVideoModels();
    await migrateVideoLikes();
    await migrateVideoPlays();
    await migrateRecordings();
    await migrateRecordingPlays();
    await migrateComments();
    await migrateAchievements();
    await migrateUserAchievements();
    await migrateUserPoints();
    await migrateUserStats();

    console.log("\n🎉 Migration complete!");
  } catch (error) {
    console.error("❌ Migration failed:", error);
    process.exit(1);
  } finally {
    await pool.end();
  }
}

main();
