// E2E 테스트: 가입 → 시드 데이터 → 발주 → 승인 + 메일 발송
// 전제: dev 서버 실행 중 (localhost:3000), DB 마이그레이션 완료
// 사용법: node scripts/test-e2e.mjs

import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import pg from "pg";

const __dirname = path.dirname(fileURLToPath(import.meta.url));
const envPath = path.join(__dirname, "..", ".env.development");
if (fs.existsSync(envPath)) {
  for (const line of fs.readFileSync(envPath, "utf-8").split(/\r?\n/)) {
    const m = line.match(/^([A-Z_][A-Z0-9_]*)=(.*)$/);
    if (m) process.env[m[1]] ??= m[2].replace(/^["']|["']$/g, "");
  }
}

const BASE = "http://localhost:3000";
const TEST_EMAIL = "chpark@wace.me";
const TEST_PASSWORD = "test1234abcd";

let cookieJar = "";
function setCookies(res) {
  const sc = res.headers.getSetCookie?.() || res.headers.raw?.()["set-cookie"] || [];
  for (const c of sc) {
    const kv = c.split(";")[0];
    cookieJar = cookieJar
      ? cookieJar.split("; ").filter((p) => !p.startsWith(kv.split("=")[0] + "=")).concat(kv).join("; ")
      : kv;
  }
}
async function api(path, init = {}) {
  const res = await fetch(`${BASE}${path}`, {
    ...init,
    headers: {
      "Content-Type": "application/json",
      ...(cookieJar ? { Cookie: cookieJar } : {}),
      ...(init.headers ?? {}),
    },
  });
  setCookies(res);
  const text = await res.text();
  let json;
  try { json = JSON.parse(text); } catch { json = { raw: text }; }
  return { status: res.status, body: json };
}

const log = (...a) => console.log("[e2e]", ...a);
const fail = (msg) => { console.error("[e2e] ✖", msg); process.exit(1); };

// ===== 1. DB 정리 + 시드 (테스트 데이터) =====
log("1. DB 정리 + 시드");
const client = new pg.Client({ connectionString: process.env.DATABASE_URL });
await client.connect();

// 기존 테스트 사용자 삭제 (재실행 가능하게)
await client.query(`DELETE FROM momo_order_items WHERE order_objid IN (SELECT objid FROM momo_orders WHERE customer_objid IN (SELECT objid FROM momo_users WHERE email = $1))`, [TEST_EMAIL]);
await client.query(`DELETE FROM momo_orders WHERE customer_objid IN (SELECT objid FROM momo_users WHERE email = $1)`, [TEST_EMAIL]);
await client.query(`DELETE FROM momo_users WHERE email = $1`, [TEST_EMAIL]);

// 품목 / 재고 시드 (테스트 품목 3개 + 본사창고 재고 100개씩)
const items = [
  { code: "TEST-EGG-01",   name: "M 유정란",    price: 10000, taxFree: "Y" },
  { code: "TEST-CHKN-01",  name: "M 꽃계탕",    price: 4500,  taxFree: "Y" },
  { code: "TEST-CLEAN-01", name: "빨강 탈취제", price: 9200,  taxFree: "N" },
];
for (const it of items) {
  await client.query(
    `INSERT INTO momo_items (objid, item_code, item_name, unit, unit_price, is_tax_free, status, regdate)
     VALUES ($1, $2, $3, 'EA', $4, $5, 'ACTIVE', NOW())
     ON CONFLICT (item_code) DO UPDATE SET unit_price = EXCLUDED.unit_price, is_tax_free = EXCLUDED.is_tax_free, status='ACTIVE', is_del='N'`,
    [`TEST-${it.code}`, it.code, it.name, it.price, it.taxFree]
  );
}
const wh = await client.query(`SELECT objid FROM momo_warehouses WHERE wh_type='STOCK' LIMIT 1`);
const whObjid = wh.rows[0].objid;
for (const it of items) {
  await client.query(
    `INSERT INTO momo_stocks (objid, wh_objid, item_objid, qty, update_date)
     VALUES ($1, $2, (SELECT objid FROM momo_items WHERE item_code = $3), 100, NOW())
     ON CONFLICT (wh_objid, item_objid) DO UPDATE SET qty = 100, update_date = NOW()`,
    [`TEST-STK-${it.code}`, whObjid, it.code]
  );
}
log("   품목 3개 + 재고 100개씩 시드 완료");

// ===== 2. 가입 =====
log("2. 회원가입");
const sup = await api("/api/auth/signup", {
  method: "POST",
  body: JSON.stringify({
    email: TEST_EMAIL,
    password: TEST_PASSWORD,
    companyName: "테스트거래처(wace)",
    ceoName: "박철현",
    bizNo: "123-45-67890",
    phone: "010-1234-5678",
  }),
});
if (!sup.body.success) fail(`가입 실패: ${JSON.stringify(sup.body)}`);
log(`   ✔ 가입 성공 (USER 세션 발급, cookie=${cookieJar.slice(0, 30)}...)`);

// ===== 3. 품목 조회 (USER 세션) =====
log("3. 품목 검색 (USER)");
const list = await api("/api/m/items/list", { method: "POST", body: JSON.stringify({ keyword: "TEST" }) });
const visible = (list.body.RESULTLIST || []).filter((r) => r.ITEM_CODE.startsWith("TEST-"));
if (visible.length !== 3) fail(`품목 조회 실패: ${visible.length}개 (기대 3개)`);
log(`   ✔ ${visible.length}개 품목 노출, 재고 ${visible[0].STOCK_QTY}`);

// ===== 4. 발주 작성 =====
log("4. 발주 요청");
const order = await api("/api/m/orders/save", {
  method: "POST",
  body: JSON.stringify({
    lines: [
      { itemObjid: visible.find((x) => x.ITEM_CODE === "TEST-EGG-01").OBJID, qty: 30 },
      { itemObjid: visible.find((x) => x.ITEM_CODE === "TEST-CHKN-01").OBJID, qty: 20 },
      { itemObjid: visible.find((x) => x.ITEM_CODE === "TEST-CLEAN-01").OBJID, qty: 11 },
    ],
    memo: "E2E 테스트 발주",
  }),
});
if (!order.body.success) fail(`발주 실패: ${JSON.stringify(order.body)}`);
log(`   ✔ 발주번호: ${order.body.orderNo}, objId: ${order.body.objId}`);

// ===== 5. 어드민 로그인 (시드 관리자) =====
log("5. 관리자 로그인");
cookieJar = ""; // USER 세션 클리어
const adminLogin = await api("/api/auth/login", {
  method: "POST",
  body: JSON.stringify({ userId: "admin@momo.com", password: "admin1234" }),
});
if (!adminLogin.body.success) {
  // 시드 비밀번호 해시가 환경에 따라 다를 수 있어 → DB에서 비밀번호 재설정
  log("   시드 비번 불일치 — bcrypt 재설정");
  const bcrypt = (await import("bcryptjs")).default;
  const hash = await bcrypt.hash("admin1234", 10);
  await client.query(`UPDATE momo_users SET password_hash = $1 WHERE email = 'admin@momo.com'`, [hash]);
  const retry = await api("/api/auth/login", {
    method: "POST",
    body: JSON.stringify({ userId: "admin@momo.com", password: "admin1234" }),
  });
  if (!retry.body.success) fail(`관리자 로그인 실패: ${JSON.stringify(retry.body)}`);
}
log(`   ✔ 관리자 세션 발급`);

// ===== 6. 승인 + 메일 발송 =====
log("6. 발주 승인 (재고차감 + 메일발송)");
const approve = await api("/api/m/orders/approve", {
  method: "POST",
  body: JSON.stringify({ objid: order.body.objId }),
});
if (!approve.body.success) fail(`승인 실패: ${JSON.stringify(approve.body)}`);
log(`   ✔ 승인 완료, mailSent=${approve.body.mailSent}, mailError=${approve.body.mailError ?? "(none)"}`);

// ===== 7. 결과 검증 =====
log("7. 후속 검증");
const r1 = await client.query(`SELECT status, total_amount, total_taxfree, total_taxable FROM momo_orders WHERE objid = $1`, [order.body.objId]);
log(`   주문 상태: ${r1.rows[0].status} (기대 APPROVED)`);
log(`   금액: 면세 ${r1.rows[0].total_taxfree} / 과세 ${r1.rows[0].total_taxable} / 합계 ${r1.rows[0].total_amount}`);
if (r1.rows[0].status !== "APPROVED") fail("주문 상태 불일치");

const r2 = await client.query(`SELECT qty FROM momo_stocks WHERE wh_objid = $1 AND item_objid = (SELECT objid FROM momo_items WHERE item_code = 'TEST-EGG-01')`, [whObjid]);
log(`   M 유정란 재고: ${r2.rows[0].qty} (기대 70 = 100-30)`);
if (Number(r2.rows[0].qty) !== 70) fail("재고 차감 불일치");

const r3 = await client.query(`SELECT to_email, subject, status, error_msg FROM momo_mail_logs WHERE ref_objid = $1 ORDER BY regdate DESC LIMIT 1`, [order.body.objId]);
log(`   메일 로그: to=${r3.rows[0].to_email}, status=${r3.rows[0].status}, subject=${r3.rows[0].subject}`);
if (r3.rows[0].error_msg) log(`   메일 에러: ${r3.rows[0].error_msg}`);

log("✔ E2E 테스트 완료");
await client.end();
