// slip-verify.jsx — Slip verification client (mock + real OpenAI mode)
// Reads tweak/config to switch between MOCK mode (Claude in-browser) and REAL mode (calls Worker proxy → OpenAI Vision)

const SlipVerify = (() => {
  // ─────────── Configuration ───────────
  // Set this to your deployed Cloudflare Worker URL when ready
  const CONFIG = {
    workerEndpoint: "https://slip-verify.sitthiwat-ma.workers.dev",
    mockMode: false,    // true = simulate; false = call workerEndpoint (Slip2Go)
    receiverAccount: "108-8-83063-2",
    receiverProxyId: "004999118274405",
    receiverName: "สิทธิวัฒน์ มะสันเทียะ",
    receiverBank: "ธนาคารกสิกรไทย",
    autoApproveThreshold: 0.85, // confidence required for auto-unlock
  };

  // Allow runtime override via window.__SLIP_CONFIG (e.g. from index.html)
  if (typeof window !== "undefined" && window.__SLIP_CONFIG) {
    Object.assign(CONFIG, window.__SLIP_CONFIG);
  }

  // ─────────── Read file as base64 (data URL) ───────────
  function fileToDataURL(file) {
    return new Promise((resolve, reject) => {
      const r = new FileReader();
      r.onload = () => resolve(r.result);
      r.onerror = reject;
      r.readAsDataURL(file);
    });
  }

  // ─────────── Resize image (max 1024px, JPEG ~80%) before send ───────────
  async function compressImage(dataUrl, maxDim = 1024, quality = 0.82) {
    const img = new Image();
    await new Promise((res, rej) => { img.onload = res; img.onerror = rej; img.src = dataUrl; });
    const scale = Math.min(1, maxDim / Math.max(img.width, img.height));
    const w = Math.round(img.width * scale);
    const h = Math.round(img.height * scale);
    const canvas = document.createElement("canvas");
    canvas.width = w; canvas.height = h;
    const ctx = canvas.getContext("2d");
    ctx.drawImage(img, 0, 0, w, h);
    return canvas.toDataURL("image/jpeg", quality);
  }

  // ─────────── MOCK mode: pretend to read slip ───────────
  // Uses Claude (built-in) to actually inspect uploaded image-ish data and produce realistic-looking results.
  // For testing the UX before deploying the Worker.
  async function mockVerify({ expectedAmount, orderId }) {
    // Simulate network delay
    await new Promise(r => setTimeout(r, 1400 + Math.random()*900));

    // Random outcome distribution: 75% pass, 15% wrong-amount, 10% can't read
    const roll = Math.random();
    if (roll < 0.75) {
      const ref = "MOCK" + Math.floor(Math.random()*1e10).toString().padStart(10,"0");
      return {
        ok: true,
        ai: {
          amount: expectedAmount,
          datetime: new Date().toLocaleString("th-TH"),
          referenceId: ref,
          receiverName: CONFIG.receiverName,
          receiverAccount: "x-x-x3063-x",
          confidence: 0.92,
          rawText: `[MOCK] อ่านสลิปจำลอง ✓ ยอด ${expectedAmount} บาท → ${CONFIG.receiverName}`,
        },
        decision: { autoApprove: true, reason: "ตรวจผ่านทุกข้อ" },
      };
    }
    if (roll < 0.90) {
      // Wrong amount
      const wrong = expectedAmount + (Math.random()<0.5 ? -10 : 50);
      return {
        ok: true,
        ai: {
          amount: wrong, datetime: new Date().toLocaleString("th-TH"),
          referenceId: "MOCK" + Math.floor(Math.random()*1e10),
          receiverName: CONFIG.receiverName, receiverAccount: "x-x-x3063-x",
          confidence: 0.88,
          rawText: `[MOCK] อ่านสลิปได้ แต่ยอดไม่ตรง (พบ ${wrong} ฿)`,
        },
        decision: { autoApprove: false, reason: `ยอดไม่ตรง: คาดหวัง ฿${expectedAmount} แต่อ่านได้ ฿${wrong}` },
      };
    }
    // Can't read clearly
    return {
      ok: true,
      ai: {
        amount: null, datetime: null, referenceId: null,
        receiverName: null, receiverAccount: null,
        confidence: 0.42,
        rawText: "[MOCK] อ่านสลิปไม่ชัด — ภาพเบลอหรือไม่ใช่สลิปจริง",
      },
      decision: { autoApprove: false, reason: "อ่านสลิปไม่ชัด ส่งให้แอดมินตรวจ" },
    };
  }

  // ─────────── REAL mode: call Cloudflare Worker → OpenAI ───────────
  async function realVerify({ slipDataUrl, expectedAmount, orderId, receiverAccount }) {
    if (!CONFIG.workerEndpoint) {
      throw new Error("ยังไม่ได้ตั้ง workerEndpoint — ตอนนี้ระบบยังเป็น mock mode");
    }
    const resp = await fetch(CONFIG.workerEndpoint, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        slipImage: slipDataUrl,
        expectedAmount,
        orderId,
        receiverAccount,
      }),
    });
    if (!resp.ok) {
      const txt = await resp.text();
      throw new Error(`Worker error ${resp.status}: ${txt}`);
    }
    return await resp.json();
  }

  // ─────────── Main entry: verify(file, {amount, orderId, episodeNumber, userId}) ───────────
  async function verify({ file, expectedAmount, orderId, episodeNumber, userId, prevReferences = [] }) {
    // 1) prep image
    const rawDataUrl = await fileToDataURL(file);
    const compressed = await compressImage(rawDataUrl);

    // 2) call mock or real
    let result;
    try {
      if (CONFIG.mockMode) {
        result = await mockVerify({ expectedAmount, orderId });
      } else {
        result = await realVerify({
          slipDataUrl: compressed,
          expectedAmount,
          orderId,
          receiverAccount: CONFIG.receiverAccount,
        });
      }
    } catch (e) {
      return {
        ok: false,
        status: "error",
        message: e.message || "เกิดข้อผิดพลาดในการตรวจสลิป",
        slipImage: compressed,
      };
    }

    if (!result.ok) {
      return {
        ok: false, status: "error",
        message: result.error || "ตรวจสลิปไม่สำเร็จ",
        slipImage: compressed,
      };
    }

    const ai = result.ai || {};
    const decision = result.decision || {};

    // 3) Local checks (regardless of AI verdict, double-check)
    const checks = [];
    if (ai.amount != null && Number(ai.amount) === Number(expectedAmount)) {
      checks.push({ key: "amount", ok: true, label: `ยอดตรง (฿${expectedAmount})` });
    } else if (ai.amount != null) {
      checks.push({ key: "amount", ok: false, label: `ยอดไม่ตรง: พบ ฿${ai.amount} คาดหวัง ฿${expectedAmount}` });
    } else {
      checks.push({ key: "amount", ok: false, label: "อ่านยอดเงินไม่ได้" });
    }

    // Check duplicate reference
    if (ai.referenceId && prevReferences.includes(ai.referenceId)) {
      checks.push({ key: "duplicate", ok: false, label: "สลิปนี้เคยใช้แล้ว (เลขอ้างอิงซ้ำ)" });
    } else if (ai.referenceId) {
      checks.push({ key: "duplicate", ok: true, label: `เลขอ้างอิงไม่ซ้ำ (${ai.referenceId.slice(-6)})` });
    } else {
      checks.push({ key: "duplicate", ok: false, label: "อ่านเลขอ้างอิงไม่ได้" });
    }

    // Check receiver — match account number OR QR proxy ID OR name
    if (ai.receiverAccount || ai.receiverName) {
      const slipDigits = String(ai.receiverAccount || "").replace(/\D/g, "");
      const accLast4 = slipDigits.slice(-4);
      const expectedLast4 = CONFIG.receiverAccount.replace(/\D/g, "").slice(-4);
      const expectedProxy = (CONFIG.receiverProxyId || "").replace(/\D/g, "");
      const accMatch = accLast4 === expectedLast4;
      const proxyMatch = expectedProxy && slipDigits.includes(expectedProxy);
      const proxyLast4Match = expectedProxy && accLast4 === expectedProxy.slice(-4);
      const nameMatch = ai.receiverName && ai.receiverName.includes(CONFIG.receiverName.split(" ")[0]);
      if (accMatch || proxyMatch || proxyLast4Match || nameMatch) {
        checks.push({ key: "receiver", ok: true, label: "บัญชีปลายทางตรง" });
      } else {
        checks.push({ key: "receiver", ok: false, label: `บัญชีปลายทางไม่ตรง (สลิป ${accLast4})` });
      }
    } else {
      checks.push({ key: "receiver", ok: false, label: "อ่านบัญชีปลายทางไม่ได้" });
    }

    const allOk = checks.every(c => c.ok);
    const dupFail = checks.find(c => c.key === "duplicate" && !c.ok);
    const confidenceOk = (ai.confidence || 0) >= CONFIG.autoApproveThreshold;

    let finalStatus, finalMessage;
    if (dupFail && ai.referenceId && prevReferences.includes(ai.referenceId)) {
      // Duplicate → reject outright
      finalStatus = "rejected";
      finalMessage = "สลิปนี้เคยใช้แล้ว กรุณาติดต่อแอดมินหากเป็นข้อผิดพลาด";
    } else if (allOk && confidenceOk) {
      finalStatus = "approved";
      finalMessage = "ตรวจสลิปผ่าน · กำลังปลดล็อกบทเรียน";
    } else {
      finalStatus = "pending";
      finalMessage = "ส่งสลิปให้แอดมินตรวจสอบ — จะได้รับการปลดล็อกใน 24 ชั่วโมง";
    }

    return {
      ok: true,
      status: finalStatus,
      message: finalMessage,
      ai,
      checks,
      decision,
      slipImage: compressed,
      submittedAt: new Date().toISOString(),
      orderId, episodeNumber, userId, expectedAmount,
    };
  }

  return {
    verify,
    config: CONFIG,
    setConfig: (patch) => Object.assign(CONFIG, patch),
  };
})();

window.SlipVerify = SlipVerify;
