/**
 * 입고관리 컨트롤러
 *
 * 입고유형별 소스 테이블:
 *  - 구매입고 → purchase_order_mng (발주 헤더) + purchase_detail (발주 디테일)
 *  - 반품입고 → shipment_instruction + shipment_instruction_detail (출하)
 *  - 기타입고 → item_info (품목)
 */

import { Response } from "express";
import { AuthenticatedRequest } from "../types/auth";
import { getPool } from "../database/db";
import { logger } from "../utils/logger";

// 입고 목록 조회 (헤더-디테일 JOIN, 레거시 호환)
export async function getList(req: AuthenticatedRequest, res: Response) {
  try {
    const companyCode = req.user!.companyCode;
    const {
      inbound_type,
      inbound_status,
      search_keyword,
      date_from,
      date_to,
    } = req.query;

    const conditions: string[] = [];
    const params: any[] = [];
    let paramIdx = 1;

    if (companyCode === "*") {
      // 최고 관리자: 전체 조회
    } else {
      conditions.push(`im.company_code = $${paramIdx}`);
      params.push(companyCode);
      paramIdx++;
    }

    if (inbound_type && inbound_type !== "all") {
      conditions.push(`im.inbound_type = $${paramIdx}`);
      params.push(inbound_type);
      paramIdx++;
    }

    if (inbound_status && inbound_status !== "all") {
      conditions.push(`im.inbound_status = $${paramIdx}`);
      params.push(inbound_status);
      paramIdx++;
    }

    if (search_keyword) {
      conditions.push(
        `(im.inbound_number ILIKE $${paramIdx} OR COALESCE(id.item_name, im.item_name) ILIKE $${paramIdx} OR COALESCE(id.item_number, im.item_number) ILIKE $${paramIdx} OR COALESCE(id.supplier_name, im.supplier_name) ILIKE $${paramIdx} OR COALESCE(id.reference_number, im.reference_number) ILIKE $${paramIdx})`
      );
      params.push(`%${search_keyword}%`);
      paramIdx++;
    }

    if (date_from) {
      conditions.push(`im.inbound_date >= $${paramIdx}::date`);
      params.push(date_from);
      paramIdx++;
    }
    if (date_to) {
      conditions.push(`im.inbound_date <= $${paramIdx}::date`);
      params.push(date_to);
      paramIdx++;
    }

    const whereClause =
      conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";

    const query = `
      SELECT
        im.id, im.company_code, im.inbound_number, im.inbound_type, im.inbound_date,
        im.warehouse_code, im.location_code, im.inspector, im.manager,
        im.inbound_status, im.memo AS header_memo, im.source_table, im.source_id,
        im.created_date, im.created_by, im.updated_date, im.updated_by,
        im.writer, im.status, im.prev_inbound_qty, im.remark,
        COALESCE(id.reference_number, im.reference_number) AS reference_number,
        COALESCE(id.supplier_code, im.supplier_code) AS supplier_code,
        COALESCE(id.supplier_name, im.supplier_name) AS supplier_name,
        COALESCE(id.item_number, im.item_number) AS item_number,
        COALESCE(id.item_name, im.item_name) AS item_name,
        COALESCE(id.spec, im.spec) AS spec,
        COALESCE(id.material, im.material) AS material,
        COALESCE(id.unit, im.unit) AS unit,
        COALESCE(id.inbound_qty, im.inbound_qty) AS inbound_qty,
        COALESCE(id.unit_price, im.unit_price) AS unit_price,
        COALESCE(id.total_amount, im.total_amount) AS total_amount,
        COALESCE(id.lot_number, im.lot_number) AS lot_number,
        COALESCE(id.inspection_status, im.inspection_status) AS inspection_status,
        COALESCE(id.memo, im.memo) AS memo,
        id.id AS detail_id,
        id.seq_no,
        id.inbound_type AS detail_inbound_type,
        wh.warehouse_name
      FROM inbound_mng im
      LEFT JOIN inbound_detail id
        ON id.inbound_id = im.inbound_number AND id.company_code = im.company_code
      LEFT JOIN warehouse_info wh
        ON im.warehouse_code = wh.warehouse_code
        AND im.company_code = wh.company_code
      ${whereClause}
      ORDER BY im.created_date DESC, id.seq_no ASC
    `;

    const pool = getPool();
    const result = await pool.query(query, params);

    logger.info("입고 목록 조회", {
      companyCode,
      rowCount: result.rowCount,
    });

    return res.json({ success: true, data: result.rows });
  } catch (error: any) {
    logger.error("입고 목록 조회 실패", { error: error.message });
    return res.status(500).json({ success: false, message: error.message });
  }
}

