import { Response } from "express";
import { query } from "../database/db";
import { logger } from "../utils/logger";

function buildCompanyFilter(companyCode: string, alias: string, paramIdx: number) {
  if (companyCode === "*") return { condition: "", params: [] as any[], nextIdx: paramIdx };
  return {
    condition: `${alias}.company_code = $${paramIdx}`,
    params: [companyCode],
    nextIdx: paramIdx + 1,
  };
}

function buildDateFilter(startDate: string | undefined, endDate: string | undefined, dateExpr: string, paramIdx: number) {
  const conditions: string[] = [];
  const params: any[] = [];
  let idx = paramIdx;

  if (startDate) {
    conditions.push(`${dateExpr} >= $${idx}`);
    params.push(startDate);
    idx++;
  }
  if (endDate) {
    conditions.push(`${dateExpr} <= $${idx}`);
    params.push(endDate);
    idx++;
  }

  return { conditions, params, nextIdx: idx };
}

function buildWhereClause(conditions: string[]): string {
  return conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
}

function extractFilterSet(rows: any[], field: string, labelField?: string): { value: string; label: string }[] {
  const set = new Map<string, string>();
  rows.forEach((r: any) => {
    const val = r[field];
    if (val && val !== "미지정") set.set(val, r[labelField || field] || val);
  });
  return [...set.entries()].map(([value, label]) => ({ value, label }));
}

