/**
 * 간단한 메일 발송 서비스 (쿼리 제외)
 * Nodemailer를 사용한 직접 발송
 */

import nodemailer from 'nodemailer';
import { mailAccountFileService } from './mailAccountFileService';
import { mailTemplateFileService } from './mailTemplateFileService';
import { encryptionService } from './encryptionService';
import { mailSentHistoryService } from './mailSentHistoryService';

export interface SendMailRequest {
  accountId: string;
  templateId?: string;
  modifiedTemplateComponents?: any[]; // 🎯 프론트엔드에서 수정된 템플릿 컴포넌트
  to: string[]; // 받는 사람
  cc?: string[]; // 참조 (Carbon Copy)
  bcc?: string[]; // 숨은참조 (Blind Carbon Copy)
  subject: string;
  variables?: Record<string, string>; // 템플릿 변수 치환
  customHtml?: string; // 템플릿 없이 직접 HTML 작성 시
  attachments?: Array<{ // 첨부파일
    filename: string;
    path: string;
    contentType?: string;
  }>;
}

export interface SendMailResult {
  success: boolean;
  messageId?: string;
  accepted?: string[];
  rejected?: string[];
  error?: string;
}

export interface BulkSendRequest {
  accountId: string;
  templateId?: string; // 템플릿 ID (선택)
  subject: string;
  customHtml?: string; // 직접 작성한 HTML (선택)
  recipients: Array<{
    email: string;
    variables?: Record<string, string>; // 템플릿 사용 시에만 필요
  }>;
}

export interface BulkSendResult {
  total: number;
  success: number;
  failed: number;
  results: Array<{
    email: string;
    success: boolean;
    messageId?: string;
    error?: string;
  }>;
}

