const validator = require("validator");

const db = require("../../../../managers/dbConfig");
const { encrypt } = require("../../../../managers/encrytion");
const { generateSessionId } = require("../../../../managers/idGenerator");
const logger = require("../../../../handlers/logger"); // Import your logger

// const consult = async (req, res) => {
//   const getDOC = req.user.cadre;
//   // if (getDOC !== "Doctor")
//   // throw "Only Doctors were allowed to write this document!";

//   let {
//     pt_id,
//     co,
//     hx,
//     drugHx,
//     oe,
//     labInv,
//     diag,
//     rx,
//     admission_stat,
//     note,
//     signed_by,
//     bill,
//     //  paid,
//     bill_to,
//     sessID,
//   } = req.body;

//   if (!pt_id) throw "Patient ID is Required";
//   if (!sessID) throw "please provide session ID, write 'nil' for new session";
//   if (!signed_by)
//     throw "oops! Logged-in staff can not be ascertain, kindly re-login.";

//   const sqlFetch =
//     "SELECT session_id FROM tx WHERE session_id=? AND patient_id=?";

//   const updateWalletSql = `UPDATE patients SET outstanding_balance=? WHERE patient_id=?`;
//   const updateHMOWalletSql = `UPDATE patients SET hmo_wallet=? WHERE patient_id=?`;
//   const insertToHMOBill = ` INSERT INTO hmo_bills(code_name,patient_id,amount) VALUES(?,?,?)`;
//   const insertToFOC = `INSERT INTO foc(patient_id, amount, awarded_by) VALUES(?,?,?)`;
//   const selectWalletBalanceSql = `SELECT outstanding_balance,hmo,hmo_wallet FROM patients WHERE patient_id=?`;
//   const sql3 = `SELECT COUNT(patient_id) FROM patients WHERE patient_id=?`;
//   //const sql4 = `UPDATE counters SET total_count=? WHERE table_name=?`;

//   const sql = `INSERT INTO tx(
//   patient_id,
//   c_o,
//   hx,
//   drug_hx,
//   o_e,
//   lab_inv,
//   diag,
//   rx,
//   admission_status,
//   dr_note,
//   signed_by,
//   bill,
//   paid,
//   to_balance,
//   bill_to,
//   session_id
//   ) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`;

//   const connection = await db.getConnection();
//   try {
//     await connection.beginTransaction();

//     if (sessID == "nil" || sessID == "Nil") {
//       sessID = generateSessionId();
//     } else {
//       const [existing] = await connection.execute(sqlFetch, [sessID, pt_id]);
//       if (existing.length === 0)
//         throw `session ID ${sessID}, does NOT exist for this patient`;
//     }

//     const [ptExist] = await connection.execute(sql3, [pt_id]);

//     if (ptExist[0]["COUNT(patient_id)"] < 1) throw "patient ID not found";

//     const [prev_balance] = await connection.execute(selectWalletBalanceSql, [
//       pt_id,
//     ]);

//     let prev_bal = Number(prev_balance[0].outstanding_balance);

//     let paid = 0;
//     let toBalance = prev_bal;
//     let hmo_wallet;

//     if (bill != 0 && bill != "" && bill != undefined) {
//       // if (!paid || paid == "") throw "please enter amount paid";
//       if (!validator.isNumeric(bill.toString()))
//         throw "Amount can only be valid numbers, please recheck!";
//       if (!bill_to) throw "Billing Error! Please select who is paying the bill";
//       // if (!paid) throw "Billing Error! Paid amount is required";
//       if (!validator.isNumeric(paid.toString()))
//         throw "Paid-Amount can only be valid numbers, please recheck!";

//       switch (bill_to) {
//         case "patient":
//           toBalance = prev_bal + (paid - bill);
//           // toBalance = toBalance + (prev_bal);
//           await connection.execute(updateWalletSql, [toBalance, pt_id]);
//           break;

//         case "hmo":
//           if (prev_balance[0].hmo == "Nil" || prev_balance[0].hmo == null)
//             throw `Billing Error! patient with ID ${pt_id} does NOT subscribe to any HMO`;
//           prev_bal = Number(prev_balance[0].hmo_wallet);
//           hmo_wallet = prev_bal + bill;
//           await connection.execute(updateHMOWalletSql, [hmo_wallet, pt_id]);
//           await connection.execute(insertToHMOBill, [
//             prev_balance[0].hmo,
//             pt_id,
//             bill,
//           ]);
//           break;

