/**
 * 공정정보관리 컨트롤러
 * - 공정 마스터 CRUD
 * - 공정별 설비 관리
 * - 품목별 라우팅 관리
 */

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

// ═══════════════════════════════════════════
// 공정 마스터 CRUD
// ═══════════════════════════════════════════

export async function getProcessList(req: AuthenticatedRequest, res: Response) {
  try {
    const companyCode = req.user!.companyCode;
    const { processCode, processName, processType, useYn } = req.query;

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

    if (companyCode !== "*") {
      conditions.push(`company_code = $${idx++}`);
      params.push(companyCode);
    }
    if (processCode) {
      conditions.push(`process_code ILIKE $${idx++}`);
      params.push(`%${processCode}%`);
    }
    if (processName) {
      conditions.push(`process_name ILIKE $${idx++}`);
      params.push(`%${processName}%`);
    }
    if (processType) {
      conditions.push(`process_type = $${idx++}`);
      params.push(processType);
    }
    if (useYn) {
      conditions.push(`use_yn = $${idx++}`);
      params.push(useYn);
    }

    const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
    const result = await pool.query(
      `SELECT * FROM process_mng ${where} ORDER BY process_code`,
      params
    );

    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 createProcess(req: AuthenticatedRequest, res: Response) {
  try {
    const companyCode = req.user!.companyCode;
    const writer = req.user!.userId;
    const { process_name, process_type, standard_time, worker_count, use_yn } = req.body;

    // 공정코드 자동 채번: PROC-001, PROC-002, ...
    const seqRes = await pool.query(
      `SELECT process_code FROM process_mng WHERE company_code = $1 AND process_code LIKE 'PROC-%' ORDER BY process_code DESC LIMIT 1`,
      [companyCode]
    );
    let nextNum = 1;
    if (seqRes.rowCount! > 0) {
      const lastCode = seqRes.rows[0].process_code;
      const numPart = parseInt(lastCode.replace("PROC-", ""), 10);
      if (!isNaN(numPart)) nextNum = numPart + 1;
    }
    const processCode = `PROC-${String(nextNum).padStart(3, "0")}`;

    const result = await pool.query(
      `INSERT INTO process_mng (id, company_code, process_code, process_name, process_type, standard_time, worker_count, use_yn, writer)
       VALUES (gen_random_uuid()::text, $1, $2, $3, $4, $5, $6, $7, $8) RETURNING *`,
      [companyCode, processCode, process_name, process_type, standard_time || "0", worker_count || "0", use_yn || "Y", writer]
    );

    return res.json({ success: true, data: result.rows[0] });
  } catch (error: any) {
    logger.error("공정 등록 실패", { error: error.message });
    return res.status(500).json({ success: false, message: error.message });
  }
}

export async function updateProcess(req: AuthenticatedRequest, res: Response) {
  try {
    const companyCode = req.user!.companyCode;
    const { id } = req.params;
    const { process_name, process_type, standard_time, worker_count, use_yn } = req.body;

    const result = await pool.query(
      `UPDATE process_mng SET process_name=$1, process_type=$2, standard_time=$3, worker_count=$4, use_yn=$5, updated_date=NOW()
       WHERE id=$6 AND company_code=$7 RETURNING *`,
      [process_name, process_type, standard_time, worker_count, use_yn, id, companyCode]
    );

    if (result.rowCount === 0) {
      return res.status(404).json({ success: false, message: "공정을 찾을 수 없습니다." });
    }
    return res.json({ success: true, data: result.rows[0] });
  } catch (error: any) {
    logger.error("공정 수정 실패", { error: error.message });
    return res.status(500).json({ success: false, message: error.message });
  }
}

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

    if (!ids || !Array.isArray(ids) || ids.length === 0) {
      return res.status(400).json({ success: false, message: "삭제할 공정을 선택해주세요." });
    }

    const placeholders = ids.map((_: any, i: number) => `$${i + 1}`).join(",");
    // 설비 매핑도 삭제
    await pool.query(
      `DELETE FROM process_equipment WHERE process_code IN (SELECT process_code FROM process_mng WHERE id IN (${placeholders}) AND company_code = $${ids.length + 1})`,
      [...ids, companyCode]
    );
    const result = await pool.query(
      `DELETE FROM process_mng WHERE id IN (${placeholders}) AND company_code = $${ids.length + 1} RETURNING id`,
      [...ids, companyCode]
    );

    return res.json({ success: true, deletedCount: result.rowCount });
  } catch (error: any) {
    logger.error("공정 삭제 실패", { error: error.message });
    return res.status(500).json({ success: false, message: error.message });
  }
}

// ═══════════════════════════════════════════
// 공정별 설비 관리
// ═══════════════════════════════════════════