// 입고 등록 (헤더 1건 + 디테일 N건)
export async function create(req: AuthenticatedRequest, res: Response) {
  const pool = getPool();
  const client = await pool.connect();

  try {
    const companyCode = req.user!.companyCode;
    const userId = req.user!.userId;
    const { items, inbound_number, inbound_date, warehouse_code, location_code, inspector, manager, memo } = req.body;

    if (!items || !Array.isArray(items) || items.length === 0) {
      return res.status(400).json({ success: false, message: "입고 품목이 없습니다." });
    }

    // 첫 번째 아이템에서 inbound_type 추출 (헤더용)
    const inboundType = items[0].inbound_type || null;
    const inboundNumber = inbound_number || items[0].inbound_number;

    await client.query("BEGIN");

    // 1. 헤더 INSERT (inbound_mng) — 품목 컬럼은 NULL
    const headerResult = await client.query(
      `INSERT INTO inbound_mng (
        id, company_code, inbound_number, inbound_type, inbound_date,
        warehouse_code, location_code,
        inbound_status, inspector, manager, memo,
        created_date, created_by, writer, status
      ) VALUES (
        gen_random_uuid()::text, $1, $2, $3, $4::date,
        $5, $6,
        $7, $8, $9, $10,
        NOW(), $11, $11, '입고'
      ) RETURNING *`,
      [
        companyCode,
        inboundNumber,
        inboundType,
        inbound_date || items[0].inbound_date,
        warehouse_code || items[0].warehouse_code || null,
        location_code || items[0].location_code || null,
        items[0].inbound_status || "대기",
        inspector || items[0].inspector || null,
        manager || items[0].manager || null,
        memo || items[0].memo || null,
        userId,
      ]
    );

    const headerRow = headerResult.rows[0];
    const insertedDetails: any[] = [];

    // 2. 디테일 INSERT (inbound_detail) + 재고/발주 업데이트
    for (let i = 0; i < items.length; i++) {
      const item = items[i];
      const seqNo = i + 1;

      // 2a. inbound_detail INSERT
      const detailResult = await client.query(
        `INSERT INTO inbound_detail (
          id, company_code, inbound_id, seq_no, inbound_type,
          item_number, item_name, spec, material, unit,
          inbound_qty, unit_price, total_amount,
          lot_number, reference_number, supplier_code, supplier_name,
          inspection_status, memo, item_id,
          created_date, created_by, writer, status
        ) VALUES (
          gen_random_uuid()::text, $1, $2, $3, $4,
          $5, $6, $7, $8, $9,
          $10, $11, $12,
          $13, $14, $15, $16,
          $17, $18, $19,
          NOW(), $20, $20, '입고'
        ) RETURNING *`,
        [
          companyCode,
          inboundNumber,
          seqNo,
          item.inbound_type || inboundType,
          item.item_number || null,
          item.item_name || null,
          item.spec || null,
          item.material || null,
          item.unit || "EA",
          item.inbound_qty || 0,
          item.unit_price || 0,
          item.total_amount || 0,
          item.lot_number || null,
          item.reference_number || null,
          item.supplier_code || null,
          item.supplier_name || null,
          item.inspection_status || "대기",
          item.memo || null,
          item.item_id || null,
          userId,
        ]
      );

      insertedDetails.push(detailResult.rows[0]);

      // 2b. 재고 업데이트 (inventory_stock): 입고 수량 증가 — 기존 로직 유지
      const itemCode = item.item_number || null;
      const whCode = warehouse_code || item.warehouse_code || null;
      const locCode = location_code || item.location_code || null;
      const inQty = Number(item.inbound_qty) || 0;
      if (itemCode && inQty > 0) {
        const existingStock = await client.query(
          `SELECT id FROM inventory_stock
           WHERE company_code = $1 AND item_code = $2
             AND COALESCE(warehouse_code, '') = COALESCE($3, '')
             AND COALESCE(location_code, '') = COALESCE($4, '')
           LIMIT 1`,
          [companyCode, itemCode, whCode || '', locCode || '']
        );

        if (existingStock.rows.length > 0) {
          await client.query(
            `UPDATE inventory_stock
             SET current_qty = CAST(COALESCE(CAST(NULLIF(current_qty, '') AS numeric), 0) + $1 AS text),
                 last_in_date = NOW(),
                 updated_date = NOW()
             WHERE id = $2`,
            [inQty, existingStock.rows[0].id]
          );
        } else {
          await client.query(
            `INSERT INTO inventory_stock (
              id, company_code, item_code, warehouse_code, location_code,
              current_qty, safety_qty, last_in_date,
              created_date, updated_date, writer
            ) VALUES (gen_random_uuid()::text, $1, $2, $3, $4, $5, '0', NOW(), NOW(), NOW(), $6)`,
            [companyCode, itemCode, whCode, locCode, String(inQty), userId]
          );
        }
      }

      // 2c. 구매입고인 경우 발주의 received_qty 업데이트 — 기존 로직 유지
      if (item.inbound_type === "구매입고" && item.source_id && item.source_table === "purchase_order_mng") {
        await client.query(
          `UPDATE purchase_order_mng
           SET received_qty = CAST(
             COALESCE(CAST(NULLIF(received_qty, '') AS numeric), 0) + $1 AS text
           ),
           remain_qty = CAST(
             GREATEST(COALESCE(CAST(NULLIF(order_qty, '') AS numeric), 0)
               - COALESCE(CAST(NULLIF(received_qty, '') AS numeric), 0) - $1, 0) AS text
           ),
           status = CASE
             WHEN COALESCE(CAST(NULLIF(received_qty, '') AS numeric), 0) + $1
               >= COALESCE(CAST(NULLIF(order_qty, '') AS numeric), 0)
             THEN '입고완료'
             ELSE '부분입고'
           END,
           updated_date = NOW()
           WHERE id = $2 AND company_code = $3`,
          [item.inbound_qty || 0, item.source_id, companyCode]
        );
      }

      // 구매입고인 경우 purchase_detail 품목별 입고수량 업데이트
      if (item.inbound_type === "구매입고" && item.source_id && item.source_table === "purchase_detail") {
        // 1. 해당 purchase_detail의 received_qty 누적 업데이트
        await client.query(
          `UPDATE purchase_detail SET
            received_qty = CAST(
              COALESCE(CAST(NULLIF(received_qty, '') AS numeric), 0) + $1 AS text
            ),
            balance_qty = CAST(
              COALESCE(CAST(NULLIF(order_qty, '') AS numeric), 0)
              - COALESCE(CAST(NULLIF(received_qty, '') AS numeric), 0)
              - $1 AS text
            ),
            updated_date = NOW()
           WHERE id = $2 AND company_code = $3`,
          [item.inbound_qty || 0, item.source_id, companyCode]
        );

        // 2. 발주 헤더 상태 업데이트
        const detailInfo = await client.query(
          `SELECT purchase_no FROM purchase_detail WHERE id = $1 AND company_code = $2`,
          [item.source_id, companyCode]
        );
        if (detailInfo.rows.length > 0) {
          const purchaseNo = detailInfo.rows[0].purchase_no;
          // 잔량 있는 디테일이 있는지 확인
          const unreceived = await client.query(
            `SELECT id FROM purchase_detail
             WHERE purchase_no = $1 AND company_code = $2
               AND COALESCE(CAST(NULLIF(order_qty, '') AS numeric), 0)
                 - COALESCE(CAST(NULLIF(received_qty, '') AS numeric), 0) > 0
             LIMIT 1`,
            [purchaseNo, companyCode]
          );
          const newStatus = unreceived.rows.length === 0 ? '입고완료' : '부분입고';
          await client.query(
            `UPDATE purchase_order_mng SET status = $1, updated_date = NOW()
             WHERE purchase_no = $2 AND company_code = $3`,
            [newStatus, purchaseNo, companyCode]
          );
        }
      }
    }

    await client.query("COMMIT");

    logger.info("입고 등록 완료", {
      companyCode,
      userId,
      headerCount: 1,
      detailCount: insertedDetails.length,
      inbound_number: inboundNumber,
    });

    return res.json({
      success: true,
      data: { header: headerRow, details: insertedDetails },
      message: `${insertedDetails.length}건 입고 등록 완료`,
    });
  } catch (error: any) {
    await client.query("ROLLBACK");
    logger.error("입고 등록 실패", { error: error.message });
    return res.status(500).json({ success: false, message: error.message });
  } finally {
    client.release();
  }
}

