import { NextRequest, NextResponse } from "next/server";
import { execute, queryOne } from "@/lib/db";
import { createObjectId } from "@/lib/utils";
import { requireMomoAdmin } from "@/lib/momo-guard";
import { sendPush } from "@/lib/push";

interface SaleInfo {
  startTxt: string | null;   // 'YYYY-MM-DD HH:MM'
  endTxt: string | null;
  alwaysSale: boolean;       // 상시 판매 플래그
  sellable: boolean;         // 출고요청 노출 가능 (상시 OR 판매기간 안)
  orderableNow: boolean;     // 지금 출고요청 가능
}

// 품목의 판매 일정/상태 정보 (KST 기준). items/list 노출 규칙과 동일.
//   sellable = ACTIVE/비숨김/미삭제 AND (상시 OR 날짜 설정+마감 미경과)
async function getSaleInfo(objid: string): Promise<SaleInfo | null> {
  const row = await queryOne<{
    start_txt: string | null; end_txt: string | null; always_sale: string;
    sellable: boolean; orderable_now: boolean;
  }>(
    `SELECT
        TO_CHAR(sale_start_date, 'YYYY-MM-DD HH24:MI') AS start_txt,
        TO_CHAR(sale_end_date,   'YYYY-MM-DD HH24:MI') AS end_txt,
        COALESCE(is_always_sale,'N') AS always_sale,
        (
          COALESCE(is_del,'N') != 'Y'
          AND UPPER(COALESCE(status,'')) = 'ACTIVE'
          AND COALESCE(is_hidden,'N') != 'Y'
          AND (
            COALESCE(is_always_sale,'N') = 'Y'
            OR (
              (sale_start_date IS NOT NULL OR sale_end_date IS NOT NULL)
              AND (
                sale_end_date IS NULL
                OR (NOW() AT TIME ZONE 'Asia/Seoul') <= CASE
                  WHEN sale_end_date = date_trunc('day', sale_end_date)
                    THEN sale_end_date + INTERVAL '1 day' - INTERVAL '1 second'
                  ELSE sale_end_date
                END
              )
            )
          )
        ) AS sellable,
        (
          COALESCE(is_del,'N') != 'Y'
          AND UPPER(COALESCE(status,'')) = 'ACTIVE'
          AND COALESCE(is_hidden,'N') != 'Y'
          AND (
            COALESCE(is_always_sale,'N') = 'Y'
            OR (
              (sale_start_date IS NULL OR (NOW() AT TIME ZONE 'Asia/Seoul') >= sale_start_date)
              AND (
                sale_end_date IS NULL
                OR (NOW() AT TIME ZONE 'Asia/Seoul') <= CASE
                  WHEN sale_end_date = date_trunc('day', sale_end_date)
                    THEN sale_end_date + INTERVAL '1 day' - INTERVAL '1 second'
                  ELSE sale_end_date
                END
              )
              AND (sale_start_date IS NOT NULL OR sale_end_date IS NOT NULL)
            )
          )
        ) AS orderable_now
     FROM momo_items WHERE objid = $1`,
    [objid]
  );
  if (!row) return null;
  return {
    startTxt: row.start_txt, endTxt: row.end_txt,
    alwaysSale: row.always_sale === "Y",
    sellable: !!row.sellable, orderableNow: !!row.orderable_now,
  };
}