//         case "f.o.c":
//           await connection.execute(insertToFOC, [pt_id, bill, signed_by]); //using signed_by instead of sFullName, as sFullName is not defined in the original code.
//           break;
//       }
//     }
//     //if(sessID =)
//     co = co ?? "nil";
//     hx = hx ?? "nil";
//     drugHx = drugHx ?? "nil";
//     oe = oe ?? "nil";
//     labInv = labInv ?? "nil";
//     diag = diag ?? "nil";
//     rx = rx ?? "nil";
//     note = note ?? null;

//     const enc_co = encrypt(co, process.env.enc_key);
//     const enc_hx = encrypt(hx, process.env.enc_key);
//     const enc_drugHx = encrypt(drugHx, process.env.enc_key);
//     const enc_oe = encrypt(oe, process.env.enc_key);
//     const enc_labInv = encrypt(labInv, process.env.enc_key);
//     const enc_diag = encrypt(diag, process.env.enc_key);
//     const enc_rx = encrypt(rx, process.env.enc_key);
//     const enc_note = encrypt(note, process.env.enc_key);

//     await connection.execute(sql, [
//       pt_id,
//       enc_co,
//       enc_hx,
//       enc_drugHx,
//       enc_oe,
//       enc_labInv,
//       enc_diag,
//       enc_rx,
//       admission_stat,
//       enc_note,
//       signed_by,
//       bill,
//       paid,
//       toBalance,
//       bill_to,
//       sessID,
//     ]);

//     await connection.commit();
//     connection.release();

//     res.status(200).json({
//       status: "success",
//       message: "Treatment Saved Successfully",
//     });
//   } catch (error) {
//     await connection.rollback();
//     connection.release();
//     logger.error("Database error in consult:", error); // Log the error using Winston
//     res.status(400).json({
//       status: "failed",
//       error,
//     });
//   }
// };

// // Appending data to existing treatments data dynamically

// const appendToRx = async (req, res) => {
//   const {
//     session_id,
//     co,
//     hx,
//     drugHx,
//     oe,
//     labInv,
//     diag,
//     rx,
//     note,
//     bill,
//     bill_to,
//     paid,
//     signed_by,
//   } = req.body;

//   if (!session_id)
//     throw "RX-Session ID is required to add to existing RX record";
//   if (!signed_by) throw "Your identity is required";

//   const sqlFetch = `SELECT signed_by,patient_id, c_o, hx, drug_hx, o_e, lab_inv, diag, rx, dr_note, bill, paid, to_balance, bill_to FROM tx WHERE session_id=?`;
//   const selectWalletBalanceSql = `SELECT outstanding_balance, hmo, hmo_wallet FROM patients WHERE patient_id=?`;
//   const updateWalletSql = `UPDATE patients SET outstanding_balance=? WHERE patient_id=?`;
//   const updateHMOWalletSql = `UPDATE patients SET hmo_wallet=? WHERE patient_id=?`;
//   const insertToHMOBill = `INSERT INTO hmo_bills(code_name, patient_id, amount) VALUES (?, ?, ?)`;
//   const insertToFOC = `INSERT INTO foc(patient_id, amount, awarded_by) VALUES(?, ?, ?)`;

//   const connection = await db.getConnection();
//   try {
//     await connection.beginTransaction();

//     // Fetch existing treatment data
//     const [existing] = await connection.execute(sqlFetch, [session_id]);
//     if (existing.length === 0)
//       throw `Treatment session with ID ${session_id} NOT found`;
//     if (signed_by != existing[0].signed_by)
//       throw `You can not add to records NOT initiated by you! please start new session.creator-- ${existing[0].signed_by}, you-- ${signed_by}`;

//     const patientId = existing[0].patient_id;

//     // Fetch patient balance details
//     const [prev_balance] = await connection.execute(selectWalletBalanceSql, [
//       patientId,
//     ]);
//     let updateFields = {};
//     let values = [];