class MailSendSimpleService {
  /**
   * 단일 메일 발송 또는 소규모 발송
   */
  async sendMail(request: SendMailRequest): Promise<SendMailResult> {
    let htmlContent = ''; // 상위 스코프로 이동
    
    try {
      // 1. 계정 조회
      const account = await mailAccountFileService.getAccountById(request.accountId);
      if (!account) {
        throw new Error('메일 계정을 찾을 수 없습니다.');
      }

      // 2. 계정 활성화 확인
      if (account.status !== 'active') {
        throw new Error('비활성 상태의 계정입니다.');
      }

      // 3. HTML 생성 (템플릿 + 추가 메시지 병합)
      if (request.templateId) {
        // 템플릿 사용
        const template = await mailTemplateFileService.getTemplateById(request.templateId);
        if (!template) {
          throw new Error('템플릿을 찾을 수 없습니다.');
        }
        
        // 🎯 수정된 컴포넌트가 있으면 덮어쓰기
        if (request.modifiedTemplateComponents && request.modifiedTemplateComponents.length > 0) {
          // console.log('✏️ 수정된 템플릿 컴포넌트 사용:', request.modifiedTemplateComponents.length);
          template.components = request.modifiedTemplateComponents;
        }
        
        htmlContent = this.renderTemplate(template, request.variables);
        
        // 템플릿 + 추가 메시지 병합
        if (request.customHtml && request.customHtml.trim()) {
          htmlContent = this.mergeTemplateAndCustomContent(htmlContent, request.customHtml);
        }
      } else {
        // 직접 작성
        htmlContent = request.customHtml || '';
      }

      if (!htmlContent) {
        throw new Error('메일 내용이 없습니다.');
      }

      // 4. 비밀번호 복호화
      const decryptedPassword = encryptionService.decrypt(account.smtpPassword);
      // // console.log('🔐 비밀번호 복호화 완료');
      // // console.log('🔐 암호화된 비밀번호 (일부):', account.smtpPassword.substring(0, 30) + '...');
      // // console.log('🔐 복호화된 비밀번호 길이:', decryptedPassword.length);

      // 5. SMTP 연결 생성
      // 포트 465는 SSL/TLS를 사용해야 함
      const isSecure = account.smtpPort === 465 ? true : (account.smtpSecure || false);
      
      // // console.log('📧 SMTP 연결 설정:', {
      //   host: account.smtpHost,
      //   port: account.smtpPort,
      //   secure: isSecure,
      //   user: account.smtpUsername,
      // });

      const transporter = nodemailer.createTransport({
        host: account.smtpHost,
        port: account.smtpPort,
        secure: isSecure, // SSL/TLS (포트 465는 자동으로 true)
        auth: {
          user: account.smtpUsername,
          pass: decryptedPassword, // 복호화된 비밀번호 사용
        },
        // 타임아웃 설정 (30초)
        connectionTimeout: 30000,
        greetingTimeout: 30000,
      });

      // console.log('📧 메일 발송 시도 중...');

      // 6. 메일 발송 (CC, BCC, 첨부파일 지원)
      const mailOptions: any = {
        from: `"${account.name}" <${account.email}>`,
        to: request.to.join(', '),
        subject: this.replaceVariables(request.subject, request.variables),
        html: htmlContent,
      };

      // 참조(CC) 추가
      if (request.cc && request.cc.length > 0) {
        mailOptions.cc = request.cc.join(', ');
        // // console.log('📧 참조(CC):', request.cc);
      }

      // 숨은참조(BCC) 추가
      if (request.bcc && request.bcc.length > 0) {
        mailOptions.bcc = request.bcc.join(', ');
        // // console.log('🔒 숨은참조(BCC):', request.bcc);
      }

      // 첨부파일 추가 (한글 파일명 인코딩 처리)
      if (request.attachments && request.attachments.length > 0) {
        mailOptions.attachments = request.attachments.map(att => {
          // 파일명에서 타임스탬프_랜덤숫자_ 부분 제거하여 원본 파일명 복원
          let filename = att.filename.replace(/^\d+-\d+_/, '');
          
          // NFC 정규화 (한글 조합 문자 정규화)
          filename = filename.normalize('NFC');
          
          // ISO-8859-1 호환을 위한 안전한 파일명 생성
          // 한글이 포함된 경우 RFC 2047 MIME 인코딩 사용
          const hasKorean = /[\uAC00-\uD7AF]/.test(filename);
          let safeFilename = filename;
          
          if (hasKorean) {
            // 한글이 포함된 경우: RFC 2047 MIME 인코딩 사용
            safeFilename = `=?UTF-8?B?${Buffer.from(filename, 'utf8').toString('base64')}?=`;
          }
          
          return {
            filename: safeFilename,
            path: att.path,
            contentType: att.contentType,
            // 다중 호환성을 위한 헤더 설정
            headers: {
              'Content-Disposition': `attachment; filename="${safeFilename}"; filename*=UTF-8''${encodeURIComponent(filename)}`
            }
          };
        });
        // console.log('📎 첨부파일 (원본):', request.attachments.map((a: any) => a.filename.replace(/^\d+-\d+_/, '')));
        // console.log('📎 첨부파일 (인코딩):', mailOptions.attachments.map((a: any) => a.filename));
      }

      const info = await transporter.sendMail(mailOptions);

      // console.log('✅ 메일 발송 성공:', {
      //   messageId: info.messageId,
      //   accepted: info.accepted,
      //   rejected: info.rejected,
      // });

      // 발송 이력 저장 (성공)
      try {
        const template = request.templateId
          ? await mailTemplateFileService.getTemplateById(request.templateId)
          : undefined;

        // AttachmentInfo 형식으로 변환
        const attachmentInfos = request.attachments?.map(att => ({
          filename: att.filename,
          originalName: att.filename,
          size: 0, // multer에서 제공하지 않으므로 0으로 설정
          path: att.path,
          mimetype: att.contentType || 'application/octet-stream',
        }));

        await mailSentHistoryService.saveSentMail({
          accountId: account.id,
          accountName: account.name,
          accountEmail: account.email,
          to: request.to,
          cc: request.cc,
          bcc: request.bcc,
          subject: this.replaceVariables(request.subject, request.variables),
          htmlContent,
          templateId: request.templateId,
          templateName: template?.name,
          attachments: attachmentInfos,
          status: 'success',
          messageId: info.messageId,
          accepted: info.accepted as string[],
          rejected: info.rejected as string[],
        });
      } catch (historyError) {
        console.error('발송 이력 저장 실패:', historyError);
        // 이력 저장 실패는 메일 발송 성공에 영향 주지 않음
      }

      return {
        success: true,
        messageId: info.messageId,
        accepted: info.accepted as string[],
        rejected: info.rejected as string[],
      };
    } catch (error) {
      const err = error as Error;
      console.error('❌ 메일 발송 실패:', err.message);
      console.error('❌ 에러 상세:', err);

      // 발송 이력 저장 (실패)
      try {
        // 계정 정보 가져오기 (실패 시에도 필요)
        let accountInfo = { name: 'Unknown', email: 'unknown@example.com' };
        try {
          const acc = await mailAccountFileService.getAccountById(request.accountId);
          if (acc) {
            accountInfo = { name: acc.name, email: acc.email };
          }
        } catch (accError) {
          // 계정 조회 실패는 무시
        }

        const template = request.templateId
          ? await mailTemplateFileService.getTemplateById(request.templateId)
          : undefined;

        // AttachmentInfo 형식으로 변환
        const attachmentInfos = request.attachments?.map(att => ({
          filename: att.filename,
          originalName: att.filename,
          size: 0,
          path: att.path,
          mimetype: att.contentType || 'application/octet-stream',
        }));

        await mailSentHistoryService.saveSentMail({
          accountId: request.accountId,
          accountName: accountInfo.name,
          accountEmail: accountInfo.email,
          to: request.to,
          cc: request.cc,
          bcc: request.bcc,
          subject: request.subject,
          htmlContent: htmlContent || '',
          templateId: request.templateId,
          templateName: template?.name,
          attachments: attachmentInfos,
          status: 'failed',
          errorMessage: err.message,
        });
      } catch (historyError) {
        console.error('발송 이력 저장 실패:', historyError);
      }

      return {
        success: false,
        error: err.message,
      };
    }
  }

