"use server";

import AdmZip from "adm-zip";
import { join } from "path";
import { existsSync } from "fs";
import { mkdir, writeFile, readdir, stat } from "fs/promises";
import { format } from "date-fns-jalali";
import { prisma } from "@/lib/prisma";
import { exec } from "child_process";
import { promisify } from "util";

const execAsync = promisify(exec);

export async function createFullBackup() {
  try {
    const zip = new AdmZip();

    // 1. Pack SQLite Database alongside its Write-Ahead-Log
    let dbPath = join(process.cwd(), "prisma", "dev.db");
    
    // In production, the SQLite DB is passed via DATABASE_URL and resides in AppData
    if (process.env.DATABASE_URL && process.env.DATABASE_URL.startsWith("file:")) {
        dbPath = process.env.DATABASE_URL.replace("file:", "");
    }

    const walPath = dbPath + "-wal";
    const shmPath = dbPath + "-shm";

    if (existsSync(dbPath)) zip.addLocalFile(dbPath, "prisma");
    if (existsSync(walPath)) zip.addLocalFile(walPath, "prisma");
    if (existsSync(shmPath)) zip.addLocalFile(shmPath, "prisma");

    // 2. Pack Uploaded Assets
    const uploadsPath = join(process.cwd(), "public", "uploads");
    if (existsSync(uploadsPath)) {
      zip.addLocalFolder(uploadsPath, "public/uploads");
    }

    // 3. Output to local Backup Vault
    const backupDir = join(process.cwd(), "public", "backups");
    if (!existsSync(backupDir)) {
      await mkdir(backupDir, { recursive: true });
    }

    const timestamp = format(new Date(), "yyyy-MM-dd_HH-mm");
    const filename = `tukan_backup_${timestamp}.zip`;
    const outputPath = join(backupDir, filename);

    await writeFile(outputPath, zip.toBuffer());

    return { success: true, url: `/backups/${filename}` };
  } catch (error: any) {
    console.error("Backup creation failed:", error);
    return { success: false, error: error.message };
  }
}

export async function restoreFromBackup(formData: FormData) {
  try {
    const file = formData.get("file") as File;
    if (!file) {
      return { success: false, error: "فایل پشتیبان بارگذاری نشده است." };
    }

    const buffer = Buffer.from(await file.arrayBuffer());
    const zip = new AdmZip(buffer);

    // Determine database directory
    let dbDir = join(process.cwd(), "prisma");
    if (process.env.DATABASE_URL && process.env.DATABASE_URL.startsWith("file:")) {
      const dbPath = process.env.DATABASE_URL.replace("file:", "");
      dbDir = require("path").dirname(dbPath);
    }

    // Disconnect Prisma to release OS file handles (critical on Windows)
    await prisma.$disconnect();

    // Wait for Windows to release SQLite file locks
    await new Promise(resolve => setTimeout(resolve, 600));

    // Extract entries manually using getData() + writeFile
    // NOTE: zip.extractEntryTo() silently fails on Windows when SQLite files are locked.
    const zipEntries = zip.getEntries();
    for (const entry of zipEntries) {
      if (entry.isDirectory) continue;

      if (entry.entryName.startsWith("prisma/")) {
        // Flatten the "prisma/" prefix and write directly to dbDir
        const fileName = entry.entryName.replace("prisma/", "");
        if (!fileName) continue;
        const targetPath = join(dbDir, fileName);
        console.log(`[Restore] Writing DB file: ${targetPath}`);
        await writeFile(targetPath, entry.getData());
      } else {
        // Uploads and other public assets — maintain folder structure under cwd
        const targetPath = join(process.cwd(), entry.entryName);
        const targetDir = require("path").dirname(targetPath);
        if (!existsSync(targetDir)) {
          await mkdir(targetDir, { recursive: true });
        }
        await writeFile(targetPath, entry.getData());
      }
    }

    // Run prisma db push to sync schema for newer tables
    try {
      console.log("Running Prisma DB Push to update restored database schema...");
      await execAsync("npx prisma db push --skip-generate", { cwd: process.cwd() });
    } catch (pushErr) {
      console.error("Prisma push warning after restore:", pushErr);
    }

    return { success: true };
  } catch (error: any) {
    console.error("Restore failed:", error);
    return { success: false, error: error.message };
  }
}

export async function getBackupsList() {
  try {
    const backupDir = join(process.cwd(), "public", "backups");
    if (!existsSync(backupDir)) {
      return { success: true, backups: [] };
    }
    const files = await readdir(backupDir);
    const backups = [];
    for (const file of files) {
      if (file.endsWith(".zip")) {
        const stats = await stat(join(backupDir, file));
        backups.push({
          filename: file,
          url: `/backups/${file}`,
          size: (stats.size / 1024 / 1024).toFixed(2) + " MB",
          date: stats.mtime
        });
      }
    }
    // Sort newest first
    backups.sort((a, b) => b.date.getTime() - a.date.getTime());
    return { success: true, backups };
  } catch (error: any) {
    return { success: false, error: error.message };
  }
}
