/**
 * ECR(Engineering Change Request) 관리 서비스
 *  - wace_plm 의 ECRController + ECRService + ecr.xml 을 Node 로 포팅
 *  - 동일 화면/동일 동작을 목표로 컬럼 명세 그대로 유지
 *  - PostgreSQL 기준 (원본도 PG)
 */
import { query, queryOne, transaction } from "../database/db";
import { logger } from "../utils/logger";

export interface EcrListParams {
  year?: string;
  productCode?: string;
  requestCode?: string;
  writer?: string;
  statusCode?: string;
  page?: number;
  pageSize?: number;
}

export interface EcrUpsertParams {
  objId?: string | number;
  product_objid?: string | number | null;
  part_objid?: string | number | null;
  request_codeArr?: string; // 콤마 구분 다중 코드
  title?: string;
  before_contents?: string;
  after_contents?: string;
  writer: string;
}

const SELECT_BASE = `
  SELECT
      T.objid::text AS objid,
      T.ecr_no,
      (SELECT product_code FROM product_mgmt WHERE objid = T.product_objid) AS product_name,
      T.product_objid::text AS product_objid,
      T.upg_no,
      T.part_objid::text AS part_objid,
      (SELECT part_no   FROM part_mng WHERE objid = T.part_objid) AS part_no,
      (SELECT part_name FROM part_mng WHERE objid = T.part_objid) AS part_name,
      T.request_cd,
      T.title,
      T.writer,
      (SELECT user_name FROM user_info WHERE user_id = T.writer)        AS writer_name,
      T.status_cd,
      -- wace_plm 의 code_name(varchar) 함수를 그대로 사용 (ecrTableMigration 에서 함수도 동일 정의)
      code_name(T.status_cd)                                            AS status_name,
      (SELECT user_name FROM user_info WHERE user_id = T.check_user_id) AS check_name,
      T.check_user_id,
      T.before_contents,
      T.after_contents,
      TO_CHAR(T.reg_date,   'YYYY-MM-DD') AS reg_date,
      TO_CHAR(T.check_date, 'YYYY-MM-DD') AS check_date,
      -- 요청 코드 콤마 분리 → code_name 콤마 결합 (원본 자바와 동일)
      (
        SELECT array_to_string(
                 array_agg((SELECT code_name FROM comm_code cc WHERE cc.code_id = trim(req))),
                 ', '
               )
        FROM unnest(string_to_array(coalesce(T.request_cd, ''), ',')) AS req
      ) AS request_name,
      -- ilshin 운영 ecr_mng 와 동기화된 신규 컬럼 (docs/migration/quality/01_*.sql)
      T.project_no,
      T.customer_cd,
      T.equip_name,
      T.design_dept,
      T.unit_cd,
      T.memo,
      T.check_result
  FROM ecr_mng T
`;

export class EcrMngService {
  /** 목록 (페이징 + 필터) */
  static async list(p: EcrListParams) {
    const page = Math.max(1, Number(p.page) || 1);
    const pageSize = Math.max(1, Math.min(200, Number(p.pageSize) || 20));
    const offset = (page - 1) * pageSize;

    const where: string[] = ["1=1"];
    const args: any[] = [];
    let i = 1;

    if (p.year) {
      where.push(`TO_CHAR(T.reg_date, 'YYYY') = $${i++}`);
      args.push(p.year);
    }
    if (p.productCode) {
      where.push(`T.product_objid = $${i++}::bigint`);
      args.push(p.productCode);
    }
    if (p.requestCode) {
      where.push(`UPPER(T.request_cd) LIKE UPPER('%' || $${i++} || '%')`);
      args.push(p.requestCode);
    }
    if (p.writer) {
      where.push(`T.writer = $${i++}`);
      args.push(p.writer);
    }
    if (p.statusCode) {
      where.push(`T.status_cd = $${i++}`);
      args.push(p.statusCode);
    }
    const whereSql = where.join(" AND ");

    const cntRow = await queryOne<{ total: string }>(
      `SELECT COUNT(1)::int AS total FROM ecr_mng T WHERE ${whereSql}`,
      args,
    );
    const total = Number(cntRow?.total || 0);

    const rows = await query<any>(
      `${SELECT_BASE} WHERE ${whereSql} ORDER BY T.reg_date DESC, T.objid DESC LIMIT $${i++} OFFSET $${i++}`,
      [...args, pageSize, offset],
    );

    return {
      list: rows,
      pagination: { page, pageSize, total, totalPages: Math.ceil(total / pageSize) },
    };
  }