// 입고 수정 (헤더 + 디테일 분리 업데이트)
export async function update(req: AuthenticatedRequest, res: Response) {
  const pool = getPool();
  const client = await pool.connect();

  try {
    const companyCode = req.user!.companyCode;
    const userId = req.user!.userId;
    const { id } = req.params;
    const {
      inbound_date, inbound_qty, unit_price, total_amount,
      lot_number, warehouse_code, location_code,
      inbound_status, inspection_status,
      inspector, manager: mgr, memo,
      detail_id,
    } = req.body;

    await client.query("BEGIN");

    // 헤더 업데이트 (inbound_mng) — 헤더 레벨 필드만
    const headerResult = await client.query(
      `UPDATE inbound_mng SET
        inbound_date = COALESCE($1::date, inbound_date),
        warehouse_code = COALESCE($2, warehouse_code),
        location_code = COALESCE($3, location_code),
        inbound_status = COALESCE($4, inbound_status),
        inspector = COALESCE($5, inspector),
        manager = COALESCE($6, manager),
        memo = COALESCE($7, memo),
        updated_date = NOW(),
        updated_by = $8
      WHERE id = $9 AND company_code = $10
      RETURNING *`,
      [
        inbound_date, warehouse_code, location_code,
        inbound_status, inspector, mgr, memo,
        userId, id, companyCode,
      ]
    );

    if (headerResult.rowCount === 0) {
      await client.query("ROLLBACK");
      return res.status(404).json({ success: false, message: "입고 데이터를 찾을 수 없습니다." });
    }

    // 디테일 업데이트 (inbound_detail) — detail_id가 있으면 디테일 레벨 필드 업데이트
    let detailRow = null;
    if (detail_id) {
      const detailResult = await client.query(
        `UPDATE inbound_detail SET
          inbound_qty = COALESCE($1, inbound_qty),
          unit_price = COALESCE($2, unit_price),
          total_amount = COALESCE($3, total_amount),
          lot_number = COALESCE($4, lot_number),
          inspection_status = COALESCE($5, inspection_status),
          memo = COALESCE($6, memo),
          updated_date = NOW(),
          updated_by = $7
        WHERE id = $8 AND company_code = $9
        RETURNING *`,
        [
          inbound_qty, unit_price, total_amount,
          lot_number, inspection_status, memo,
          userId, detail_id, companyCode,
        ]
      );
      detailRow = detailResult.rows[0] || null;
    } else {
      // 레거시 데이터: detail_id 없이 inbound_mng 자체에 품목 정보 업데이트
      await client.query(
        `UPDATE inbound_mng SET
          inbound_qty = COALESCE($1, inbound_qty),
          unit_price = COALESCE($2, unit_price),
          total_amount = COALESCE($3, total_amount),
          lot_number = COALESCE($4, lot_number),
          inspection_status = COALESCE($5, inspection_status)
        WHERE id = $6 AND company_code = $7`,
        [
          inbound_qty, unit_price, total_amount,
          lot_number, inspection_status,
          id, companyCode,
        ]
      );
    }

    await client.query("COMMIT");

    logger.info("입고 수정", { companyCode, userId, id, detail_id });

    return res.json({
      success: true,
      data: { header: headerResult.rows[0], detail: detailRow },
    });
  } catch (error: any) {
    await client.query("ROLLBACK");
    logger.error("입고 수정 실패", { error: error.message });
    return res.status(500).json({ success: false, message: error.message });
  } finally {
    client.release();
  }
}

