// ============================================================
// SMTP 발송 유틸 — wace MailUtil.sendMailWithAttachFileUTF8 1:1
// ([MailUtil.java:810-1034](../../../../wace_plm/src/com/pms/common/utils/MailUtil.java))
//
// 계정 타입(ERP/SALES/PURCHASE)별 SMTP 분기 — wace Constants.Mail 동일.
// 발송 흐름: mail_log INSERT(is_send='N') → nodemailer 발송
//   → 성공: UPDATE is_send='Y', log_time=NOW()
//   → 실패: UPDATE is_send='N', error_log
// ============================================================

import nodemailer from "nodemailer";
import { getPool } from "../database/db";
import { logger } from "./logger";

export type SmtpAccountType = "ERP" | "SALES" | "PURCHASE";

export interface MailAttachment {
  filename: string;         // 표시될 파일명 (UTF-8 가능)
  path?: string;            // 디스크 경로 (path 또는 content 둘 중 하나)
  content?: Buffer;         // 메모리 바이너리
  contentType?: string;
}

export interface SendMailUTF8Params {
  accountType?: SmtpAccountType;     // 기본 ERP
  fromUserId: string;                // mail_log.send_user_id
  toEmails: string[];                // 수신
  ccEmails?: string[];               // 참조
  bccEmails?: string[];              // 숨은참조
  toUserIds?: string[];              // mail_log.reception_user_id (참고용)
  subject: string;                   // 실제 메일 제목
  subjectForLog?: string;            // mail_log.title (기본: subject 그대로). 그리드 LEFT JOIN용 [OBJID:nnn] 토큰은 호출 측에서 부착.
  html: string;                      // 본문 HTML (text/plain은 \n → <br>로 직접 변환)
  attachments?: MailAttachment[];
  mailType: string;                  // mail_log.mail_type
  important?: "High" | "Normal" | "Low";
}

interface SmtpConfig {
  host: string;
  port: number;
  user: string;
  pass: string;
  secure: boolean;
}

function readSmtpConfig(accountType: SmtpAccountType): SmtpConfig {
  const host = process.env.SMTP_HOST || "";
  const port = parseInt(process.env.SMTP_PORT || "25", 10);
  const secure = (process.env.SMTP_TLS || "false").toLowerCase() === "true";

  let user: string;
  let pass: string;
  switch (accountType) {
    case "SALES":
      user = process.env.SMTP_USER_SALES || "";
      pass = process.env.SMTP_PW_SALES || "";
      break;
    case "PURCHASE":
      user = process.env.SMTP_USER_PURCHASE || "";
      pass = process.env.SMTP_PW_PURCHASE || "";
      break;
    case "ERP":
    default:
      user = process.env.SMTP_USER_ERP || "";
      pass = process.env.SMTP_PW_ERP || "";
      break;
  }

  return { host, port, user, pass, secure };
}

function genMailLogObjid(): string {
  // mail_log.objid (VARCHAR). wace는 CommonUtils.createObjId() 사용 — 우리는 ML-{ms}-{rand} 패턴 통일.
  const ms = Date.now();
  const rand = Math.floor(Math.random() * 1000).toString().padStart(3, "0");
  return `ML-${ms}-${rand}`;
}

/**
 * UTF-8 HTML 본문 + 첨부파일 메일 발송.
 * wace MailUtil.sendMailWithAttachFileUTF8 1:1.
 *
 * @returns { objid: mail_log.objid, sent: 실제 발송 성공 여부 }
 *          SMTP_SEND_SWITCH !== 'Y'면 INSERT만 하고 sent=false 리턴 (wace sendMailSwitch와 동일).
 */
