// 출고 관리 — 발주 단건 편집 락(비관적 락)
// action=acquire: 락 획득. 다른 사용자가 보유 중(2분 이내 갱신)이면 거부.
// action=heartbeat: 자기 락 갱신 (30초마다 호출 권장)
// action=release: 자기 락 해제
//
// 만료 정책: editing_at < NOW() - INTERVAL '2 minutes' 면 자동 만료로 간주 → 다른 사람이 가져갈 수 있음.
// 페이지가 그냥 닫혀도 최대 2분 이내에 자동 해제.
import { NextRequest, NextResponse } from "next/server";
import { pool } from "@/lib/db";
import { requireMomoAdmin } from "@/lib/momo-guard";

let colsEnsured = false;
async function ensureLockCols() {
  if (colsEnsured) return;
  try {
    await pool.query(`
      ALTER TABLE momo_orders
        ADD COLUMN IF NOT EXISTS editing_by TEXT,
        ADD COLUMN IF NOT EXISTS editing_at TIMESTAMP;
    `);
    colsEnsured = true;
  } catch (err) {
    console.error("[orders/lock/ensureLockCols]", err);
  }
}

const TTL_MINUTES = 2;

export async function POST(req: NextRequest) {
  const g = await requireMomoAdmin();
  if (g instanceof NextResponse) return g;
  await ensureLockCols();

  const me = String(g.user.objid || g.user.userId);
  const myName = g.user.userName || me;
  const body = await req.json().catch(() => ({}));
  const orderObjid = String(body.orderObjid || "");
  const action = String(body.action || "");
  if (!orderObjid || !["acquire", "heartbeat", "release"].includes(action)) {
    return NextResponse.json({ success: false, message: "invalid params" }, { status: 400 });
  }

  const client = await pool.connect();
  try {
    if (action === "release") {
      // 자기가 가진 락만 해제 (다른 사람 거 건드리지 않음)
      await client.query(
        `UPDATE momo_orders SET editing_by = NULL, editing_at = NULL
          WHERE objid::text = $1 AND editing_by = $2`,
        [orderObjid, me]
      );
      return NextResponse.json({ success: true });
    }

    if (action === "heartbeat") {
      // heartbeat: 자기 락일 때만 editing_at 만 갱신 (절대 빈 락을 새로 잡지 않음).
      // 사용자가 다른 발주로 이동해서 release 가 적용된 후 늦게 도착한 heartbeat 이
      // 빈 락을 다시 me 로 잡아버리는 race condition 차단.
      const upd = await client.query(
        `UPDATE momo_orders
            SET editing_at = NOW()
          WHERE objid::text = $1
            AND editing_by  = $2
            AND editing_at > NOW() - INTERVAL '${TTL_MINUTES} minutes'`,
        [orderObjid, me]
      );
      if (upd.rowCount === 0) {
        // 자기 락이 아니거나 이미 만료 — 다른 사람이 가져갔을 수도
        const cur = await client.query<{ editing_by: string | null; lock_name: string | null }>(
          `SELECT O.editing_by, U.user_name AS lock_name
             FROM momo_orders O
             LEFT JOIN user_info U ON U.user_id = O.editing_by
            WHERE O.objid::text = $1
              AND O.editing_at IS NOT NULL
              AND O.editing_at > NOW() - INTERVAL '${TTL_MINUTES} minutes'`,
          [orderObjid]
        );
        const lockedBy = cur.rows[0]?.editing_by || "";
        const lockedByName = cur.rows[0]?.lock_name || "";
        return NextResponse.json({
          success: false,
          lockedBy,
          lockedByName,
          message: lockedBy && lockedBy !== me
            ? `${lockedByName || lockedBy} 님이 수정 중입니다.`
            : "락이 해제되었습니다.",
        }, { status: 409 });
      }
      return NextResponse.json({ success: true, action: "heartbeat", lockedBy: me, lockedByName: myName });
    }

    // action === "acquire": 현재 락 상태 조회
    const cur = await client.query<{ editing_by: string | null; alive: boolean; lock_name: string | null }>(
      `SELECT O.editing_by,
              (O.editing_at IS NOT NULL AND O.editing_at > NOW() - INTERVAL '${TTL_MINUTES} minutes') AS alive,
              U.user_name AS lock_name
         FROM momo_orders O
         LEFT JOIN user_info U ON U.user_id = O.editing_by
        WHERE O.objid::text = $1`,
      [orderObjid]
    );
    if (cur.rowCount === 0) {
      return NextResponse.json({ success: false, message: "발주를 찾을 수 없습니다." }, { status: 404 });
    }
    const { editing_by, alive, lock_name } = cur.rows[0];

    // 다른 사람의 유효 락이 있으면 거부
    if (alive && editing_by && editing_by !== me) {
      return NextResponse.json({
        success: false,
        locked: true,
        lockedBy: editing_by,
        lockedByName: lock_name || editing_by,
        message: `${lock_name || editing_by} 님이 수정 중입니다.`,
      }, { status: 409 });
    }

    // 빈 락이거나 자기 락 — acquire 만 새로 잡음
    await client.query(
      `UPDATE momo_orders SET editing_by = $2, editing_at = NOW() WHERE objid::text = $1`,
      [orderObjid, me]
    );
    return NextResponse.json({
      success: true,
      action: "acquire",
      lockedBy: me,
      lockedByName: myName,
    });
  } catch (err) {
    console.error("[orders/lock]", err);
    return NextResponse.json({ success: false, message: "락 처리 오류" }, { status: 500 });
  } finally {
    client.release();
  }
}