// 입고 삭제 (헤더 + 디테일, 재고/발주 롤백 포함)
export async function deleteReceiving(req: AuthenticatedRequest, res: Response) {
  const pool = getPool();
  const client = await pool.connect();

  try {
    const companyCode = req.user!.companyCode;
    const { id } = req.params;

    await client.query("BEGIN");

    // 헤더 정보 조회 (inbound_number, warehouse_code 등)
    const headerResult = await client.query(
      `SELECT * FROM inbound_mng WHERE id = $1 AND company_code = $2`,
      [id, companyCode]
    );

    if (headerResult.rowCount === 0) {
      await client.query("ROLLBACK");
      return res.status(404).json({ success: false, message: "데이터를 찾을 수 없습니다." });
    }

    const header = headerResult.rows[0];
    const inboundNumber = header.inbound_number;

    // 디테일 조회 (재고/발주 롤백용)
    const detailResult = await client.query(
      `SELECT * FROM inbound_detail WHERE inbound_id = $1 AND company_code = $2`,
      [inboundNumber, companyCode]
    );

    // 디테일이 있으면 디테일 기반으로 롤백, 없으면 헤더(레거시) 기반으로 롤백
    const rollbackItems = detailResult.rows.length > 0
      ? detailResult.rows.map((d: any) => ({
          item_number: d.item_number,
          inbound_qty: d.inbound_qty,
          inbound_type: d.inbound_type || header.inbound_type,
          source_table: header.source_table,
          source_id: header.source_id,
        }))
      : [{
          item_number: header.item_number,
          inbound_qty: header.inbound_qty,
          inbound_type: header.inbound_type,
          source_table: header.source_table,
          source_id: header.source_id,
        }];

    const whCode = header.warehouse_code || null;
    const locCode = header.location_code || null;

    for (const item of rollbackItems) {
      const itemCode = item.item_number || null;
      const inQty = Number(item.inbound_qty) || 0;

      // 재고 롤백: 입고 수량만큼 차감
      if (itemCode && inQty > 0) {
        await client.query(
          `UPDATE inventory_stock
           SET current_qty = CAST(
             GREATEST(COALESCE(CAST(NULLIF(current_qty, '') AS numeric), 0) - $1, 0) AS text
           ),
           updated_date = NOW()
           WHERE company_code = $2 AND item_code = $3
             AND COALESCE(warehouse_code, '') = COALESCE($4, '')
             AND COALESCE(location_code, '') = COALESCE($5, '')`,
          [inQty, companyCode, itemCode, whCode || '', locCode || '']
        );
      }

      // 구매입고 발주 롤백: purchase_order_mng 기반
      if (item.inbound_type === "구매입고" && item.source_id && item.source_table === "purchase_order_mng") {
        await client.query(
          `UPDATE purchase_order_mng
           SET received_qty = CAST(
             GREATEST(COALESCE(CAST(NULLIF(received_qty, '') AS numeric), 0) - $1, 0) AS text
           ),
           remain_qty = CAST(
             COALESCE(CAST(NULLIF(order_qty, '') AS numeric), 0)
             - GREATEST(COALESCE(CAST(NULLIF(received_qty, '') AS numeric), 0) - $1, 0) AS text
           ),
           status = CASE
             WHEN GREATEST(COALESCE(CAST(NULLIF(received_qty, '') AS numeric), 0) - $1, 0) <= 0
             THEN '발주확정'
             ELSE '부분입고'
           END,
           updated_date = NOW()
           WHERE id = $2 AND company_code = $3`,
          [inQty, item.source_id, companyCode]
        );
      }

      // 구매입고 발주 롤백: purchase_detail 기반
      if (item.inbound_type === "구매입고" && item.source_id && item.source_table === "purchase_detail") {
        const detailInfo = await client.query(
          `SELECT purchase_no FROM purchase_detail WHERE id = $1 AND company_code = $2`,
          [item.source_id, companyCode]
        );
        if (detailInfo.rows.length > 0) {
          const purchaseNo = detailInfo.rows[0].purchase_no;
          // 삭제 후 재계산을 위해 현재 입고 건 제외한 미입고 확인
          const unreceived = await client.query(
            `SELECT pd.id
             FROM purchase_detail pd
             LEFT JOIN (
               SELECT source_id, SUM(COALESCE(inbound_qty, 0)) AS total_received
               FROM inbound_mng
               WHERE source_table = 'purchase_detail' AND company_code = $1
                 AND inbound_number != $3
               GROUP BY source_id
             ) r ON r.source_id = pd.id
             WHERE pd.purchase_no = $2 AND pd.company_code = $1
               AND COALESCE(CAST(NULLIF(pd.order_qty, '') AS numeric), 0) - COALESCE(r.total_received, 0) > 0
             LIMIT 1`,
            [companyCode, purchaseNo, inboundNumber]
          );
          // 잔량 있으면 부분입고, 전량 미입고면 발주확정
          const hasAnyReceived = await client.query(
            `SELECT 1 FROM inbound_mng
             WHERE source_table = 'purchase_detail' AND company_code = $1
               AND inbound_number != $2
             LIMIT 1`,
            [companyCode, inboundNumber]
          );
          const newStatus = hasAnyReceived.rows.length > 0
            ? (unreceived.rows.length === 0 ? '입고완료' : '부분입고')
            : '발주확정';
          await client.query(
            `UPDATE purchase_order_mng SET status = $1, updated_date = NOW()
             WHERE purchase_no = $2 AND company_code = $3`,
            [newStatus, purchaseNo, companyCode]
          );
        }
      }
    }

    // 디테일 삭제
    await client.query(
      `DELETE FROM inbound_detail WHERE inbound_id = $1 AND company_code = $2`,
      [inboundNumber, companyCode]
    );

    // 헤더 삭제
    await client.query(
      `DELETE FROM inbound_mng WHERE id = $1 AND company_code = $2`,
      [id, companyCode]
    );

    await client.query("COMMIT");

    logger.info("입고 삭제", { companyCode, id, inboundNumber });

    return res.json({ success: true, message: "삭제 완료" });
  } catch (error: any) {
    await client.query("ROLLBACK");
    logger.error("입고 삭제 실패", { error: error.message });
    return res.status(500).json({ success: false, message: error.message });
  } finally {
    client.release();
  }
}