export async function sendMailUTF8(params: SendMailUTF8Params): Promise<{ objid: string; sent: boolean; error?: string }> {
  const accountType: SmtpAccountType = params.accountType || "ERP";
  const cfg = readSmtpConfig(accountType);
  const sendSwitch = (process.env.SMTP_SEND_SWITCH || "Y").toUpperCase() === "Y";

  const subjectForLog = params.subjectForLog && params.subjectForLog.trim() !== ""
    ? params.subjectForLog
    : params.subject;

  // ─── 1. mail_log INSERT (is_send 기본 NULL/N, 발송 후 갱신) ───
  const pool = getPool();
  const objid = genMailLogObjid();
  const receiverTo = params.toEmails.join(", ") + (params.ccEmails && params.ccEmails.length > 0 ? `; cc: ${params.ccEmails.join(", ")}` : "");

  try {
    await pool.query(
      `INSERT INTO mail_log (
         objid, system_name, send_user_id, from_addr,
         reception_user_id, receiver_to,
         title, contents, log_time, is_send, mail_type
       ) VALUES (
         $1, 'vexplor_rps', $2, $3,
         $4, $5,
         $6, $7, NOW(), 'N', $8
       )`,
      [
        objid,
        params.fromUserId,
        cfg.user || null,
        params.toUserIds && params.toUserIds.length > 0 ? params.toUserIds.join(", ") : null,
        receiverTo,
        subjectForLog,
        params.html,
        params.mailType,
      ],
    );
  } catch (logErr) {
    logger.error("mail_log INSERT 실패", { objid, error: (logErr as Error).message });
    throw logErr;
  }

  // ─── 2. 발송 스킵 모드: wace Constants.Mail.sendMailSwitch == false ───
  if (!sendSwitch) {
    logger.warn("SMTP_SEND_SWITCH !== 'Y' — 실제 발송 스킵, mail_log만 기록", { objid });
    return { objid, sent: false };
  }

  // ─── 3. 실제 SMTP 발송 ───
  try {
    if (!cfg.host || !cfg.user) {
      throw new Error(`SMTP 설정 누락 (accountType=${accountType}, host=${cfg.host}, user=${cfg.user})`);
    }
    if (params.toEmails.length === 0) {
      throw new Error("수신인 이메일이 없습니다.");
    }

    const transporter = nodemailer.createTransport({
      host: cfg.host,
      port: cfg.port,
      secure: cfg.secure,
      auth: { user: cfg.user, pass: cfg.pass },
      // wace JavaMail: mail.smtp.starttls.enable=false, mail.smtp.ssl.enable=false, plain auth on 25
      tls: { rejectUnauthorized: false },
      logger: false,
      debug: false,
    });

    const info = await transporter.sendMail({
      from: cfg.user,
      to: params.toEmails.join(", "),
      cc: params.ccEmails && params.ccEmails.length > 0 ? params.ccEmails.join(", ") : undefined,
      bcc: params.bccEmails && params.bccEmails.length > 0 ? params.bccEmails.join(", ") : undefined,
      subject: params.subject,
      html: params.html,
      priority: params.important === "High" ? "high" : params.important === "Low" ? "low" : "normal",
      attachments: params.attachments?.map((a) => ({
        filename: a.filename,
        path: a.path,
        content: a.content,
        contentType: a.contentType,
      })),
    });

    logger.info("메일 발송 성공", { objid, messageId: info.messageId, accountType, to: params.toEmails });

    // mail_log 갱신 — 성공
    await pool.query(
      `UPDATE mail_log SET is_send='Y', log_time=NOW() WHERE objid=$1`,
      [objid],
    );

    return { objid, sent: true };
  } catch (err) {
    const msg = (err as Error).message;
    logger.error("메일 발송 실패", { objid, accountType, error: msg });

    // mail_log 갱신 — 실패. 컬럼이 없으면 best-effort.
    try {
      await pool.query(
        `UPDATE mail_log SET is_send='N', error_log=$2 WHERE objid=$1`,
        [objid, msg],
      );
    } catch (updErr) {
      // error_log 컬럼이 없는 환경에서는 silently skip
      logger.warn("mail_log 실패 상태 기록 스킵 (error_log 컬럼 없을 수 있음)", { objid });
    }

    return { objid, sent: false, error: msg };
  }
}