// 판매 일정 등록/변경 시 모든 구독자(거래처 + 관리자 본인 포함) 에게 푸시.
//   관리자 본인도 본인 변경분을 받아 새 상품 등록 사실/시점을 확인할 수 있게 함.
async function notifyItemSale(itemName: string, objid: string, info: SaleInfo) {
  try {
    const body = info.orderableNow
      ? itemName
      : `${itemName} (${info.startTxt ?? "곧"} 판매 예정)`;
    const res = await sendPush(
      { title: "새 상품이 등록되었습니다", body, url: "/m/orders/new", tag: `item-${objid}` }
    );
    console.log(`[items/save notify] item=${itemName} sent=${res.sent} failed=${res.failed}`);
  } catch (err) {
    console.error("[items/save notify]", err);
  }
}

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

  const body = await req.json();
  const {
    objid,
    actionType,
    itemName,
    itemDetail,
    makerObjid,
    unit,
    unitPrice,
    costPrice,
    isTaxFree,
    imageUrl,
    attributes,
    status,
    maxOrderQty,
    isHidden,
    requiresDelivery,
    vendorObjid,
    saleStartDate,
    saleEndDate,
    isAlwaysSale,
  } = body;
  const maxQty = maxOrderQty == null || maxOrderQty === "" ? null : Number(maxOrderQty);
  const hidden = isHidden === "Y" ? "Y" : "N";
  const reqDelivery = requiresDelivery === "Y" ? "Y" : "N";
  // 상시 판매 체크 시 날짜는 강제로 비움 (상시 == 항상 노출).
  const alwaysSale = isAlwaysSale === "Y" ? "Y" : "N";
  const saleStart = alwaysSale === "Y" ? null
    : (saleStartDate && String(saleStartDate).trim() !== "" ? saleStartDate : null);
  const saleEnd   = alwaysSale === "Y" ? null
    : (saleEndDate   && String(saleEndDate).trim()   !== "" ? saleEndDate   : null);

  if (!itemName) {
    return NextResponse.json({ success: false, message: "품목명은 필수입니다." }, { status: 400 });
  }

  // 품목명 앞의 'M' / 'M ' 접두는 자동 제거 (면세 표시는 is_tax_free 컬럼에서 관리)
  const cleanName = String(itemName).replace(/^M\s+/, "").trim();

  // 면세 여부는 사용자 명시 선택 그대로 사용 (자동 추론 X)
  const taxFree = isTaxFree === "Y" ? "Y" : "N";

  if (actionType === "regist") {
    const newId = createObjectId();
    const itemCode = await genItemCode();
    await execute(
      `INSERT INTO momo_items (
         objid, item_code, item_name, item_detail, maker_objid, vendor_objid,
         unit, unit_price, cost_price, is_tax_free, image_url, attributes, status,
         max_order_qty, is_hidden, requires_delivery,
         sale_start_date, sale_end_date, is_always_sale,
         is_del, regdate, regid
       ) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12::jsonb,$13,$14,$15,$16,$18::timestamp,$19::timestamp,$20,'N',NOW(),$17)`,
      [newId, itemCode, cleanName, itemDetail ?? null, makerObjid ?? null, vendorObjid ?? null,
       unit ?? "EA", Number(unitPrice ?? 0), Number(costPrice ?? 0),
       taxFree, imageUrl ?? null,
       attributes ? JSON.stringify(attributes) : null,
       status ?? "ACTIVE",
       maxQty, hidden, reqDelivery,
       userId, saleStart, saleEnd, alwaysSale]
    );
    // 신규 등록 품목에 판매 일정(현재/미래)이 잡혀 있으면 일반 사용자에게 알림
    const newInfo = await getSaleInfo(newId);
    if (newInfo?.sellable) await notifyItemSale(cleanName, newId, newInfo);
    return NextResponse.json({ success: true, objId: newId, itemCode });
  }

  if (!objid) return NextResponse.json({ success: false, message: "objid 누락" }, { status: 400 });
  // 수정 전 판매 일정 — 날짜가 바뀐 경우에만 알림 판단
  const beforeInfo = await getSaleInfo(objid);
  await execute(
    `UPDATE momo_items SET
       item_name=$2, item_detail=$3, maker_objid=$4, unit=$5,
       unit_price=$6, cost_price=$7, is_tax_free=$8, image_url=$9,
       attributes=$10::jsonb, status=$11,
       max_order_qty=$12, is_hidden=$13, requires_delivery=$14,
       vendor_objid=$15,
       sale_start_date=$17::timestamp, sale_end_date=$18::timestamp,
       is_always_sale=$19,
       update_date=NOW(), update_id=$16
     WHERE objid=$1`,
    [objid, cleanName, itemDetail ?? null, makerObjid ?? null, unit ?? "EA",
     Number(unitPrice ?? 0), Number(costPrice ?? 0),
     taxFree, imageUrl ?? null,
     attributes ? JSON.stringify(attributes) : null,
     status ?? "ACTIVE",
     maxQty, hidden, reqDelivery,
     vendorObjid ?? null,
     userId, saleStart, saleEnd, alwaysSale]
  );
  // 판매 일정(시작/마감) 또는 상시 플래그가 바뀌었고, 바뀐 결과가 출고요청 노출 대상(sellable)이면 알림.
  //   단가/이미지 등만 수정(노출 조건 동일)이거나, 마감 지난 날짜로 바뀐 경우는 알림 안 함.
  const afterInfo = await getSaleInfo(objid);
  const datesChanged =
    (beforeInfo?.startTxt ?? null) !== (afterInfo?.startTxt ?? null) ||
    (beforeInfo?.endTxt ?? null)   !== (afterInfo?.endTxt ?? null) ||
    (beforeInfo?.alwaysSale ?? false) !== (afterInfo?.alwaysSale ?? false);
  console.log(`[items/save] update item=${cleanName} objid=${objid} datesChanged=${datesChanged} sellable=${afterInfo?.sellable} alwaysSale=${afterInfo?.alwaysSale} startBefore="${beforeInfo?.startTxt ?? ""}" startAfter="${afterInfo?.startTxt ?? ""}" endBefore="${beforeInfo?.endTxt ?? ""}" endAfter="${afterInfo?.endTxt ?? ""}"`);
  if (datesChanged && afterInfo?.sellable) {
    await notifyItemSale(cleanName, objid, afterInfo);
  } else {
    console.log(`[items/save] notify SKIPPED — datesChanged=${datesChanged} sellable=${afterInfo?.sellable}`);
  }
  return NextResponse.json({ success: true, objId: objid });
}

async function genItemCode(): 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 = `ITM-${ymd}-`;
  const row = await queryOne<{ MAX_NO: string }>(
    `SELECT COALESCE(MAX(item_code), '') AS "MAX_NO" FROM momo_items WHERE item_code LIKE $1 || '%'`,
    [prefix]
  );
  const last = row?.MAX_NO ?? "";
  const lastNum = last ? Number(last.replace(prefix, "")) || 0 : 0;
  return prefix + String(lastNum + 1).padStart(4, "0");
}