// 구매입고용: 발주 데이터 조회 (미입고분) - 신규 헤더-디테일 구조 + 레거시 단일 테이블 UNION ALL
export async function getPurchaseOrders(req: AuthenticatedRequest, res: Response) {
  try {
    const companyCode = req.user!.companyCode;
    const { keyword, page, pageSize } = req.query;
    const currentPage = Math.max(1, Number(page) || 1);
    const limit = Math.min(500, Math.max(1, Number(pageSize) || 20));
    const offset = (currentPage - 1) * limit;

    const params: any[] = [companyCode];
    let paramIdx = 2;

    let keywordConditionDetail = "";
    let keywordConditionLegacy = "";
    if (keyword) {
      keywordConditionDetail = `AND (pd.purchase_no ILIKE $${paramIdx} OR COALESCE(NULLIF(pd.item_name, ''), ii.item_name) ILIKE $${paramIdx} OR COALESCE(NULLIF(pd.item_code, ''), ii.item_number) ILIKE $${paramIdx} OR COALESCE(pd.supplier_name, po.supplier_name) ILIKE $${paramIdx})`;
      keywordConditionLegacy = `AND (po.purchase_no ILIKE $${paramIdx} OR po.item_name ILIKE $${paramIdx} OR po.item_code ILIKE $${paramIdx} OR po.supplier_name ILIKE $${paramIdx})`;
      params.push(`%${keyword}%`);
      paramIdx++;
    }

    const baseQuery = `
      WITH combined AS (
        -- 디테일 기반 발주 데이터 (purchase_detail.received_qty로 잔량 계산)
        SELECT
          pd.id,
          COALESCE(po.purchase_no, pd.purchase_no) AS purchase_no,
          po.order_date,
          COALESCE(pd.supplier_code, po.supplier_code) AS supplier_code,
          COALESCE(pd.supplier_name, po.supplier_name) AS supplier_name,
          COALESCE(NULLIF(pd.item_code, ''), ii.item_number) AS item_code,
          COALESCE(NULLIF(pd.item_name, ''), ii.item_name) AS item_name,
          COALESCE(NULLIF(pd.spec, ''), ii.size) AS spec,
          COALESCE(NULLIF(pd.material, ''), ii.material) AS material,
          COALESCE(CAST(NULLIF(pd.order_qty, '') AS numeric), 0) AS order_qty,
          COALESCE(CAST(NULLIF(pd.received_qty, '') AS numeric), 0) AS received_qty,
          COALESCE(CAST(NULLIF(pd.order_qty, '') AS numeric), 0) - COALESCE(CAST(NULLIF(pd.received_qty, '') AS numeric), 0) AS remain_qty,
          COALESCE(CAST(NULLIF(pd.unit_price, '') AS numeric), 0) AS unit_price,
          COALESCE(po.status, '') AS status,
          COALESCE(pd.due_date, po.due_date) AS due_date,
          'purchase_detail' AS source_table
        FROM purchase_detail pd
        LEFT JOIN purchase_order_mng po
          ON pd.purchase_no = po.purchase_no AND pd.company_code = po.company_code
        LEFT JOIN item_info ii ON pd.item_id = ii.id
        WHERE pd.company_code = $1
          AND COALESCE(CAST(NULLIF(pd.order_qty, '') AS numeric), 0) - COALESCE(CAST(NULLIF(pd.received_qty, '') AS numeric), 0) > 0
          AND COALESCE(pd.approval_status, '') NOT IN ('반려')
          AND COALESCE(po.status, '') NOT IN ('입고완료', '취소')
          ${keywordConditionDetail}

        UNION ALL

        -- 레거시 단일 테이블 데이터 (purchase_detail에 없는 발주)
        SELECT
          po.id,
          po.purchase_no,
          po.order_date,
          po.supplier_code,
          po.supplier_name,
          po.item_code,
          po.item_name,
          po.spec,
          po.material,
          COALESCE(CAST(NULLIF(po.order_qty, '') AS numeric), 0) AS order_qty,
          COALESCE(CAST(NULLIF(po.received_qty, '') AS numeric), 0) AS received_qty,
          COALESCE(CAST(NULLIF(po.remain_qty, '') AS numeric),
            COALESCE(CAST(NULLIF(po.order_qty, '') AS numeric), 0)
            - COALESCE(CAST(NULLIF(po.received_qty, '') AS numeric), 0)
          ) AS remain_qty,
          COALESCE(CAST(NULLIF(po.unit_price, '') AS numeric), 0) AS unit_price,
          po.status,
          po.due_date,
          'purchase_order_mng' AS source_table
        FROM purchase_order_mng po
        WHERE po.company_code = $1
          AND NOT EXISTS (
            SELECT 1 FROM purchase_detail pd
            WHERE pd.purchase_no = po.purchase_no AND pd.company_code = po.company_code
          )
          AND COALESCE(CAST(NULLIF(po.remain_qty, '') AS numeric),
            COALESCE(CAST(NULLIF(po.order_qty, '') AS numeric), 0)
            - COALESCE(CAST(NULLIF(po.received_qty, '') AS numeric), 0)
          ) > 0
          AND po.status NOT IN ('입고완료', '취소')
          ${keywordConditionLegacy}
      )`;

    const pool = getPool();

    const countResult = await pool.query(
      `${baseQuery} SELECT COUNT(*) AS total FROM combined`,
      params
    );
    const totalCount = parseInt(countResult.rows[0].total, 10);

    const dataResult = await pool.query(
      `${baseQuery} SELECT * FROM combined ORDER BY order_date DESC, purchase_no LIMIT ${limit} OFFSET ${offset}`,
      params
    );

    return res.json({ success: true, data: dataResult.rows, totalCount });
  } catch (error: any) {
    logger.error("발주 데이터 조회 실패", { error: error.message });
    return res.status(500).json({ success: false, message: error.message });
  }
}

