/**
 * 자재현황 컨트롤러
 * - 생산계획(작업지시) 조회
 * - 선택된 작업지시의 BOM 기반 자재소요량 + 재고 현황 조회
 * - 창고 목록 조회
 */

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

// ─── 생산계획(작업지시) 조회 ───

export async function getWorkOrders(
  req: AuthenticatedRequest,
  res: Response
) {
  try {
    const companyCode = req.user!.companyCode;
    const { dateFrom, dateTo, itemCode, itemName } = req.query;

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

    if (companyCode === "*") {
      logger.info("최고 관리자 전체 작업지시 조회");
    } else {
      conditions.push(`p.company_code = $${paramIndex}`);
      params.push(companyCode);
      paramIndex++;
    }

    if (dateFrom) {
      conditions.push(`p.plan_date >= $${paramIndex}::date`);
      params.push(dateFrom);
      paramIndex++;
    }

    if (dateTo) {
      conditions.push(`p.plan_date <= $${paramIndex}::date`);
      params.push(dateTo);
      paramIndex++;
    }

    if (itemCode) {
      conditions.push(`p.item_code ILIKE $${paramIndex}`);
      params.push(`%${itemCode}%`);
      paramIndex++;
    }

    if (itemName) {
      conditions.push(`p.item_name ILIKE $${paramIndex}`);
      params.push(`%${itemName}%`);
      paramIndex++;
    }

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

    const query = `
      SELECT 
        p.id,
        p.plan_no,
        p.item_code,
        p.item_name,
        p.plan_qty,
        p.completed_qty,
        p.plan_date,
        p.start_date,
        p.end_date,
        p.status,
        p.work_order_no,
        p.company_code
      FROM production_plan_mng p
      ${whereClause}
      ORDER BY p.plan_date DESC, p.created_date DESC
    `;

    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 });
  }
}

// ─── 선택된 작업지시의 자재소요 + 재고 현황 조회 ───