// ============================================
// 생산 리포트
// ============================================
export async function getProductionReportData(req: any, res: Response): Promise<void> {
  try {
    const companyCode = req.user?.companyCode;
    if (!companyCode) { res.status(401).json({ success: false, message: "인증 정보가 없습니다" }); return; }

    const { startDate, endDate } = req.query;
    const conditions: string[] = [];
    const params: any[] = [];
    let idx = 1;

    const cf = buildCompanyFilter(companyCode, "wop", idx);
    if (cf.condition) { conditions.push(cf.condition); params.push(...cf.params); idx = cf.nextIdx; }

    const dateExpr = "COALESCE(NULLIF(wopr.started_at, ''), wop.created_date::date::text)";
    const df = buildDateFilter(startDate, endDate, dateExpr, idx);
    conditions.push(...df.conditions); params.push(...df.params); idx = df.nextIdx;

    const whereClause = buildWhereClause(conditions);

    // 공정 메타(process_code/name/plan_qty)는 work_order_process,
    // 실적(started_at/completed_at/good_qty/defect_qty/equipment_code 등)은 work_order_process_result에 있음
    const dataQuery = `
      SELECT
        COALESCE(NULLIF(wopr.started_at, ''), wop.created_date::date::text) as date,
        COALESCE(NULLIF(wop.process_name, ''), NULLIF(wop.process_code, ''), '미지정') as process,
        COALESCE(NULLIF(em.equipment_name, ''), NULLIF(em.equipment_code, ''), '미지정') as equipment,
        COALESCE(NULLIF(ii.item_name, ''), NULLIF(ii.item_number, ''), '미지정') as item,
        COALESCE(NULLIF(wi.worker, ''), '미지정') as worker,
        CAST(COALESCE(NULLIF(wop.plan_qty, ''), '0') AS numeric) as "planQty",
        CAST(COALESCE(NULLIF(wopr.good_qty, ''), '0') AS numeric) as "prodQty",
        CAST(COALESCE(NULLIF(wopr.defect_qty, ''), '0') AS numeric) as "defectQty",
        CASE
          WHEN NULLIF(wopr.started_at, '') IS NOT NULL
           AND NULLIF(wopr.completed_at, '') IS NOT NULL
          THEN GREATEST(
            EXTRACT(EPOCH FROM (wopr.completed_at::timestamp - wopr.started_at::timestamp)) / 3600.0,
            0
          )
          ELSE 0
        END as "runTime",
        CAST(COALESCE(NULLIF(wopr.total_paused_time, ''), '0') AS numeric) / 3600.0 as "downTime",
        wopr.status,
        wop.company_code
      FROM work_order_process wop
      LEFT JOIN work_order_process_result wopr
        ON wopr.wop_id = wop.id AND wopr.company_code = wop.company_code
      LEFT JOIN work_instruction wi
        ON wop.wo_id = wi.id AND wop.company_code = wi.company_code
      LEFT JOIN LATERAL (
        SELECT equipment_code, equipment_name
        FROM equipment_mng
        WHERE company_code = wi.company_code
          AND (id = wi.equipment_id OR equipment_code = wi.equipment_id
               OR id = wopr.equipment_code OR equipment_code = wopr.equipment_code)
        ORDER BY (id = wi.equipment_id OR id = wopr.equipment_code) DESC, created_date DESC
        LIMIT 1
      ) em ON true
      LEFT JOIN LATERAL (
        SELECT ii_inner.item_number, ii_inner.item_name
        FROM item_info ii_inner
        WHERE ii_inner.company_code = wi.company_code
          AND (
            (NULLIF(wi.item_id, '') IS NOT NULL
             AND (ii_inner.id = wi.item_id OR ii_inner.item_number = wi.item_id))
            OR ii_inner.item_number = (
              SELECT wid.item_number
              FROM work_instruction_detail wid
              WHERE wid.work_instruction_id = wi.id
                AND wid.company_code = wi.company_code
                AND NULLIF(wid.item_number, '') IS NOT NULL
              ORDER BY wid.created_date ASC
              LIMIT 1
            )
          )
        ORDER BY
          CASE WHEN ii_inner.id = wi.item_id THEN 1
               WHEN ii_inner.item_number = wi.item_id THEN 2
               ELSE 3 END,
          ii_inner.created_date DESC
        LIMIT 1
      ) ii ON true
      ${whereClause}
      ORDER BY date DESC NULLS LAST
    `;

    const dataRows = await query(dataQuery, params);

    logger.info("생산 리포트 데이터 조회", { companyCode, rowCount: dataRows.length });

    res.status(200).json({
      success: true,
      data: {
        rows: dataRows,
        filterOptions: {
          processes: extractFilterSet(dataRows, "process"),
          equipment: extractFilterSet(dataRows, "equipment"),
          items: extractFilterSet(dataRows, "item"),
          workers: extractFilterSet(dataRows, "worker"),
        },
        totalCount: dataRows.length,
      },
    });
  } catch (error: any) {
    logger.error("생산 리포트 조회 실패", { error: error.message });
    res.status(500).json({ success: false, message: "생산 리포트 데이터 조회에 실패했습니다", error: error.message });
  }
}