// 반품입고용: 출하 데이터 조회
export async function getShipments(req: AuthenticatedRequest, res: Response) {
  try {
    const companyCode = req.user!.companyCode;
    const { keyword, page, pageSize } = req.query;
    const currentPage = Math.max(1, Number(page) || 1);
    const limit = Math.min(500, Math.max(1, Number(pageSize) || 20));
    const offset = (currentPage - 1) * limit;

    const conditions: string[] = ["si.company_code = $1"];
    const params: any[] = [companyCode];
    let paramIdx = 2;

    if (keyword) {
      conditions.push(
        `(si.instruction_no ILIKE $${paramIdx} OR sid.item_name ILIKE $${paramIdx} OR sid.item_code ILIKE $${paramIdx})`
      );
      params.push(`%${keyword}%`);
      paramIdx++;
    }

    const whereClause = conditions.join(" AND ");
    const pool = getPool();

    const countResult = await pool.query(
      `SELECT COUNT(*) AS total
       FROM shipment_instruction si
       JOIN shipment_instruction_detail sid
         ON si.id = sid.instruction_id AND si.company_code = sid.company_code
       WHERE ${whereClause}`,
      params
    );
    const totalCount = parseInt(countResult.rows[0].total, 10);

    const dataResult = await pool.query(
      `SELECT
        sid.id AS detail_id,
        si.id AS instruction_id,
        si.instruction_no,
        si.instruction_date,
        si.partner_id,
        si.status AS instruction_status,
        sid.item_code,
        sid.item_name,
        sid.spec,
        sid.material,
        COALESCE(sid.ship_qty, 0) AS ship_qty,
        COALESCE(sid.order_qty, 0) AS order_qty,
        sid.source_type
      FROM shipment_instruction si
      JOIN shipment_instruction_detail sid
        ON si.id = sid.instruction_id
        AND si.company_code = sid.company_code
      WHERE ${whereClause}
      ORDER BY si.instruction_date DESC, si.instruction_no
      LIMIT ${limit} OFFSET ${offset}`,
      params
    );

    return res.json({ success: true, data: dataResult.rows, totalCount });
  } catch (error: any) {
    logger.error("출하 데이터 조회 실패", { error: error.message });
    return res.status(500).json({ success: false, message: error.message });
  }
}