export async function getProcessEquipments(req: AuthenticatedRequest, res: Response) {
  try {
    const companyCode = req.user!.companyCode;
    const { processCode } = req.params;

    const result = await pool.query(
      `SELECT pe.*, ei.equipment_name
       FROM process_equipment pe
       LEFT JOIN equipment_info ei ON pe.equipment_code = ei.equipment_code AND pe.company_code = ei.company_code
       WHERE pe.process_code = $1 AND pe.company_code = $2
       ORDER BY pe.equipment_code`,
      [processCode, 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 });
  }
}

export async function addProcessEquipment(req: AuthenticatedRequest, res: Response) {
  try {
    const companyCode = req.user!.companyCode;
    const writer = req.user!.userId;
    const { process_code, equipment_code } = req.body;

    const dupCheck = await pool.query(
      `SELECT id FROM process_equipment WHERE process_code=$1 AND equipment_code=$2 AND company_code=$3`,
      [process_code, equipment_code, companyCode]
    );
    if (dupCheck.rowCount! > 0) {
      return res.status(400).json({ success: false, message: "이미 등록된 설비입니다." });
    }

    const result = await pool.query(
      `INSERT INTO process_equipment (id, company_code, process_code, equipment_code, writer)
       VALUES (gen_random_uuid()::text, $1, $2, $3, $4) RETURNING *`,
      [companyCode, process_code, equipment_code, writer]
    );

    return res.json({ success: true, data: result.rows[0] });
  } catch (error: any) {
    logger.error("공정 설비 등록 실패", { error: error.message });
    return res.status(500).json({ success: false, message: error.message });
  }
}

export async function removeProcessEquipment(req: AuthenticatedRequest, res: Response) {
  try {
    const companyCode = req.user!.companyCode;
    const { id } = req.params;

    await pool.query(
      `DELETE FROM process_equipment WHERE id=$1 AND company_code=$2`,
      [id, companyCode]
    );

    return res.json({ success: true });
  } catch (error: any) {
    logger.error("공정 설비 제거 실패", { error: error.message });
    return res.status(500).json({ success: false, message: error.message });
  }
}