//     // Append encrypted data
//     if (co)
//       updateFields["c_o"] = existing[0].c_o
//         ? existing[0].c_o + "\n" + encrypt(co, process.env.enc_key)
//         : encrypt(co, process.env.enc_key);
//     if (hx)
//       updateFields["hx"] = existing[0].hx
//         ? existing[0].hx + "\n" + encrypt(hx, process.env.enc_key)
//         : encrypt(hx, process.env.enc_key);
//     if (drugHx)
//       updateFields["drug_hx"] = existing[0].drug_hx
//         ? existing[0].drug_hx + "\n" + encrypt(drugHx, process.env.enc_key)
//         : encrypt(drugHx, process.env.enc_key);
//     if (oe)
//       updateFields["o_e"] = existing[0].o_e
//         ? existing[0].o_e + "\n" + encrypt(oe, process.env.enc_key)
//         : encrypt(oe, process.env.enc_key);
//     if (labInv)
//       updateFields["lab_inv"] = existing[0].lab_inv
//         ? existing[0].lab_inv + "\n" + encrypt(labInv, process.env.enc_key)
//         : encrypt(labInv, process.env.enc_key);
//     if (diag)
//       updateFields["diag"] = existing[0].diag
//         ? existing[0].diag + "\n" + encrypt(diag, process.env.enc_key)
//         : encrypt(diag, process.env.enc_key);
//     if (rx)
//       updateFields["rx"] = existing[0].rx
//         ? existing[0].rx + "\n" + encrypt(rx, process.env.enc_key)
//         : encrypt(rx, process.env.enc_key);
//     if (note)
//       updateFields["dr_note"] = existing[0].dr_note
//         ? existing[0].dr_note + "\n" + encrypt(note, process.env.enc_key)
//         : encrypt(note, process.env.enc_key);
//     // handle billing cases
//     if (bill != 0 && bill != "" && bill != undefined) {
//       if (!validator.isNumeric(bill.toString()))
//         throw "Amount can only be valid numbers, please recheck!";
//       if (!bill_to) throw "Billing Error! Please select who is paying the bill";
//       if (!paid) throw "Billing Error! Paid amount is required";
//       if (!validator.isNumeric(paid.toString()))
//         throw "Paid-Amount can only be valid numbers, please recheck!";

//       let prev_bal;
//       switch (bill_to) {
//         case "patient":
//           prev_bal = Number(prev_balance[0].outstanding_balance);
//           let toBalance = paid - bill + prev_bal;
//           await connection.execute(updateWalletSql, [toBalance, patientId]);
//           updateFields["to_balance"] = toBalance;
//           break;

//         case "hmo":
//           if (prev_balance[0].hmo == "Nil" || prev_balance[0].hmo == null)
//             throw `Patient with ID ${patientId} has no HMO`;
//           prev_bal = Number(prev_balance[0].hmo_wallet);
//           let hmo_wallet = prev_bal + Number(bill);
//           await connection.execute(updateHMOWalletSql, [hmo_wallet, patientId]);
//           await connection.execute(insertToHMOBill, [
//             prev_balance[0].hmo,
//             patientId,
//             bill,
//           ]);
//           break;

//         case "foc":
//           await connection.execute(insertToFOC, [
//             patientId,
//             bill,
//             "System Update",
//           ]);
//           break;
//       }

//       updateFields["bill"] = (existing[0].bill || 0) + Number(bill);
//       updateFields["paid"] = (existing[0].paid || 0) + Number(paid);
//     }

//     if (Object.keys(updateFields).length === 0)
//       throw "No valid fields to add to";

//     let sqlParts = Object.keys(updateFields).map((field) => `${field}=?`);
//     values = [...Object.values(updateFields), session_id];

//     const sqlUpdate = `UPDATE tx SET ${sqlParts.join(", ")} WHERE session_id=?`;

//     await connection.execute(sqlUpdate, values);
//     await connection.commit();
//     connection.release();

//     res.status(200).json({
//       status: "success",
//       message: "Consultation updated with additional details successfully",
//     });
//   } catch (error) {
//     await connection.rollback();
//     connection.release();
//     logger.error("Database error in appendToRx:", error); // Log the error using Winston
//     res.status(500).json({
//       status: "error",
//       message: "An error occurred when updating the consultation",
//     });
//   }
// };

// module.exports = { consult, appendToRx };