// 기타입고용: 품목 데이터 조회
export async function getItems(req: AuthenticatedRequest, res: Response) {
  try {
    const companyCode = req.user!.companyCode;
    const { keyword, page, pageSize, division } = req.query;
    const currentPage = Math.max(1, Number(page) || 1);
    const limit = Math.min(500, Math.max(1, Number(pageSize) || 20));
    const offset = (currentPage - 1) * limit;

    const conditions: string[] = ["company_code = $1"];
    const params: any[] = [companyCode];
    let paramIdx = 2;

    if (keyword) {
      conditions.push(
        `(item_number ILIKE $${paramIdx} OR item_name ILIKE $${paramIdx})`
      );
      params.push(`%${keyword}%`);
      paramIdx++;
    }

    if (division) {
      conditions.push(`division ILIKE $${paramIdx}`);
      params.push(`%${division}%`);
      paramIdx++;
    }

    const whereClause = conditions.join(" AND ");
    const pool = getPool();

    const countResult = await pool.query(
      `SELECT COUNT(*) AS total FROM item_info WHERE ${whereClause}`,
      params
    );
    const totalCount = parseInt(countResult.rows[0].total, 10);

    const dataResult = await pool.query(
      `SELECT
        id, item_number, item_name, size AS spec, material, unit,
        COALESCE(CAST(NULLIF(standard_price, '') AS numeric), 0) AS standard_price
      FROM item_info
      WHERE ${whereClause}
      ORDER BY item_name
      LIMIT ${limit} OFFSET ${offset}`,
      params
    );

    return res.json({ success: true, data: dataResult.rows, totalCount });
  } catch (error: any) {
    logger.error("품목 데이터 조회 실패", { error: error.message });
    return res.status(500).json({ success: false, message: error.message });
  }
}