// ============================================
// 재고 리포트
// ============================================
export async function getInventoryReportData(req: any, res: Response): Promise<void> {
  try {
    const companyCode = req.user?.companyCode;
    if (!companyCode) { res.status(401).json({ success: false, message: "인증 정보가 없습니다" }); return; }

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

    const cf = buildCompanyFilter(companyCode, "ist", idx);
    if (cf.condition) { conditions.push(cf.condition); params.push(...cf.params); idx = cf.nextIdx; }

    const whereClause = buildWhereClause(conditions);

    const dataQuery = `
      SELECT
        COALESCE(ist.updated_date, ist.created_date)::date::text as date,
        ist.item_code,
        COALESCE(ii.item_name, ist.item_code, '미지정') as item,
        COALESCE(wi.warehouse_name, ist.warehouse_code, '미지정') as warehouse,
        '일반' as category,
        CAST(COALESCE(NULLIF(ist.current_qty::text, ''), '0') AS numeric) as "currentQty",
        CAST(COALESCE(NULLIF(ist.safety_qty::text, ''), '0') AS numeric) as "safetyQty",
        COALESCE(ih_in.in_qty, 0) as "inQty",
        COALESCE(ih_out.out_qty, 0) as "outQty",
        0 as "stockValue",
        GREATEST(CAST(COALESCE(NULLIF(ist.safety_qty::text, ''), '0') AS numeric)
          - CAST(COALESCE(NULLIF(ist.current_qty::text, ''), '0') AS numeric), 0) as "shortageQty",
        CASE WHEN CAST(COALESCE(NULLIF(ist.current_qty::text, ''), '0') AS numeric) > 0
             AND COALESCE(ih_out.out_qty, 0) > 0
        THEN ROUND(COALESCE(ih_out.out_qty, 0)::numeric
             / CAST(COALESCE(NULLIF(ist.current_qty::text, ''), '1') AS numeric), 2)
        ELSE 0 END as "turnover",
        ist.company_code
      FROM inventory_stock ist
      LEFT JOIN (
        SELECT DISTINCT ON (item_number, company_code)
          item_number, item_name, company_code
        FROM item_info ORDER BY item_number, company_code, created_date DESC
      ) ii ON ist.item_code = ii.item_number AND ist.company_code = ii.company_code
      LEFT JOIN warehouse_info wi ON ist.warehouse_code = wi.warehouse_code
        AND ist.company_code = wi.company_code
      LEFT JOIN (
        SELECT item_code, company_code,
          SUM(CAST(COALESCE(NULLIF(quantity::text, ''), '0') AS numeric)) as in_qty
        FROM inventory_history WHERE transaction_type = 'IN'
        GROUP BY item_code, company_code
      ) ih_in ON ist.item_code = ih_in.item_code AND ist.company_code = ih_in.company_code
      LEFT JOIN (
        SELECT item_code, company_code,
          SUM(CAST(COALESCE(NULLIF(quantity::text, ''), '0') AS numeric)) as out_qty
        FROM inventory_history WHERE transaction_type = 'OUT'
        GROUP BY item_code, company_code
      ) ih_out ON ist.item_code = ih_out.item_code AND ist.company_code = ih_out.company_code
      ${whereClause}
      ORDER BY date DESC NULLS LAST
    `;

    const dataRows = await query(dataQuery, params);

    logger.info("재고 리포트 데이터 조회", { companyCode, rowCount: dataRows.length });

    res.status(200).json({
      success: true,
      data: {
        rows: dataRows,
        filterOptions: {
          items: extractFilterSet(dataRows, "item"),
          warehouses: extractFilterSet(dataRows, "warehouse"),
          categories: [
            { value: "원자재", label: "원자재" }, { value: "부자재", label: "부자재" },
            { value: "반제품", label: "반제품" }, { value: "완제품", label: "완제품" },
            { value: "일반", label: "일반" },
          ],
        },
        totalCount: dataRows.length,
      },
    });
  } catch (error: any) {
    logger.error("재고 리포트 조회 실패", { error: error.message });
    res.status(500).json({ success: false, message: "재고 리포트 데이터 조회에 실패했습니다", error: error.message });
  }
}