  /**
   * 템플릿 렌더링 (일반 메일 양식)
   */
  private renderTemplate(
    template: any,
    variables?: Record<string, string>
  ): string {
    // 일반적인 메일 레이아웃 (전체 너비, 그림자 없음)
    let html = `
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body style="margin: 0; padding: 0; background-color: #ffffff; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;">
  <table role="presentation" style="width: 100%; border-collapse: collapse; background-color: #ffffff;">
    <tr>
      <td style="padding: 20px;">
`;

    template.components.forEach((component: any) => {
      switch (component.type) {
        case 'text':
          let content = component.content || '';
          if (variables) {
            content = this.replaceVariables(content, variables);
          }
          // 텍스트는 왼쪽 정렬, 적절한 줄간격
          html += `<div style="margin: 0 0 20px 0; color: ${component.color || '#333'}; font-size: ${component.fontSize || '15px'}; line-height: 1.6; text-align: left;">${content}</div>`;
          break;
        case 'button':
          let buttonText = component.text || 'Button';
          if (variables) {
            buttonText = this.replaceVariables(buttonText, variables);
          }
          // styles 객체 또는 직접 속성에서 색상 가져오기
          const buttonBgColor = component.styles?.backgroundColor || component.backgroundColor || '#007bff';
          const buttonTextColor = component.styles?.color || component.textColor || '#fff';
          // 버튼은 왼쪽 정렬 (text-align 제거)
          html += `<div style="margin: 30px 0; text-align: left;">
            <a href="${component.url || '#'}" style="display: inline-block; padding: 14px 28px; background-color: ${buttonBgColor}; color: ${buttonTextColor}; text-decoration: none; border-radius: 6px; font-weight: 600; font-size: 15px;">${buttonText}</a>
          </div>`;
          break;
        case 'image':
          // 이미지는 왼쪽 정렬
          html += `<div style="margin: 20px 0; text-align: left;">
            <img src="${component.src}" alt="${component.alt || ''}" style="max-width: 100%; height: auto; display: block; border-radius: 4px;" />
          </div>`;
          break;
        case 'spacer':
          html += `<div style="height: ${component.height || '20px'};"></div>`;
          break;
        case 'header':
          html += `
            <div style="padding: 20px; background-color: ${component.headerBgColor || '#f8f9fa'}; border-radius: 8px; margin-bottom: 20px;">
              <table style="width: 100%;">
                <tr>
                  <td style="vertical-align: middle;">
                    ${component.logoSrc ? `<img src="${component.logoSrc}" alt="로고" style="height: 40px; margin-right: 12px;">` : ''}
                    <span style="font-size: 18px; font-weight: bold;">${component.brandName || ''}</span>
                  </td>
                  <td style="text-align: right; color: #6b7280; font-size: 14px;">
                    ${component.sendDate || ''}
                  </td>
                </tr>
              </table>
            </div>
          `;
          break;
        case 'infoTable':
          html += `
            <div style="border: 1px solid #e5e7eb; border-radius: 8px; overflow: hidden; margin: 16px 0;">
              ${component.tableTitle ? `<div style="background-color: #f9fafb; padding: 12px 16px; font-weight: 600; border-bottom: 1px solid #e5e7eb;">${component.tableTitle}</div>` : ''}
              <table style="width: 100%; border-collapse: collapse;">
                ${(component.rows || []).map((row: any, i: number) => `
                  <tr style="background-color: ${i % 2 === 0 ? '#ffffff' : '#f9fafb'};">
                    <td style="padding: 12px 16px; font-weight: 500; color: #4b5563; width: 35%; border-right: 1px solid #e5e7eb;">${row.label}</td>
                    <td style="padding: 12px 16px;">${row.value}</td>
                  </tr>
                `).join('')}
              </table>
            </div>
          `;
          break;
        case 'alertBox':
          const alertColors: Record<string, { bg: string; border: string; text: string }> = {
            info: { bg: '#eff6ff', border: '#3b82f6', text: '#1e40af' },
            warning: { bg: '#fffbeb', border: '#f59e0b', text: '#92400e' },
            danger: { bg: '#fef2f2', border: '#ef4444', text: '#991b1b' },
            success: { bg: '#ecfdf5', border: '#10b981', text: '#065f46' }
          };
          const colors = alertColors[component.alertType || 'info'];
          html += `
            <div style="padding: 16px; background-color: ${colors.bg}; border-left: 4px solid ${colors.border}; border-radius: 4px; margin: 16px 0; color: ${colors.text};">
              ${component.alertTitle ? `<div style="font-weight: bold; margin-bottom: 8px;">${component.alertTitle}</div>` : ''}
              <div>${component.content || ''}</div>
            </div>
          `;
          break;
        case 'divider':
          html += `<hr style="border: none; border-top: ${component.height || 1}px solid #e5e7eb; margin: 20px 0;">`;
          break;
        case 'footer':
          html += `
            <div style="text-align: center; padding: 24px 16px; background-color: #f9fafb; border-top: 1px solid #e5e7eb; font-size: 14px; color: #6b7280;">
              ${component.companyName ? `<div style="font-weight: 600; color: #374151; margin-bottom: 8px;">${component.companyName}</div>` : ''}
              ${(component.ceoName || component.businessNumber) ? `
                <div style="margin-bottom: 4px;">
                  ${component.ceoName ? `대표: ${component.ceoName}` : ''}
                  ${component.ceoName && component.businessNumber ? ' | ' : ''}
                  ${component.businessNumber ? `사업자등록번호: ${component.businessNumber}` : ''}
                </div>
              ` : ''}
              ${component.address ? `<div style="margin-bottom: 4px;">${component.address}</div>` : ''}
              ${(component.phone || component.email) ? `
                <div style="margin-bottom: 4px;">
                  ${component.phone ? `Tel: ${component.phone}` : ''}
                  ${component.phone && component.email ? ' | ' : ''}
                  ${component.email ? `Email: ${component.email}` : ''}
                </div>
              ` : ''}
              ${component.copyright ? `<div style="margin-top: 12px; font-size: 12px; color: #9ca3af;">${component.copyright}</div>` : ''}
            </div>
          `;
          break;
        case 'numberedList':
          html += `
            <div style="padding: 16px;">
              ${component.listTitle ? `<div style="font-weight: 600; margin-bottom: 12px;">${component.listTitle}</div>` : ''}
              <ol style="margin: 0; padding-left: 20px;">
                ${(component.listItems || []).map((item: string) => `<li style="margin-bottom: 8px;">${item}</li>`).join('')}
              </ol>
            </div>
          `;
          break;
      }
    });

    html += `
      </td>
    </tr>
  </table>
</body>
</html>
`;
    return html;
  }