export async function getEquipmentList(req: AuthenticatedRequest, res: Response) {
  try {
    const companyCode = req.user!.companyCode;
    const condition = companyCode === "*" ? "" : `WHERE company_code = $1`;
    const params = companyCode === "*" ? [] : [companyCode];

    const result = await pool.query(
      `SELECT id, equipment_code, equipment_name FROM equipment_info ${condition} ORDER BY equipment_code`,
      params
    );

    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 getItemsForRouting(req: AuthenticatedRequest, res: Response) {
  try {
    const companyCode = req.user!.companyCode;
    const { search } = req.query;

    const conditions: string[] = ["i.company_code = rv.company_code"];
    const params: any[] = [];
    let idx = 1;

    if (companyCode !== "*") {
      conditions.push(`i.company_code = $${idx++}`);
      params.push(companyCode);
    }
    if (search) {
      conditions.push(`(i.item_number ILIKE $${idx} OR i.item_name ILIKE $${idx})`);
      params.push(`%${search}%`);
      idx++;
    }

    const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
    const result = await pool.query(
      `SELECT DISTINCT i.id, i.item_number, i.item_name, i.size, i.unit, i.type
       FROM item_info i
       INNER JOIN item_routing_version rv ON rv.item_code = i.item_number AND rv.company_code = i.company_code
       ${where}
       ORDER BY i.item_number LIMIT 200`,
      params
    );

    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 searchAllItems(req: AuthenticatedRequest, res: Response) {
  try {
    const companyCode = req.user!.companyCode;
    const { search } = req.query;

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

    if (companyCode !== "*") {
      conditions.push(`company_code = $${idx++}`);
      params.push(companyCode);
    }
    if (search) {
      conditions.push(`(item_number ILIKE $${idx} OR item_name ILIKE $${idx})`);
      params.push(`%${search}%`);
      idx++;
    }

    const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
    const result = await pool.query(
      `SELECT id, item_number, item_name, size, unit, type FROM item_info ${where} ORDER BY item_number LIMIT 200`,
      params
    );

    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 getRoutingVersions(req: AuthenticatedRequest, res: Response) {
  try {
    const companyCode = req.user!.companyCode;
    const { itemCode } = req.params;

    const result = await pool.query(
      `SELECT * FROM item_routing_version WHERE item_code=$1 AND company_code=$2 ORDER BY created_date`,
      [itemCode, 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 });
  }
}

export async function createRoutingVersion(req: AuthenticatedRequest, res: Response) {
  try {
    const companyCode = req.user!.companyCode;
    const writer = req.user!.userId;
    const { item_code, version_name, description, is_default } = req.body;

    if (is_default) {
      await pool.query(
        `UPDATE item_routing_version SET is_default=false WHERE item_code=$1 AND company_code=$2`,
        [item_code, companyCode]
      );
    }

    const result = await pool.query(
      `INSERT INTO item_routing_version (id, company_code, item_code, version_name, description, is_default, writer)
       VALUES (gen_random_uuid()::text, $1, $2, $3, $4, $5, $6) RETURNING *`,
      [companyCode, item_code, version_name, description || "", is_default || false, writer]
    );

    return res.json({ success: true, data: result.rows[0] });
  } catch (error: any) {
    logger.error("라우팅 버전 생성 실패", { error: error.message });
    return res.status(500).json({ success: false, message: error.message });
  }
}

export async function deleteRoutingVersion(req: AuthenticatedRequest, res: Response) {
  try {
    const companyCode = req.user!.companyCode;
    const { id } = req.params;

    await pool.query(
      `DELETE FROM item_routing_detail WHERE routing_version_id=$1 AND company_code=$2`,
      [id, companyCode]
    );
    await pool.query(
      `DELETE FROM item_routing_version WHERE id=$1 AND company_code=$2`,
      [id, companyCode]
    );

    return res.json({ success: true });
  } catch (error: any) {
    logger.error("라우팅 버전 삭제 실패", { error: error.message });
    return res.status(500).json({ success: false, message: error.message });
  }
}

export async function getRoutingDetails(req: AuthenticatedRequest, res: Response) {
  try {
    const companyCode = req.user!.companyCode;
    const { versionId } = req.params;

    const result = await pool.query(
      `SELECT rd.*, pm.process_name
       FROM item_routing_detail rd
       LEFT JOIN process_mng pm ON rd.process_code = pm.process_code AND rd.company_code = pm.company_code
       WHERE rd.routing_version_id=$1 AND rd.company_code=$2
       ORDER BY CAST(rd.seq_no AS INTEGER)`,
      [versionId, 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 });
  }
}

export async function saveRoutingDetails(req: AuthenticatedRequest, res: Response) {
  try {
    const companyCode = req.user!.companyCode;
    const writer = req.user!.userId;
    const { versionId } = req.params;
    const { details } = req.body;

    const client = await pool.connect();
    try {
      await client.query("BEGIN");

      // 기존 상세 삭제 후 재입력
      await client.query(
        `DELETE FROM item_routing_detail WHERE routing_version_id=$1 AND company_code=$2`,
        [versionId, companyCode]
      );

      for (const d of details) {
        await client.query(
          `INSERT INTO item_routing_detail (id, company_code, routing_version_id, seq_no, process_code, is_required, is_fixed_order, work_type, standard_time, outsource_supplier, writer)
           VALUES (gen_random_uuid()::text, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10)`,
          [companyCode, versionId, d.seq_no, d.process_code, d.is_required || "Y", d.is_fixed_order || "Y", d.work_type || "내부", d.standard_time || "0", d.outsource_supplier || "", writer]
        );
      }

      await client.query("COMMIT");
      return res.json({ success: true });
    } catch (err) {
      await client.query("ROLLBACK");
      throw err;
    } finally {
      client.release();
    }
  } catch (error: any) {
    logger.error("라우팅 상세 저장 실패", { error: error.message });
    return res.status(500).json({ success: false, message: error.message });
  }
}

// ═══════════════════════════════════════════
// BOM 구성 자재 조회 (품목코드 기반)
// ═══════════════════════════════════════════

export async function getBomMaterials(req: AuthenticatedRequest, res: Response) {
  try {
    const companyCode = req.user!.companyCode;
    const { itemCode } = req.params;

    if (!itemCode) {
      return res.status(400).json({ success: false, message: "itemCode는 필수입니다" });
    }

    const query = `
      SELECT
        bd.id,
        bd.child_item_id,
        bd.quantity,
        bd.unit as detail_unit,
        bd.process_type,
        i.item_name as child_item_name,
        i.item_number as child_item_code,
        i.type as child_item_type,
        i.unit as item_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 i ON bd.child_item_id = i.id AND bd.company_code = i.company_code
      WHERE b.item_code = $1 AND b.company_code = $2
      ORDER BY bd.seq_no ASC, bd.created_date ASC
    `;

    const result = await pool.query(query, [itemCode, companyCode]);

    logger.info("BOM 자재 조회 성공", { companyCode, itemCode, count: result.rowCount });
    return res.json({ success: true, data: result.rows });
  } catch (error: any) {
    logger.error("BOM 자재 조회 실패", { error: error.message });
    return res.status(500).json({ success: false, message: error.message });
  }
}