// ============================================
// 구매 리포트
// ============================================
export async function getPurchaseReportData(req: any, res: Response): Promise<void> {
  try {
    const companyCode = req.user?.companyCode;
    if (!companyCode) { res.status(401).json({ success: false, message: "인증 정보가 없습니다" }); return; }

    const { startDate, endDate } = req.query;
    const params: any[] = [];
    let idx = 1;

    // company_code 필터 파라미터 ($1 또는 없음)
    const cf = buildCompanyFilter(companyCode, "po", idx);
    let companyConditionDetail = "";
    let companyConditionLegacy = "";
    if (cf.condition) {
      // purchase_detail 쪽: pd.company_code
      companyConditionDetail = `pd.company_code = $${idx}`;
      // purchase_order_mng 쪽: po.company_code
      companyConditionLegacy = `po.company_code = $${idx}`;
      // NOT EXISTS 내부에서도 동일 파라미터 재사용
      params.push(...cf.params);
      idx = cf.nextIdx;
    }

    // 날짜 필터는 외부 쿼리에서 적용
    const outerConditions: string[] = [];
    const df = buildDateFilter(startDate, endDate, "date", idx);
    outerConditions.push(...df.conditions);
    params.push(...df.params);
    idx = df.nextIdx;

    const outerWhereClause = buildWhereClause(outerConditions);

    const dataQuery = `
      WITH combined AS (
        -- 신규: purchase_detail 기반 (헤더는 purchase_order_mng LEFT JOIN)
        SELECT
          COALESCE(po.order_date, po.created_date::date::text, pd.created_date::date::text) as date,
          COALESCE(po.purchase_no, pd.purchase_no) as purchase_no,
          COALESCE(pd.supplier_name, pd.supplier_code, po.supplier_name, po.supplier_code, '미지정') as supplier,
          COALESCE(NULLIF(pd.item_name, ''), po.item_name, NULLIF(pd.item_code, ''), po.item_code, '미지정') as item,
          COALESCE(NULLIF(pd.item_code, ''), po.item_code) as item_code,
          COALESCE(po.manager, '미지정') as manager,
          COALESCE(po.status, '') as status,
          CAST(COALESCE(NULLIF(pd.order_qty, ''), '0') AS numeric) as "orderQty",
          CAST(COALESCE(NULLIF(pd.received_qty, ''), NULLIF(po.received_qty, ''), '0') AS numeric) as "receiveQty",
          CAST(COALESCE(NULLIF(pd.unit_price, ''), '0') AS numeric) as "unitPrice",
          CAST(COALESCE(NULLIF(pd.order_qty, ''), '0') AS numeric)
            * CAST(COALESCE(NULLIF(pd.unit_price, ''), '0') AS numeric) as "orderAmt",
          CAST(COALESCE(NULLIF(pd.received_qty, ''), NULLIF(po.received_qty, ''), '0') AS numeric)
            * CAST(COALESCE(NULLIF(pd.unit_price, ''), '0') AS numeric) as "receiveAmt",
          1 as "orderCnt",
          pd.company_code
        FROM purchase_detail pd
        LEFT JOIN purchase_order_mng po
          ON pd.purchase_no = po.purchase_no AND pd.company_code = po.company_code
        ${companyConditionDetail ? `WHERE ${companyConditionDetail}` : ""}

        UNION ALL

        -- 레거시: purchase_detail에 없는 purchase_order_mng 데이터
        SELECT
          COALESCE(po.order_date, po.created_date::date::text) as date,
          po.purchase_no,
          COALESCE(po.supplier_name, po.supplier_code, '미지정') as supplier,
          COALESCE(po.item_name, po.item_code, '미지정') as item,
          po.item_code,
          COALESCE(po.manager, '미지정') as manager,
          po.status,
          CAST(COALESCE(NULLIF(po.order_qty, ''), '0') AS numeric) as "orderQty",
          CAST(COALESCE(NULLIF(po.received_qty, ''), '0') AS numeric) as "receiveQty",
          CAST(COALESCE(NULLIF(po.unit_price, ''), '0') AS numeric) as "unitPrice",
          CAST(COALESCE(NULLIF(po.amount, ''), '0') AS numeric) as "orderAmt",
          CAST(COALESCE(NULLIF(po.received_qty, ''), '0') AS numeric)
            * CAST(COALESCE(NULLIF(po.unit_price, ''), '0') AS numeric) as "receiveAmt",
          1 as "orderCnt",
          po.company_code
        FROM purchase_order_mng po
        WHERE ${companyConditionLegacy ? `${companyConditionLegacy} AND ` : ""}NOT EXISTS (
          SELECT 1 FROM purchase_detail pd
          WHERE pd.purchase_no = po.purchase_no AND pd.company_code = po.company_code
        )
      )
      SELECT * FROM combined
      ${outerWhereClause}
      ORDER BY date DESC NULLS LAST
    `;

    const dataRows = await query(dataQuery, params);

    logger.info("구매 리포트 데이터 조회", { companyCode, rowCount: dataRows.length });

    res.status(200).json({
      success: true,
      data: {
        rows: dataRows,
        filterOptions: {
          suppliers: extractFilterSet(dataRows, "supplier"),
          items: extractFilterSet(dataRows, "item"),
          managers: extractFilterSet(dataRows, "manager"),
          statuses: extractFilterSet(dataRows, "status"),
        },
        totalCount: dataRows.length,
      },
    });
  } catch (error: any) {
    logger.error("구매 리포트 조회 실패", { error: error.message });
    res.status(500).json({ success: false, message: "구매 리포트 데이터 조회에 실패했습니다", error: error.message });
  }
}