  /**
   * 변수 치환
   */
  private replaceVariables(
    content: string,
    variables?: Record<string, string>
  ): string {
    if (!variables) return content;

    let result = content;
    Object.entries(variables).forEach(([key, value]) => {
      const regex = new RegExp(`\\{${key}\\}`, 'g');
      result = result.replace(regex, value);
    });

    return result;
  }

  /**
   * 템플릿과 추가 메시지 병합
   * 템플릿 HTML의 body 태그 끝 부분에 추가 메시지를 삽입
   */
  private mergeTemplateAndCustomContent(templateHtml: string, customContent: string): string {
    // customContent에 HTML 태그가 없으면 기본 스타일 적용
    let formattedCustomContent = customContent;
    if (!customContent.includes('<')) {
      // 일반 텍스트인 경우 단락으로 변환
      const paragraphs = customContent
        .split('\n\n')
        .filter((p) => p.trim())
        .map((p) => `<p style="margin: 16px 0; line-height: 1.6;">${p.replace(/\n/g, '<br>')}</p>`)
        .join('');
      
      formattedCustomContent = `
        <div style="margin-top: 32px; padding-top: 24px; border-top: 1px solid #e5e7eb;">
          ${paragraphs}
        </div>
      `;
    } else {
      // 이미 HTML인 경우 구분선만 추가
      formattedCustomContent = `
        <div style="margin-top: 32px; padding-top: 24px; border-top: 1px solid #e5e7eb;">
          ${customContent}
        </div>
      `;
    }

    // </body> 또는 </div> 태그 앞에 삽입
    if (templateHtml.includes('</body>')) {
      return templateHtml.replace('</body>', `${formattedCustomContent}</body>`);
    } else if (templateHtml.includes('</div>')) {
      // 마지막 </div> 앞에 삽입
      const lastDivIndex = templateHtml.lastIndexOf('</div>');
      return (
        templateHtml.substring(0, lastDivIndex) +
        formattedCustomContent +
        templateHtml.substring(lastDivIndex)
      );
    } else {
      // 태그가 없으면 단순 결합
      return templateHtml + formattedCustomContent;
    }
  }

