import mongoose from 'mongoose';
import Product from '../models/Product.js';
import Sale from '../models/Sale.js';
import Purchase from '../models/Purchase.js';
import StockHistory from '../models/StockHistory.js';
import StoreSettings from '../models/StoreSettings.js';
import Admin from '../models/Admin.js';
import SaleReturn from '../models/SaleReturn.js';
import AuditLog from '../models/AuditLog.js';
import logAudit from '../utils/audit.js';

const BACKUP_VERSION = 1;

const COLLECTIONS = [
  { key: 'products', model: Product },
  { key: 'sales', model: Sale },
  { key: 'returns', model: SaleReturn },
  { key: 'purchases', model: Purchase },
  { key: 'stockHistory', model: StockHistory },
  { key: 'settings', model: StoreSettings },
  { key: 'auditLogs', model: AuditLog },
];

const createBackup = async (req) => {
  const data = {};
  const counts = {};

  for (const { key, model } of COLLECTIONS) {
    const docs = await model.find({}).lean();
    data[key] = docs;
    counts[key] = docs.length;
  }

  // Users are exported WITHOUT password hashes and are never restored.
  const admins = await Admin.find({}).select('name email role').lean();
  data.admins = admins;
  counts.admins = admins.length;

  logAudit(req, 'BACKUP_CREATED', 'backup', '', { counts });

  return {
    meta: {
      app: 'StorePro',
      version: BACKUP_VERSION,
      exportedAt: new Date().toISOString(),
      counts,
    },
    data,
  };
};

const validateBackupPayload = (payload) => {
  if (!payload || typeof payload !== 'object') {
    throw Object.assign(new Error('Invalid backup file'), { statusCode: 400 });
  }
  const { meta, data } = payload;
  if (!meta || meta.app !== 'StorePro' || meta.version !== BACKUP_VERSION) {
    throw Object.assign(
      new Error('Unsupported backup file: missing or incompatible metadata'),
      { statusCode: 400 }
    );
  }
  if (!data || typeof data !== 'object') {
    throw Object.assign(new Error('Backup file contains no data'), { statusCode: 400 });
  }

  const counts = {};
  for (const { key } of COLLECTIONS) {
    if (!Array.isArray(data[key])) {
      throw Object.assign(
        new Error(`Backup file is corrupted: missing "${key}" collection`),
        { statusCode: 400 }
      );
    }
    counts[key] = data[key].length;
  }
  return { meta, counts };
};

const restoreBackup = async (payload, req) => {
  const { meta, counts } = validateBackupPayload(payload);

  const session = await mongoose.startSession();
  session.startTransaction();

  try {
    for (const { key, model } of COLLECTIONS) {
      await model.deleteMany({}, { session });
      const docs = payload.data[key];
      if (docs.length > 0) {
        await model.insertMany(docs, { session });
      }
    }
    // Admins are intentionally NOT restored so current logins keep working.
    await session.commitTransaction();
  } catch (error) {
    await session.abortTransaction();
    if (error.name === 'ValidationError' || error.name === 'CastError') {
      throw Object.assign(
        new Error(`Backup data failed validation: ${error.message}`),
        { statusCode: 400 }
      );
    }
    throw error;
  } finally {
    session.endSession();
  }

  logAudit(req, 'RESTORE_PERFORMED', 'backup', '', {
    backupDate: meta.exportedAt,
    counts,
  });

  return { restoredFrom: meta.exportedAt, counts };
};

export default { createBackup, restoreBackup, validateBackupPayload };