// ============================================
// 품질 리포트
// ============================================
export async function getQualityReportData(req: any, res: Response): Promise<void> {
  try {
    const companyCode = req.user?.companyCode;
    if (!companyCode) { res.status(401).json({ success: false, message: "인증 정보가 없습니다" }); return; }

    const { startDate, endDate } = req.query;
    const conditions: string[] = [];
    const params: any[] = [];
    let idx = 1;

    const cf = buildCompanyFilter(companyCode, "pr", idx);
    if (cf.condition) { conditions.push(cf.condition); params.push(...cf.params); idx = cf.nextIdx; }

    const df = buildDateFilter(startDate, endDate, "COALESCE(pr.production_date, pr.created_date::date::text)", idx);
    conditions.push(...df.conditions); params.push(...df.params); idx = df.nextIdx;

    const whereClause = buildWhereClause(conditions);

    const dataQuery = `
      SELECT
        COALESCE(pr.production_date, pr.created_date::date::text) as date,
        COALESCE(NULLIF(ii.item_name, ''), NULLIF(ii.item_number, ''), '미지정') as item,
        '일반검사' as "defectType",
        COALESCE(wi.routing, '미지정') as process,
        COALESCE(pr.worker_name, '미지정') as inspector,
        CAST(COALESCE(NULLIF(pr.production_qty, ''), '0') AS numeric) as "inspQty",
        CAST(COALESCE(NULLIF(pr.production_qty, ''), '0') AS numeric)
          - CAST(COALESCE(NULLIF(pr.defect_qty, ''), '0') AS numeric) as "passQty",
        CAST(COALESCE(NULLIF(pr.defect_qty, ''), '0') AS numeric) as "defectQty",
        0 as "reworkQty",
        0 as "scrapQty",
        0 as "claimCnt",
        pr.company_code
      FROM production_record pr
      LEFT JOIN work_instruction wi ON pr.wo_id = wi.id AND pr.company_code = wi.company_code
      LEFT JOIN LATERAL (
        SELECT ii_inner.item_number, ii_inner.item_name
        FROM item_info ii_inner
        WHERE ii_inner.company_code = wi.company_code
          AND (
            (NULLIF(wi.item_id, '') IS NOT NULL
             AND (ii_inner.id = wi.item_id OR ii_inner.item_number = wi.item_id))
            OR ii_inner.item_number = (
              SELECT wid.item_number
              FROM work_instruction_detail wid
              WHERE wid.work_instruction_id = wi.id
                AND wid.company_code = wi.company_code
                AND NULLIF(wid.item_number, '') IS NOT NULL
              ORDER BY wid.created_date ASC
              LIMIT 1
            )
          )
        ORDER BY
          CASE WHEN ii_inner.id = wi.item_id THEN 1
               WHEN ii_inner.item_number = wi.item_id THEN 2
               ELSE 3 END,
          ii_inner.created_date DESC
        LIMIT 1
      ) ii ON true
      ${whereClause}
      ORDER BY date DESC NULLS LAST
    `;

    const dataRows = await query(dataQuery, params);

    logger.info("품질 리포트 데이터 조회", { companyCode, rowCount: dataRows.length });

    res.status(200).json({
      success: true,
      data: {
        rows: dataRows,
        filterOptions: {
          items: extractFilterSet(dataRows, "item"),
          defectTypes: [
            { value: "외관불량", label: "외관불량" }, { value: "치수불량", label: "치수불량" },
            { value: "기능불량", label: "기능불량" }, { value: "재질불량", label: "재질불량" },
            { value: "일반검사", label: "일반검사" },
          ],
          processes: extractFilterSet(dataRows, "process"),
          inspectors: extractFilterSet(dataRows, "inspector"),
        },
        totalCount: dataRows.length,
      },
    });
  } catch (error: any) {
    logger.error("품질 리포트 조회 실패", { error: error.message });
    res.status(500).json({ success: false, message: "품질 리포트 데이터 조회에 실패했습니다", error: error.message });
  }
}