  /**
   * 대량 메일 발송 (배치 처리)
   */
  async sendBulkMail(request: BulkSendRequest): Promise<BulkSendResult> {
    const results: Array<{
      email: string;
      success: boolean;
      messageId?: string;
      error?: string;
    }> = [];

    let successCount = 0;
    let failedCount = 0;

    // console.log(`📧 대량 발송 시작: ${request.recipients.length}명`);

    // 순차 발송 (너무 빠르면 스팸으로 분류될 수 있음)
    for (const recipient of request.recipients) {
      try {
        const result = await this.sendMail({
          accountId: request.accountId,
          templateId: request.templateId, // 템플릿이 있으면 사용
          customHtml: request.customHtml, // 직접 작성한 HTML이 있으면 사용
          to: [recipient.email],
          subject: request.subject,
          variables: recipient.variables || {}, // 템플릿 사용 시에만 필요
        });

        if (result.success) {
          successCount++;
          results.push({
            email: recipient.email,
            success: true,
            messageId: result.messageId,
          });
        } else {
          failedCount++;
          results.push({
            email: recipient.email,
            success: false,
            error: result.error || '발송 실패',
          });
        }
      } catch (error: unknown) {
        const err = error as Error;
        failedCount++;
        results.push({
          email: recipient.email,
          success: false,
          error: err.message,
        });
      }

      // 발송 간격 (500ms) - 스팸 방지
      await new Promise((resolve) => setTimeout(resolve, 500));
    }

    // console.log(`✅ 대량 발송 완료: 성공 ${successCount}, 실패 ${failedCount}`);

    return {
      total: request.recipients.length,
      success: successCount,
      failed: failedCount,
      results,
    };
  }

  /**
   * SMTP 연결 테스트
   */
  async testConnection(accountId: string): Promise<{ success: boolean; message: string }> {
    try {
      const account = await mailAccountFileService.getAccountById(accountId);
      if (!account) {
        return { success: false, message: '메일 계정을 찾을 수 없습니다.' };
      }

      // 비밀번호 복호화
      const decryptedPassword = encryptionService.decrypt(account.smtpPassword);
      // // console.log('🔐 테스트용 비밀번호 복호화 완료');
      // // console.log('🔐 복호화된 비밀번호 길이:', decryptedPassword.length);

      // 포트 465는 SSL/TLS를 사용해야 함
      const isSecure = account.smtpPort === 465 ? true : (account.smtpSecure || false);

      // // console.log('🧪 SMTP 연결 테스트 시작:', {
      //   host: account.smtpHost,
      //   port: account.smtpPort,
      //   secure: isSecure,
      //   user: account.smtpUsername,
      // });

      const transporter = nodemailer.createTransport({
        host: account.smtpHost,
        port: account.smtpPort,
        secure: isSecure,
        auth: {
          user: account.smtpUsername,
          pass: decryptedPassword, // 복호화된 비밀번호 사용
        },
        // 테스트용 타임아웃 (10초)
        connectionTimeout: 10000,
        greetingTimeout: 10000,
      });

      // 연결 테스트
      await transporter.verify();
      
      // console.log('✅ SMTP 연결 테스트 성공');
      return { success: true, message: 'SMTP 연결이 성공했습니다.' };
    } catch (error) {
      const err = error as Error;
      console.error('❌ SMTP 연결 테스트 실패:', err.message);
      return { success: false, message: `SMTP 연결 실패: ${err.message}` };
    }
  }
}

export const mailSendSimpleService = new MailSendSimpleService();