export async function getMaterialStatus(
  req: AuthenticatedRequest,
  res: Response
) {
  try {
    const companyCode = req.user!.companyCode;
    const { planIds, warehouseCode } = req.body;

    if (!planIds || !Array.isArray(planIds) || planIds.length === 0) {
      return res
        .status(400)
        .json({ success: false, message: "작업지시를 선택해주세요." });
    }

    // 1) 선택된 작업지시의 품목코드 + 수량 조회
    const planPlaceholders = planIds
      .map((_, i) => `$${i + 1}`)
      .join(",");
    let paramIndex = planIds.length + 1;

    const companyCondition =
      companyCode === "*" ? "" : `AND p.company_code = $${paramIndex}`;
    const planParams: any[] = [...planIds];
    if (companyCode !== "*") {
      planParams.push(companyCode);
      paramIndex++;
    }

    const planQuery = `
      SELECT p.item_code, p.item_name, p.plan_qty
      FROM production_plan_mng p
      WHERE p.id IN (${planPlaceholders})
      ${companyCondition}
    `;

    const planResult = await pool.query(planQuery, planParams);

    if (planResult.rowCount === 0) {
      return res.json({ success: true, data: [] });
    }

    // 2) 해당 품목들의 BOM에서 필요 자재 목록 조회
    const itemCodes = planResult.rows.map((r: any) => r.item_code);
    const planQtyMap: Record<string, number> = {};
    for (const row of planResult.rows) {
      const code = row.item_code;
      planQtyMap[code] = (planQtyMap[code] || 0) + Number(row.plan_qty || 0);
    }

    const itemPlaceholders = itemCodes.map((_: any, i: number) => `$${i + 1}`).join(",");

    // BOM 조인: bom -> bom_detail -> item_info (자재 정보)
    const bomCompanyCondition =
      companyCode === "*" ? "" : `AND b.company_code = $${itemCodes.length + 1}`;
    const bomParams: any[] = [...itemCodes];
    if (companyCode !== "*") {
      bomParams.push(companyCode);
    }

    const bomQuery = `
      SELECT 
        b.item_code AS parent_item_code,
        b.base_qty AS bom_base_qty,
        bd.child_item_id,
        bd.quantity AS bom_qty,
        bd.unit AS bom_unit,
        bd.loss_rate,
        ii.item_name AS material_name,
        ii.item_number AS material_code,
        ii.unit AS material_unit
      FROM bom b
      JOIN bom_detail bd ON b.id = bd.bom_id AND b.company_code = bd.company_code
      LEFT JOIN item_info ii ON bd.child_item_id = ii.id AND b.company_code = ii.company_code
      WHERE b.item_code IN (${itemPlaceholders})
      ${bomCompanyCondition}
      ORDER BY b.item_code, bd.seq_no
    `;

    const bomResult = await pool.query(bomQuery, bomParams);

    // 3) 자재별 필요수량 계산
    interface MaterialNeed {
      childItemId: string;
      materialCode: string;
      materialName: string;
      unit: string;
      requiredQty: number;
    }

    const materialMap: Record<string, MaterialNeed> = {};

    for (const bomRow of bomResult.rows) {
      const parentQty = planQtyMap[bomRow.parent_item_code] || 0;
      const baseQty = Number(bomRow.bom_base_qty) || 1;
      const bomQty = Number(bomRow.bom_qty) || 0;
      const lossRate = Number(bomRow.loss_rate) || 0;

      // 필요수량 = (생산수량 / BOM기준수량) * BOM자재수량 * (1 + 로스율/100)
      const requiredQty =
        (parentQty / baseQty) * bomQty * (1 + lossRate / 100);

      const key = bomRow.child_item_id;
      if (materialMap[key]) {
        materialMap[key].requiredQty += requiredQty;
      } else {
        materialMap[key] = {
          childItemId: bomRow.child_item_id,
          materialCode:
            bomRow.material_code || bomRow.child_item_id,
          materialName: bomRow.material_name || "알 수 없음",
          unit: bomRow.bom_unit || bomRow.material_unit || "EA",
          requiredQty,
        };
      }
    }

    const materialIds = Object.keys(materialMap);

    if (materialIds.length === 0) {
      return res.json({ success: true, data: [] });
    }

    // 4) 재고 조회 (창고/위치별)
    const stockPlaceholders = materialIds
      .map((_, i) => `$${i + 1}`)
      .join(",");
    const stockParams: any[] = [...materialIds];
    let stockParamIdx = materialIds.length + 1;

    const stockConditions: string[] = [
      `s.item_code IN (${stockPlaceholders})`,
    ];

    if (companyCode !== "*") {
      stockConditions.push(`s.company_code = $${stockParamIdx}`);
      stockParams.push(companyCode);
      stockParamIdx++;
    }

    if (warehouseCode) {
      stockConditions.push(`s.warehouse_code = $${stockParamIdx}`);
      stockParams.push(warehouseCode);
      stockParamIdx++;
    }

    const stockQuery = `
      SELECT 
        s.item_code,
        s.warehouse_code,
        s.location_code,
        COALESCE(CAST(s.current_qty AS NUMERIC), 0) AS current_qty
      FROM inventory_stock s
      WHERE ${stockConditions.join(" AND ")}
        AND COALESCE(CAST(s.current_qty AS NUMERIC), 0) > 0
      ORDER BY s.item_code, s.warehouse_code, s.location_code
    `;

    const stockResult = await pool.query(stockQuery, stockParams);

    // 5) 결과 조합
    // item_code 기준 재고 맵핑 (inventory_stock.item_code는 item_info.item_number 또는 item_info.id일 수 있음)
    const stockByItem: Record<
      string,
      { location: string; warehouse: string; qty: number }[]
    > = {};

    for (const stockRow of stockResult.rows) {
      const code = stockRow.item_code;
      if (!stockByItem[code]) {
        stockByItem[code] = [];
      }
      stockByItem[code].push({
        location: stockRow.location_code || "",
        warehouse: stockRow.warehouse_code || "",
        qty: Number(stockRow.current_qty),
      });
    }

    const resultData = materialIds.map((id) => {
      const material = materialMap[id];
      // inventory_stock의 item_code가 item_number 또는 child_item_id일 수 있음
      const locations =
        stockByItem[material.materialCode] ||
        stockByItem[id] ||
        [];

      const totalCurrentQty = locations.reduce(
        (sum, loc) => sum + loc.qty,
        0
      );

      return {
        code: material.materialCode,
        name: material.materialName,
        required: Math.round(material.requiredQty * 100) / 100,
        current: totalCurrentQty,
        unit: material.unit,
        locations,
      };
    });

    logger.info("자재현황 조회 완료", {
      companyCode,
      planCount: planIds.length,
      materialCount: resultData.length,
    });

    return res.json({ success: true, data: resultData });
  } 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;

    let query: string;
    let params: any[];

    if (companyCode === "*") {
      query = `
        SELECT DISTINCT warehouse_code, warehouse_name, warehouse_type
        FROM warehouse_info
        ORDER BY warehouse_code
      `;
      params = [];
    } else {
      query = `
        SELECT DISTINCT warehouse_code, warehouse_name, warehouse_type
        FROM warehouse_info
        WHERE company_code = $1
        ORDER BY warehouse_code
      `;
      params = [companyCode];
    }

    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 });
  }
}