// ============================================
// 설비 리포트
// ============================================
export async function getEquipmentReportData(req: any, res: Response): Promise<void> {
  try {
    const companyCode = req.user?.companyCode;
    if (!companyCode) { res.status(401).json({ success: false, message: "인증 정보가 없습니다" }); return; }

    const { startDate, endDate } = req.query;

    // 회사 필터
    const equipParams: any[] = [];
    let equipWhere = "";
    if (companyCode !== "*") {
      equipParams.push(companyCode);
      equipWhere = `WHERE ei.company_code = $1`;
    }

    // wopr(가동 실적) 집계: 회사 + 날짜 필터
    const woprParams: any[] = [];
    const woprConds: string[] = [
      "NULLIF(wopr.started_at, '') IS NOT NULL",
      "NULLIF(wopr.equipment_code, '') IS NOT NULL",
    ];
    if (companyCode !== "*") {
      woprParams.push(companyCode);
      woprConds.push(`wopr.company_code = $${woprParams.length}`);
    }
    if (startDate) {
      woprParams.push(startDate);
      woprConds.push(`wopr.started_at::date >= $${woprParams.length}::date`);
    }
    if (endDate) {
      woprParams.push(endDate);
      woprConds.push(`wopr.started_at::date <= $${woprParams.length}::date`);
    }
    const woprWhere = woprConds.join(" AND ");

    // 1-A) wopr(가동시간) 집계 — equipment_code 또는 em.id 매칭
    const woprStatsQuery = `
      SELECT
        em.equipment_code,
        em.company_code,
        SUM(GREATEST(
          CASE
            WHEN NULLIF(wopr.completed_at, '') IS NOT NULL
              AND NULLIF(wopr.started_at, '') IS NOT NULL
            THEN EXTRACT(EPOCH FROM (wopr.completed_at::timestamp - wopr.started_at::timestamp)) / 3600.0
            ELSE 0
          END, 0)) AS run_hours,
        SUM(CAST(COALESCE(NULLIF(wopr.total_paused_time, ''), '0') AS numeric)) / 3600.0 AS down_hours,
        COUNT(*) FILTER (
          WHERE wopr.status IN ('fault','error','breakdown','수리','고장')
        ) AS fault_cnt,
        MAX(wopr.started_at) AS last_started
      FROM equipment_mng em
      JOIN work_order_process_result wopr
        ON wopr.company_code = em.company_code
       AND (wopr.equipment_code = em.equipment_code OR wopr.equipment_code = em.id::text)
      WHERE ${woprWhere}
        ${companyCode !== "*" ? `AND em.company_code = $1` : ""}
      GROUP BY em.equipment_code, em.company_code
    `;
    const woprStatsRows = await query(woprStatsQuery, woprParams);

    // 1-B) production_record(생산량/불량) 집계 — wo_id → wi.equipment_id → em
    //   pr.production_date(date string) 기준 날짜 필터
    const prParams: any[] = [];
    const prConds: string[] = [];
    if (companyCode !== "*") {
      prParams.push(companyCode);
      prConds.push(`pr.company_code = $${prParams.length}`);
    }
    if (startDate) {
      prParams.push(startDate);
      prConds.push(`COALESCE(pr.production_date, pr.created_date::date::text) >= $${prParams.length}`);
    }
    if (endDate) {
      prParams.push(endDate);
      prConds.push(`COALESCE(pr.production_date, pr.created_date::date::text) <= $${prParams.length}`);
    }
    const prWhere = prConds.length > 0 ? `WHERE ${prConds.join(" AND ")}` : "";
    const prStatsQuery = `
      SELECT
        em.equipment_code,
        em.company_code,
        SUM(CAST(COALESCE(NULLIF(pr.production_qty, ''), '0') AS numeric)) AS prod_qty,
        SUM(CAST(COALESCE(NULLIF(pr.defect_qty, ''), '0') AS numeric)) AS defect_qty,
        MAX(COALESCE(pr.production_date, pr.created_date::date::text)) AS last_prod_date
      FROM equipment_mng em
      JOIN work_instruction wi
        ON wi.company_code = em.company_code
       AND (wi.equipment_id = em.id::text OR wi.equipment_id = em.equipment_code)
      JOIN production_record pr
        ON pr.wo_id = wi.id AND pr.company_code = wi.company_code
      ${prWhere}
      GROUP BY em.equipment_code, em.company_code
    `;
    const prStatsRows = await query(prStatsQuery, prParams);

    // 두 집계를 회사+설비코드 키로 병합
    const statsByCode = new Map<string, any>();
    for (const r of woprStatsRows) {
      const k = `${r.company_code}::${r.equipment_code}`;
      statsByCode.set(k, { ...(statsByCode.get(k) || {}), ...r });
    }
    for (const r of prStatsRows) {
      const k = `${r.company_code}::${r.equipment_code}`;
      statsByCode.set(k, { ...(statsByCode.get(k) || {}), ...r });
    }

    // 2) 설비 마스터 조회 (전체) + 집계 매핑
    const equipQuery = `
      SELECT
        ei.id::text AS em_id,
        ei.equipment_code,
        ei.equipment_name,
        ei.equipment_type,
        ei.installation_location,
        ei.manufacturer,
        ei.operation_status,
        ei.created_date,
        ei.updated_date,
        ei.company_code
      FROM equipment_mng ei
      ${equipWhere}
      ORDER BY ei.equipment_name ASC, ei.equipment_code ASC
    `;
    const equipRows = await query(equipQuery, equipParams);

    const dataRows = equipRows.map((e: any) => {
      const s = statsByCode.get(`${e.company_code}::${e.equipment_code}`);
      const runHours = Number(s?.run_hours ?? 0);
      const downHours = Number(s?.down_hours ?? 0);
      const totalHours = runHours + downHours;
      const opRate = totalHours > 0
        ? Math.round((runHours / totalHours) * 1000) / 10
        : 0;
      const lastDate = (s?.last_prod_date || s?.last_started || e.updated_date || e.created_date || "")
        .toString().slice(0, 10);
      return {
        date: lastDate,
        equipment_code: e.equipment_code,
        equipment: (e.equipment_name && e.equipment_name.trim()) || e.equipment_code || "미지정",
        equipType: (e.equipment_type && e.equipment_type.trim()) || "미지정",
        line: (e.installation_location && e.installation_location.trim()) || "미지정",
        manager: (e.manufacturer && e.manufacturer.trim()) || "미지정",
        status: (e.operation_status && e.operation_status.trim()) || "미지정",
        runTime: Math.round(runHours * 10) / 10,
        downTime: Math.round(downHours * 10) / 10,
        opRate,
        faultCnt: Number(s?.fault_cnt ?? 0),
        mtbf: 0,
        mttr: 0,
        maintCost: 0,
        prodQty: Number(s?.prod_qty ?? 0),
        defectQty: Number(s?.defect_qty ?? 0),
        company_code: e.company_code,
      };
    });

    logger.info("설비 리포트 데이터 조회", {
      companyCode,
      rowCount: dataRows.length,
      woprStatsCount: woprStatsRows.length,
      prStatsCount: prStatsRows.length,
    });

    res.status(200).json({
      success: true,
      data: {
        rows: dataRows,
        filterOptions: {
          equipment: extractFilterSet(dataRows, "equipment"),
          equipTypes: extractFilterSet(dataRows, "equipType"),
          lines: extractFilterSet(dataRows, "line"),
          managers: extractFilterSet(dataRows, "manager"),
        },
        totalCount: dataRows.length,
      },
    });
    return;
  } catch (error: any) {
    logger.error("설비 리포트 조회 실패", { error: error.message });
    res.status(500).json({ success: false, message: "설비 리포트 데이터 조회에 실패했습니다", error: error.message });
    return;
  }
}

