'use strict';

const fs = require('fs');
const path = require('path');
const { v4: uuidv4 } = require('uuid');
const archiver = require('archiver');

const DEPLOYMENTS_PATH = path.join(__dirname, '..', 'data', 'deployments.json');
const BACKUPS_DIR = path.join(__dirname, '..', 'backups');

function readDeployments() {
  try {
    return JSON.parse(fs.readFileSync(DEPLOYMENTS_PATH, 'utf8'));
  } catch {
    return [];
  }
}

function writeDeployments(data) {
  fs.writeFileSync(DEPLOYMENTS_PATH, JSON.stringify(data, null, 2));
}

function getAll() {
  return readDeployments();
}

function getBySite(siteId) {
  return readDeployments()
    .filter(d => d.siteId === siteId)
    .sort((a, b) => new Date(b.deployedAt) - new Date(a.deployedAt));
}

function getById(id) {
  return readDeployments().find(d => d.id === id) || null;
}

/**
 * Create a versioned backup of the site's current physical directory.
 * Returns the backup path.
 */
async function createBackup(siteId, siteName, physicalPath, version) {
  const ts = new Date().toISOString().replace(/[:.]/g, '-');
  const backupName = `${siteName}_${version}_${ts}`;
  const backupPath = path.join(BACKUPS_DIR, siteId, backupName);

  fs.mkdirSync(backupPath, { recursive: true });

  await new Promise((resolve, reject) => {
    const output = fs.createWriteStream(backupPath + '.zip');
    const archive = archiver('zip', { zlib: { level: 6 } });
    output.on('close', resolve);
    archive.on('error', reject);
    archive.pipe(output);
    if (fs.existsSync(physicalPath)) {
      archive.directory(physicalPath, false);
    }
    archive.finalize();
  });

  return backupPath + '.zip';
}

/**
 * Record a deployment in the history.
 */
function recordDeployment({ siteId, siteName, version, notes, status, backupPath, isRollback, rolledBackFrom }) {
  const deployments = readDeployments();
  const entry = {
    id: uuidv4(),
    siteId,
    siteName,
    version,
    notes: notes || '',
    deployedAt: new Date().toISOString(),
    status,           // 'success' | 'failed' | 'in-progress'
    backupPath: backupPath || null,
    isRollback: !!isRollback,
    rolledBackFrom: rolledBackFrom || null,
  };
  deployments.unshift(entry);
  writeDeployments(deployments);
  return entry;
}

function updateDeploymentStatus(id, status, extra = {}) {
  const deployments = readDeployments();
  const idx = deployments.findIndex(d => d.id === id);
  if (idx !== -1) {
    deployments[idx] = { ...deployments[idx], status, ...extra };
    writeDeployments(deployments);
    return deployments[idx];
  }
  return null;
}

/**
 * Prune old backups for a site beyond maxVersions.
 */
function pruneOldVersions(siteId, maxVersions = 10) {
  const deployments = readDeployments();
  const siteDeps = deployments
    .filter(d => d.siteId === siteId && d.status === 'success' && d.backupPath)
    .sort((a, b) => new Date(b.deployedAt) - new Date(a.deployedAt));

  const toDelete = siteDeps.slice(maxVersions);
  toDelete.forEach(d => {
    try {
      if (d.backupPath && fs.existsSync(d.backupPath)) {
        fs.unlinkSync(d.backupPath);
      }
    } catch { /* ignore */ }
  });
}

module.exports = {
  getAll,
  getBySite,
  getById,
  createBackup,
  recordDeployment,
  updateDeploymentStatus,
  pruneOldVersions,
};