const consult = async (req, res) => {
  //   const getDOC = req.user.cadre;
  //   // if (getDOC !== "Doctor")
  //   // throw "Only Doctors were allowed to write this document!";
  let {
    pt_id,
    co,
    hx,
    drugHx,
    oe,
    labInv,
    diag,
    rx,
    admission_stat,
    note,
    signed_by,
    bill,
    bill_to,
    sessID,
  } = req.body;

  if (!pt_id) throw "Patient ID is Required";
  if (!sessID) throw "please provide session ID, write 'nil' for new session";
  if (!signed_by)
    throw "oops! Logged-in staff can not be ascertain, kindly re-login.";
  //console.log("Incoming RX:", req.body.rx);

  const sqlFetch =
    "SELECT session_id FROM tx WHERE session_id=? AND patient_id=?";
  const sql3 = `SELECT COUNT(patient_id) FROM patients WHERE patient_id=?`;
  const selectWalletBalanceSql = `SELECT outstanding_balance,hmo,hmo_wallet FROM patients WHERE patient_id=?`;
  const updateWalletSql = `UPDATE patients SET outstanding_balance=? WHERE patient_id=?`;
  const updateHMOWalletSql = `UPDATE patients SET hmo_wallet=? WHERE patient_id=?`;
  const insertToHMOBill = ` INSERT INTO hmo_bills(code_name,patient_id,amount) VALUES(?,?,?)`;
  const insertToFOC = `INSERT INTO foc(patient_id, amount, awarded_by) VALUES(?,?,?)`;

  const sqlInsert = `INSERT INTO tx(
    patient_id, c_o, hx, drug_hx, o_e, lab_inv, diag, rx,
    admission_status, dr_note, signed_by,
    bill, paid, to_balance, bill_to, session_id
  ) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`;

  const connection = await db.getConnection();
  try {
    await connection.beginTransaction();

    if (sessID.toLowerCase() === "nil") {
      sessID = generateSessionId();
    } else {
      const [existing] = await connection.execute(sqlFetch, [sessID, pt_id]);
      if (existing.length === 0)
        throw `session ID ${sessID}, does NOT exist for this patient`;
    }

    const [ptExist] = await connection.execute(sql3, [pt_id]);
    if (ptExist[0]["COUNT(patient_id)"] < 1) throw "patient ID not found";

    const [prev_balance] = await connection.execute(selectWalletBalanceSql, [
      pt_id,
    ]);
    let prev_bal = Number(prev_balance[0].outstanding_balance);
    let paid = 0;
    let toBalance = prev_bal;
    let hmo_wallet;

    if (bill > 0 && bill != "" && bill != undefined) {
      if (!bill_to) throw "Billing Error! Please select who is paying the bill";
      if (!validator.isNumeric(bill.toString())) throw "Invalid bill amount";
      if (!validator.isNumeric(paid.toString())) throw "Invalid paid amount";

      //  Save billing summary if estimated billing is used
      const insertSummarySql = `
    INSERT INTO billing_summary(
      patient_id, session_id, rx_time,
      total_bill, vat_rate, discount_type, discount_rate,
      vat_amount, discount_amount, net_payable,balance_remaining, status
    ) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)
  `;

      const now = new Date();
      const rx_time = now.toISOString().slice(0, 19).replace("T", " ");
      const subtotal = bill;
      const vat_rate = 0;
      const discount_type = "none";
      const discount_value = 0;
      const vat_amount = 0;
      const discount_amount = 0;
      const net_payable = subtotal;

      await connection.execute(insertSummarySql, [
        pt_id,
        sessID,
        rx_time,
        subtotal,
        vat_rate,
        discount_type,
        discount_value,
        vat_amount,
        discount_amount,
        net_payable,
        net_payable,
        "pending",
      ]);

      switch (bill_to) {
        case "patient":
          toBalance = prev_bal + (paid - bill);
          await connection.execute(updateWalletSql, [toBalance, pt_id]);

          // Update payment and billing summary records if wallet is positive

          if (prev_bal > 0.0) {
            let walletCharged;

            const insertPaymentSql = `INSERT INTO payments (
         patient_id, rx_time, amount_paid, paid_for, payment_method,
         payer_type, confirmed_by, rx_session, bank_name
       ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`;

            const updateBillingSummarySql = `UPDATE billing_summary SET status = ?, total_paid = ?, balance_remaining = ?
       WHERE patient_id = ? AND session_id = ? AND rx_time = ?`;

            //
            if (prev_bal < bill) {
              walletCharged = prev_bal;

              await connection.execute(insertPaymentSql, [
                pt_id,
                rx_time,
                walletCharged,
                "treatment",
                "Wallet",
                "patient",
                signed_by,
                sessID,
                "N/A",
              ]);

              const [payments] = await connection.execute(
                `SELECT SUM(amount_paid) AS total_paid FROM payments
       WHERE patient_id = ? AND rx_time = ? AND rx_session = ?`,
                [pt_id, rx_time, sessID]
              );

              const totalPaid = Number(payments[0].total_paid || 0);

              const remaining = bill - totalPaid;

              await connection.execute(updateBillingSummarySql, [
                "partially_paid",
                totalPaid,
                remaining,
                pt_id,
                sessID,
                rx_time,
              ]);
            } else if (prev_bal >= bill) {
              walletCharged = bill;

              await connection.execute(insertPaymentSql, [
                pt_id,
                rx_time,
                walletCharged,
                "treatment",
                "Wallet",
                "patient",
                signed_by,
                sessID,
                "N/A",
              ]);

              await connection.execute(updateBillingSummarySql, [
                "paid",
                bill,
                0.0,
                patient_id,
                sessID,
                rx_time,
              ]);
            }
          }
          break;
        case "hmo":
          if (!prev_balance[0].hmo) throw "Patient is not under any HMO";
          hmo_wallet = Number(prev_balance[0].hmo_wallet) + Number(bill);
          await connection.execute(updateHMOWalletSql, [hmo_wallet, pt_id]);
          await connection.execute(insertToHMOBill, [
            prev_balance[0].hmo,
            pt_id,
            bill,
          ]);
          break;
        case "f.o.c":
          await connection.execute(insertToFOC, [pt_id, bill, signed_by]);
          break;
      }
    }

    // Default fields
    co = co ?? "nil";
    hx = hx ?? "nil";
    drugHx = drugHx ?? "nil";
    oe = oe ?? "nil";
    labInv = labInv ?? "nil";
    diag = diag ?? "nil";
    note = note ?? null;

    // ✳️ Convert rx array to encrypted string
    if (!Array.isArray(rx))
      throw "Invalid RX format. Expected a List of Prescription.";

    const encryptedRx = JSON.stringify(
      rx.map((item, index) => {
        if (!item.drug_name)
          throw `Drug name is missing in prescription line ${index + 1}`;
        if (item.dosage == null || item.dosage == "")
          throw `Dosage is missing in prescription line ${index + 1}`;

        return {
          drug_id:
            item.inventory_id == null
              ? "N/A"
              : encrypt(item.inventory_id.toString(), process.env.enc_key),
          drug_name: encrypt(item.drug_name.toString(), process.env.enc_key),
          dosage: encrypt(item.dosage.toString(), process.env.enc_key),
          quantity: item.quantity ?? 0,
          cp_pu: item.cp_pu,
          sp_pu: item.sp_pu,
        };
      })
    );

    // Encrypt other fields
    const enc_co = encrypt(co, process.env.enc_key);
    const enc_hx = encrypt(hx, process.env.enc_key);
    const enc_drugHx = encrypt(drugHx, process.env.enc_key);
    const enc_oe = encrypt(oe, process.env.enc_key);
    const enc_labInv = encrypt(labInv, process.env.enc_key);
    const enc_diag = encrypt(diag, process.env.enc_key);
    const enc_note = encrypt(note, process.env.enc_key);

    await connection.execute(sqlInsert, [
      pt_id,
      enc_co,
      enc_hx,
      enc_drugHx,
      enc_oe,
      enc_labInv,
      enc_diag,
      encryptedRx,
      admission_stat,
      enc_note,
      signed_by,
      bill,
      paid,
      toBalance,
      bill_to,
      sessID,
    ]);

    await connection.commit();
    connection.release();

    res.status(200).json({
      status: "success",
      message: "Treatment saved successfully!",
    });
  } catch (error) {
    await connection.rollback();
    connection.release();
    logger.error("Database error in consult:", error);
    res.status(400).json({ status: "failed", error });
  }
};
module.exports = { consult };
