const dbConnect = require("../../busapi/configs/dbConnection");
require("dotenv")

const crypto = require("crypto");

/**
 * Helper: Decrypt JWE using dynamic import (ESM-safe)
 */
async function decryptJWE(jweCompact) {
  const { compactDecrypt } = await import("jose"); // ✅ dynamic import
  const { TextDecoder } = require("util");

  const encryptionKey = Buffer.from(process.env.BD_ENC_KEY, "utf8");

  const { plaintext } = await compactDecrypt(
    jweCompact,
    encryptionKey
  );

  return new TextDecoder().decode(plaintext);
}

async function updateWebhookResponse(rawResponse, signatureVerified, insertId) {
  await dbConnect.query(
    `
    UPDATE billdesk_webhook_logs
    SET encoded_response = ?,
    signature_verified = ?
    WHERE id = ?
    `,
    [rawResponse, signatureVerified, insertId]
  );
}

/**
 * Inserts payment response into database
 */
async function insertEnquirePaymentData(data) {
    // If response is nested under decodedData, extract it
    const res = data.decodedData || data;

    if (!res.orderid) throw new Error("Missing required field: orderid");
  
    const sql = `
        INSERT INTO bd_enquire_payment_response (
            order_id, trans_id, transaction_date, amount, surcharge, discount, 
            charge_amount, bank_id, bank_ref_no, auth_status, transaction_error_desc, 
            transaction_error_type, payment_method, payment_category
        ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
        ON DUPLICATE KEY UPDATE
        amount = VALUES(amount),
        surcharge = VALUES(surcharge), 
        discount = VALUES(discount), 
        charge_amount = VALUES(charge_amount),
        bank_id = VALUES(bank_id),
        bank_ref_no = VALUES(bank_ref_no), 
        auth_status = VALUES(auth_status),
        transaction_error_desc = VALUES(transaction_error_desc), 
        transaction_error_type = VALUES(transaction_error_type),
        payment_method = VALUES(payment_method), 
        payment_category = VALUES(payment_category)
    `;
    
    // status = CASE
        //   WHEN status = 'SUCCESS' THEN status
        //   ELSE VALUES(status)
        // END,
    
    
  const values = [
    res.orderid ?? null,
    res.transactionid ?? null,
    res.transaction_date ? new Date(res.transaction_date) : null,
    res.amount ?? null,
    res.surcharge ?? null,
    res.discount ?? null,
    res.charge_amount ?? null,
    res.bankid ?? null,
    res.bank_ref_no ?? null,
    res.auth_status ?? null, 
    res.transaction_error_desc ?? null,
    res.transaction_error_type ?? null,
    res.payment_method_type ?? null,
    res.payment_category ?? null
  ];

  try {
    await dbConnect.execute(sql, values);
    console.log("✅ Enquire Payment Data Inserted Successfully");
  } catch (err) {
    console.error("❌ DB Insert Error:", err);
    throw err;
  }
}

exports.billdeskWebhook = async (req, res) => {
    let rawPayload;
    let rawResponse = "OK";
    let signatureVerified = false;
    let insertId = null;
      
  try {
    console.log("========== BILLDESK WEBHOOK HIT ==========");
    console.log("Webhook time:", new Date().toISOString());
    console.log("Type of req.body:", typeof req.body);

    // 1️⃣ Raw payload
    rawPayload = req.body;
    console.log("rawPayload: ",rawPayload );
    
    
     const query = `
        INSERT INTO billdesk_webhook_logs (encoded_request)
        VALUES (?)
        `;
    const [result] = await dbConnect.query(query, [rawPayload]);
    console.log(`Order inserted with ID: ${result.insertId}`);
    const insertId = result.insertId;
    
    rawPayload = req.body.toString("utf8");
    
    const parts = rawPayload.split(".");

    console.log("Parts count:", parts.length);

    if (parts.length !== 3) {
      console.log("Invalid JWS format");
      await updateWebhookResponse(rawResponse, false, insertId);
      return res.status(200).send(rawResponse);
    }

    const [encodedHeader, encodedPayload, receivedSignature] = parts;

    // 2️⃣ Decode & log header
    const headerJson = Buffer
      .from(encodedHeader, "base64url")
      .toString("utf8");

    console.log("DECODED HEADER JSON >>>");
    console.log(headerJson);
    console.log("============================================");

    // 3️⃣ Verify signature (HS256)
    const signingKey = process.env.BD_SIGN_KEY;
    // if (!signingKey) {
    //   console.log("Signing key not configured");
    //   return res.status(200).send("OK");
    // }

    const dataToVerify = `${encodedHeader}.${encodedPayload}`;

    const expectedSignature = crypto
      .createHmac("sha256", signingKey)
      .update(dataToVerify)
      .digest("base64url");

     signatureVerified  = crypto.timingSafeEqual(
      Buffer.from(expectedSignature),
      Buffer.from(receivedSignature)
    );

    console.log("SIGNATURE VALID:", signatureVerified);
    if (!signatureVerified) {
        await updateWebhookResponse(rawResponse, false, insertId );
        return res.status(200).send(rawResponse);
    }

    // 4️⃣ First decode (JWS payload → base64 string)
    const decodedOnce = Buffer
      .from(encodedPayload, "base64url")
      .toString("utf8");

    console.log("PAYLOAD AFTER 1st DECODE >>>");
    console.log(decodedOnce);
    console.log("============================================");

    // 5️⃣ Second decode (base64 → JWE compact string)
    // ✅ decodedOnce IS the JWE compact string
    const jweCompact = decodedOnce;


    console.log("JWE COMPACT STRING >>>");
    console.log(jweCompact);
    console.log("============================================");

    // 6️⃣ FINAL STEP: Decrypt JWE
    // const finalPayload = await decryptJWE(jweCompact);
    const decrypt2 = await decryptJWE(jweCompact);
    console.log("Decrypt 2:", decrypt2);
    const finalPayload = JSON.parse(decrypt2);

    
    // 7️⃣ Extract business fields (example)
    const orderId = finalPayload.orderid;
    const bd_txn_id = finalPayload.transactionid;
    const authStatus = finalPayload.auth_status;
    // const amount = finalPayload.amount;

    console.log("🎉 FINAL DECRYPTED PAYLOAD >>>");
    //console.log(finalPayload);
    console.log("<<< END");
    
    
    // const status =
    //     authStatus === "0300" ? "SUCCESS" :
    //     authStatus ? "FAILED" :
    //     "PENDING";
    
    const status =
        authStatus === "0300" ? "Transaction Successful" :
        authStatus === "0399" ? "Transaction Failed" :
        "Transaction Pending";
        
    await insertEnquirePaymentData(finalPayload);
    
    // 8️⃣ Store webhook in DB (raw JWS + signature + orderId)
    
    await dbConnect.query(`
        UPDATE billdesk_webhook_logs
        SET order_id = ?,
        bd_txn_id = ?,
        encoded_response = ?,
        auth_status = ?,
        status = ?,
        signature_verified = ?
        WHERE id = ?
    `,
    [orderId, bd_txn_id, rawResponse, authStatus, status, signatureVerified, insertId]
  );
  
  // update online pay table
  await dbConnect.query(
      "UPDATE onlinepay SET status = ? WHERE ipgid = ?",
      [status, orderId]
    );
  return res.status(200).send(rawResponse);

  } catch (err) {
    console.error("Webhook error:", err);
    // store failure attempt as well
    if (rawPayload && insertId) {
      await updateWebhookResponse(rawResponse, false, insertId );
    }
    return res.status(200).send("OK");
  }
};