  /** 단건 상세 */
  static async detail(objId: string | number) {
    const row = await queryOne<any>(
      `${SELECT_BASE} WHERE T.objid = $1::bigint`,
      [objId],
    );
    return row;
  }

  /**
   * 등록/수정 (mergeECR)
   * 원본: ON CONFLICT (OBJID) DO UPDATE …
   *   신규 시 ECR_NO 자동 채번: ECR-YYYY-{seq_ecr_no:3자리}
   */
  static async merge(p: EcrUpsertParams) {
    const objId = p.objId ? String(p.objId) : `${Date.now()}`; // 신규 시 epoch 기반 OBJID
    return await transaction(async (client) => {
      const r = await client.query(
        `
        INSERT INTO ecr_mng
          (objid, ecr_no, product_objid, part_objid, request_cd, title, writer,
           status_cd, before_contents, after_contents, reg_date)
        VALUES
          ($1::bigint,
           'ECR-' || TO_CHAR(NOW(), 'YYYY') || '-' || LPAD(nextval('seq_ecr_no')::TEXT, 3, '0'),
           NULLIF($2,'')::bigint, NULLIF($3,'')::bigint, $4, $5, $6,
           '0000100', $7, $8, NOW())
        ON CONFLICT (objid) DO UPDATE SET
            title           = EXCLUDED.title,
            product_objid   = EXCLUDED.product_objid,
            part_objid      = EXCLUDED.part_objid,
            request_cd      = EXCLUDED.request_cd,
            before_contents = EXCLUDED.before_contents
        RETURNING objid, ecr_no, status_cd
        `,
        [
          objId,
          p.product_objid ? String(p.product_objid) : "",
          p.part_objid ? String(p.part_objid) : "",
          p.request_codeArr || "",
          p.title || "",
          p.writer,
          p.before_contents || "",
          p.after_contents || "",
        ],
      );
      return r.rows[0];
    });
  }

  /**
   * 조치완료 (completeECR)
   *  - status_cd → '0000102'(조치완료), after_contents 갱신, check_user_id/check_date 기록
   */
  static async complete(p: { objId: string | number; after_contents?: string; writer: string }) {
    const r = await query<any>(
      `
      UPDATE ecr_mng
      SET status_cd      = '0000102',
          after_contents = $1,
          check_user_id  = $2,
          check_date     = NOW()
      WHERE objid = $3::bigint
      RETURNING objid, status_cd
      `,
      [p.after_contents || "", p.writer, p.objId],
    );
    return r[0];
  }

  /** 삭제 (단건 또는 콤마 다중) */
  static async deleteByIds(ids: Array<string | number>) {
    if (!ids?.length) return { deleted: 0 };
    return await transaction(async (client) => {
      const r = await client.query(
        `DELETE FROM ecr_mng WHERE objid = ANY($1::bigint[]) RETURNING objid`,
        [ids.map((x) => String(x))],
      );
      return { deleted: r.rowCount || 0 };
    });
  }

  /** 작성자 select 옵션 — 원본 common.getUserselect 유사 */
  static async writerOptions() {
    return await query<any>(
      `SELECT user_id AS value, user_name AS label FROM user_info
        WHERE status='active' AND user_id IS NOT NULL AND user_id <> ''
        ORDER BY user_name`,
    );
  }

  /** 제품 select 옵션 — 원본 common.getProductCodeselect 유사 */
  static async productOptions() {
    return await query<any>(
      `SELECT objid::text AS value, COALESCE(product_code, product_name) AS label
         FROM product_mgmt
        WHERE COALESCE(status,'active') = 'active'
        ORDER BY product_code, product_name`,
    );
  }

  /** 부품 select 옵션 */
  static async partOptions() {
    return await query<any>(
      `SELECT objid::text AS value,
              COALESCE(part_no, part_name) || COALESCE(' (' || part_name || ')', '') AS label
         FROM part_mng
        WHERE COALESCE(status,'active') = 'active'
        ORDER BY part_no`,
    );
  }

  /** 공통코드 child 옵션 (parent_code_id 기준) */
  static async commCodeOptions(parentCodeId: string) {
    return await query<any>(
      `SELECT code_id AS value, code_name AS label
         FROM comm_code
        WHERE parent_code_id = $1 AND COALESCE(status,'active') = 'active'
        ORDER BY sort_order, code_name`,
      [parentCodeId],
    );
  }
}