// ============================================
// 금형 리포트
// ============================================
export async function getMoldReportData(req: any, res: Response): Promise<void> {
  try {
    const companyCode = req.user?.companyCode;
    if (!companyCode) { res.status(401).json({ success: false, message: "인증 정보가 없습니다" }); return; }

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

    const cf = buildCompanyFilter(companyCode, "mm", idx);
    if (cf.condition) { conditions.push(cf.condition); params.push(...cf.params); idx = cf.nextIdx; }

    const whereClause = buildWhereClause(conditions);

    const dataQuery = `
      SELECT
        COALESCE(mm.updated_date, mm.created_date)::date::text as date,
        mm.mold_code,
        COALESCE(mm.mold_name, mm.mold_code) as mold,
        COALESCE(mm.mold_type, mm.category, '미지정') as "moldType",
        COALESCE(ii.item_name, '미지정') as item,
        COALESCE(mm.manufacturer, '미지정') as maker,
        mm.operation_status as status,
        CAST(COALESCE(NULLIF(mm.shot_count::text, ''), '0') AS numeric) as "shotCnt",
        CAST(COALESCE(NULLIF(mm.warranty_shot_count::text, ''), '0') AS numeric) as "guaranteeShot",
        CASE WHEN CAST(COALESCE(NULLIF(mm.warranty_shot_count::text, ''), '0') AS numeric) > 0
        THEN ROUND(
          CAST(COALESCE(NULLIF(mm.shot_count::text, ''), '0') AS numeric) * 100.0
          / CAST(COALESCE(NULLIF(mm.warranty_shot_count::text, ''), '1') AS numeric), 1)
        ELSE 0 END as "lifeRate",
        0 as "repairCnt",
        0 as "repairCost",
        0 as "prodQty",
        0 as "defectRate",
        CAST(COALESCE(NULLIF(mm.cavity_count::text, ''), '0') AS numeric) as "cavityUse",
        mm.company_code
      FROM mold_mng mm
      LEFT JOIN (
        SELECT DISTINCT ON (item_number, company_code)
          item_number, item_name, company_code
        FROM item_info ORDER BY item_number, company_code, created_date DESC
      ) ii ON mm.mold_code = ii.item_number AND mm.company_code = ii.company_code
      ${whereClause}
      ORDER BY mold ASC
    `;

    const dataRows = await query(dataQuery, params);

    logger.info("금형 리포트 데이터 조회", { companyCode, rowCount: dataRows.length });

    res.status(200).json({
      success: true,
      data: {
        rows: dataRows,
        filterOptions: {
          molds: extractFilterSet(dataRows, "mold"),
          moldTypes: extractFilterSet(dataRows, "moldType"),
          items: extractFilterSet(dataRows, "item"),
          makers: extractFilterSet(dataRows, "maker"),
        },
        totalCount: dataRows.length,
      },
    });
  } catch (error: any) {
    logger.error("금형 리포트 조회 실패", { error: error.message });
    res.status(500).json({ success: false, message: "금형 리포트 데이터 조회에 실패했습니다", error: error.message });
  }
}
