// 입고 처리: 매입발주 라인의 정상/불량 수량을 기록 + 정상 수량만 재고 +
import { NextRequest, NextResponse } from "next/server";
import { pool, queryOne } from "@/lib/db";
import { createObjectId } from "@/lib/utils";
import { requireMomoAdmin } from "@/lib/momo-guard";

interface Line {
  itemObjid: string;
  qtyNormal: number;
  qtyDefect: number;
  costPrice: number;
  defectReason?: string;
}

export async function POST(req: NextRequest) {
  const g = await requireMomoAdmin();
  if (g instanceof NextResponse) return g;
  const adminId = g.user.objid || g.user.userId;

  const { procObjid, vendorObjid, whObjid, inboundDate, lines, memo } = await req.json() as {
    procObjid?: string; vendorObjid?: string; whObjid: string; inboundDate?: string;
    lines: Line[]; memo?: string;
  };
  if (!whObjid || !Array.isArray(lines) || lines.length === 0) {
    return NextResponse.json({ success: false, message: "창고와 입고 라인이 필요합니다." }, { status: 400 });
  }

  const inboundObjid = createObjectId();
  const inboundNo = await genInboundNo();
  let total = 0;
  for (const ln of lines) total += Math.round(Number(ln.costPrice) * (Number(ln.qtyNormal) + Number(ln.qtyDefect)));

  const client = await pool.connect();
  try {
    await client.query("BEGIN");
    await client.query(
      `INSERT INTO momo_inbounds (objid, inbound_no, proc_objid, vendor_objid, wh_objid, inbound_date, status, total_amount, memo, regdate, regid)
       VALUES ($1,$2,$3,$4,$5,COALESCE($6::date, CURRENT_DATE),'COMPLETED',$7,$8,NOW(),$9)`,
      [inboundObjid, inboundNo, procObjid ?? null, vendorObjid ?? null, whObjid, inboundDate ?? null, total, memo ?? null, adminId]
    );

    // 입고 한도 사전 검증 (procObjid 있을 때) — 발주수량 - 기존 누적 입고 ≥ 이번 입고
    if (procObjid) {
      for (const ln of lines) {
        const qtyN = Number(ln.qtyNormal) || 0;
        const qtyD = Number(ln.qtyDefect) || 0;
        const cur = await client.query(
          `SELECT qty, COALESCE(received_qty,0) AS received, item_objid
           FROM momo_procurement_items
           WHERE proc_objid = $1 AND item_objid = $2`,
          [procObjid, ln.itemObjid]
        );
        if (cur.rowCount === 0) continue;
        const remaining = Number(cur.rows[0].qty) - Number(cur.rows[0].received);
        if (qtyN + qtyD > remaining) {
          await client.query("ROLLBACK");
          return NextResponse.json({
            success: false,
            message: `입고 가능 수량을 초과했습니다. (남은 수량 ${remaining})`,
          }, { status: 400 });
        }
      }
    }

    let seq = 0;
    for (const ln of lines) {
      seq++;
      const qtyN = Number(ln.qtyNormal) || 0;
      const qtyD = Number(ln.qtyDefect) || 0;
      if (qtyN + qtyD === 0) continue; // 0 입고 라인은 건너뛰기
      const lineTotal = Math.round(Number(ln.costPrice) * (qtyN + qtyD));
      await client.query(
        `INSERT INTO momo_inbound_items (objid, inbound_objid, item_objid, qty_normal, qty_defect, cost_price, defect_reason, total_amount, seq)
         VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9)`,
        [createObjectId(), inboundObjid, ln.itemObjid, qtyN, qtyD, ln.costPrice, ln.defectReason ?? null, lineTotal, seq]
      );

      if (qtyN > 0) {
        await client.query(
          `INSERT INTO momo_stocks (objid, wh_objid, item_objid, qty, update_date)
           VALUES ($1,$2,$3,$4,NOW())
           ON CONFLICT (wh_objid, item_objid) DO UPDATE SET qty = momo_stocks.qty + EXCLUDED.qty, update_date = NOW()`,
          [createObjectId(), whObjid, ln.itemObjid, qtyN]
        );
        await client.query(
          `INSERT INTO momo_stock_moves (objid, wh_objid, item_objid, move_type, qty, ref_type, ref_objid, regdate, regid)
           VALUES ($1,$2,$3,'IN',$4,'INBOUND',$5,NOW(),$6)`,
          [createObjectId(), whObjid, ln.itemObjid, qtyN, inboundObjid, adminId]
        );
      }
      if (procObjid) {
        await client.query(
          `UPDATE momo_procurement_items
             SET received_normal = COALESCE(received_normal,0) + $2,
                 received_defect = COALESCE(received_defect,0) + $3,
                 received_qty    = COALESCE(received_qty,0)    + $2 + $3
           WHERE proc_objid = $1 AND item_objid = $4`,
          [procObjid, qtyN, qtyD, ln.itemObjid]
        );
      }
      if (Number(ln.costPrice) > 0) {
        await client.query(`UPDATE momo_items SET cost_price = $2 WHERE objid = $1`, [ln.itemObjid, ln.costPrice]);
      }
    }

    // 매입발주 상태 갱신: 모두 입고 완료면 RECEIVED, 일부만이면 PARTIAL
    if (procObjid) {
      const status = await client.query(
        `SELECT
           COUNT(*) FILTER (WHERE COALESCE(received_qty,0) < qty) AS pending,
           COUNT(*) FILTER (WHERE COALESCE(received_qty,0) > 0)   AS started
         FROM momo_procurement_items
         WHERE proc_objid = $1`,
        [procObjid]
      );
      const pending = Number(status.rows[0].pending);
      const started = Number(status.rows[0].started);
      if (pending === 0) {
        await client.query(`UPDATE momo_procurements SET status='RECEIVED' WHERE objid=$1`, [procObjid]);
      } else if (started > 0) {
        await client.query(`UPDATE momo_procurements SET status='PARTIAL' WHERE objid=$1`, [procObjid]);
      }
    }

    await client.query("COMMIT");
    return NextResponse.json({ success: true, objId: inboundObjid, inboundNo });
  } catch (err) {
    await client.query("ROLLBACK");
    console.error("[inbound/save]", err);
    return NextResponse.json({ success: false, message: "입고 저장 오류" }, { status: 500 });
  } finally {
    client.release();
  }
}

async function genInboundNo(): Promise<string> {
  const today = new Date();
  const ymd = `${today.getFullYear()}${String(today.getMonth() + 1).padStart(2, "0")}${String(today.getDate()).padStart(2, "0")}`;
  const prefix = `INB-${ymd}-`;
  const row = await queryOne<{ MAX_NO: string }>(
    `SELECT COALESCE(MAX(inbound_no), '') AS "MAX_NO" FROM momo_inbounds WHERE inbound_no LIKE $1 || '%'`,
    [prefix]
  );
  const lastNum = row?.MAX_NO ? Number(row.MAX_NO.replace(prefix, "")) || 0 : 0;
  return prefix + String(lastNum + 1).padStart(4, "0");
}