// 입고번호 자동생성
export async function generateNumber(req: AuthenticatedRequest, res: Response) {
  try {
    const companyCode = req.user!.companyCode;
    const pool = getPool();

    const today = new Date();
    const yyyy = today.getFullYear();
    const prefix = `RCV-${yyyy}-`;

    const result = await pool.query(
      `SELECT inbound_number FROM inbound_mng
       WHERE company_code = $1 AND inbound_number LIKE $2
       ORDER BY inbound_number DESC LIMIT 1`,
      [companyCode, `${prefix}%`]
    );

    let seq = 1;
    if (result.rows.length > 0) {
      const lastNo = result.rows[0].inbound_number;
      const lastSeq = parseInt(lastNo.replace(prefix, ""), 10);
      if (!isNaN(lastSeq)) seq = lastSeq + 1;
    }

    const newNumber = `${prefix}${String(seq).padStart(4, "0")}`;

    return res.json({ success: true, data: newNumber });
  } catch (error: any) {
    logger.error("입고번호 생성 실패", { error: error.message });
    return res.status(500).json({ success: false, message: error.message });
  }
}

// 창고 목록 조회
export async function getWarehouses(req: AuthenticatedRequest, res: Response) {
  try {
    const companyCode = req.user!.companyCode;
    const pool = getPool();

    const result = await pool.query(
      `SELECT warehouse_code, warehouse_name, warehouse_type
       FROM warehouse_info
       WHERE company_code = $1 AND status != '삭제'
       ORDER BY warehouse_name`,
      [companyCode]
    );

    return res.json({ success: true, data: result.rows });
  } catch (error: any) {
    logger.error("창고 목록 조회 실패", { error: error.message });
    return res.status(500).json({ success: false, message: error.message });
  }
}
