const db = require("../../managers/dbConfig");
const crypto = require("crypto");
const { DateTime } = require("luxon");

async function renewLicense({ hospital_id, machine_id }) {
  const conn = await db.getConnection();
  try {
    await conn.beginTransaction();

    // Fetch hospital settings
    const [settingsRows] = await conn.execute(
      "SELECT * FROM hospitals WHERE id = ?",
      [hospital_id]
    );
    if (!settingsRows.length) throw "Hospital not found";
    const settings = settingsRows[0];

    // Verify machine ID
    if (settings.machine_id !== machine_id) {
      throw "Unrecognized machine, contact support";
    }

    // Fetch plan and wallet
    const plan = await getCurrentSubscriptionPlan(hospital_id, conn);
    const wallet = await getWallet(hospital_id, conn);

    if (wallet.balance < plan.price) {
      throw "Insufficient wallet balance";
    }

    // Deduct balance
    const before = wallet.balance;
    const after = before - plan.price;
    await conn.execute("UPDATE wallets SET balance = ? WHERE hospital_id = ?", [
      after,
      hospital_id,
    ]);

    // Log wallet transaction
    await conn.execute(
      `
      INSERT INTO wallet_transactions 
        (hospital_id, amount, type, balance_before, balance_after)
      VALUES (?, ?, 'debit', ?, ?)`,
      [hospital_id, plan.price, before, after]
    );

    // Generate license
    const issuedAt = DateTime.now();
    const expiryDate = issuedAt.plus({ days: plan.duration });

    const license = {
      hospital_id,
      machine_id,
      plan: plan.name,
      duration_days: plan.duration,
      issued_at: issuedAt.toISO(),
      expiry_date: expiryDate.toISO(),
    };

    // Create HMAC signature
    license.signature = signLicense(license);

    // Save or update license metadata
    const [licenseRows] = await conn.execute(
      "SELECT id FROM licenses WHERE hospital_id = ?",
      [settings.id]
    );

    if (licenseRows.length) {
      await conn.execute(
        `UPDATE licenses 
         SET expiry_date = ?, last_renewed = NOW() 
         WHERE hosp_setting_id = ?`,
        [expiryDate.toISO(), settings.id]
      );
    } else {
      await conn.execute(
        `INSERT INTO licenses 
         (hosp_setting_id, expiry_date, last_renewed)
         VALUES (?, ?, NOW())`,
        [settings.id, expiryDate.toISO()]
      );
    }

    await conn.commit();
    return license;
  } catch (err) {
    await conn.rollback();
    throw err;
  } finally {
    conn.release();
  }
}

// --- Helper functions ---

async function getCurrentSubscriptionPlan(hospital_id, conn) {
  const [result] = await conn.execute(
    `
    SELECT sp.* FROM subscription_plans sp
    JOIN hospitals h ON h.plan_id = sp.id
    WHERE h.id = ?`,
    [hospital_id]
  );
  if (!result.length) "No subscription plan assigned";
  return result[0];
}

async function getWallet(hospital_id, conn) {
  const [walletRows] = await conn.execute(
    "SELECT * FROM wallets WHERE hospital_id = ?",
    [hospital_id]
  );
  if (!walletRows.length) throw "Wallet not found";
  return walletRows[0];
}

function signLicense(license) {
  const key = process.env.LICENSE_SECRET;
  const data = `${license.hospital_id}|${license.machine_id}|${license.expiry_date}|${license.plan}`;
  return crypto.createHmac("sha256", key).update(data).digest("hex");
}

module.exports = { renewLicense };
