import {
  BadGatewayException,
  BadRequestException,
  Injectable,
  InternalServerErrorException,
} from '@nestjs/common';
import { Resend } from 'resend';
import { basename, join } from 'path';
import { existsSync, readFileSync } from 'fs';
import sanitizeHtml from 'sanitize-html';

type EmailAttachment = {
  filename: string;
  content: string;
};

export type SendMeetingRequestMailParams = {
  to: string[];
  replyTo?: string | null;
  requestId: number;
  title: string;
  description?: string | null;
  ministryName: string;
  workingGroupName: string;
  workingGroupEmail?: string | null;
  meetingRequestLetter?: string | null;
  frontendUrl?: string;
  issues?: {
    title?: string | null;
    description?: string | null;
    recommendation?: string | null;
    issueStatus?: {
      name?: string | null;
    } | null;
    category?: {
      name?: string | null;
    } | null;
  }[];
};

@Injectable()
export class ResendMailMeetingRequestsService {
  async sendMeetingRequestToMinistry(
    params: SendMeetingRequestMailParams,
  ): Promise<string | null> {
    const apiKey = process.env.RESEND_API_KEY;
    const fromEmail = process.env.RESEND_FROM_EMAIL;

    if (!apiKey) {
      throw new InternalServerErrorException('RESEND_API_KEY is missing.');
    }

    if (!fromEmail) {
      throw new InternalServerErrorException('RESEND_FROM_EMAIL is missing.');
    }

    const to = Array.from(
      new Set(
        params.to
          .map((email) => email.trim())
          .filter((email) => this.isValidEmail(email)),
      ),
    );

    if (!to.length) {
      throw new BadRequestException('Ministry email recipient is empty.');
    }

    const replyTo = this.isValidEmail(params.replyTo)
      ? params.replyTo.trim()
      : undefined;

    const resend = new Resend(apiKey);

    const frontendUrl =
      params.frontendUrl || process.env.FRONTEND_URL || 'http://localhost:3000';

    const requestUrl = `${frontendUrl}/pswg/meeting-request/${params.requestId}`;

    const attachments = this.buildAttachments(params.meetingRequestLetter);

    const subject = `New Meeting Request #${params.requestId}: ${params.title}`;

    const html = this.buildHtml({
      ...params,
      requestUrl,
      replyTo,
    });

    const text = this.buildText({
      ...params,
      requestUrl,
      replyTo,
    });

    console.log('RESEND SEND TO:', to);
    console.log('RESEND REPLY TO:', replyTo || '-');
    console.log('RESEND FROM:', fromEmail);
    console.log('RESEND ATTACHMENTS:', attachments.length);

    const { data, error } = await resend.emails.send({
      from: fromEmail,
      to,
      subject,
      replyTo,
      html,
      text,
      attachments: attachments.length ? attachments : undefined,
    });

    console.log('RESEND DATA:', data);
    console.log('RESEND ERROR:', error);

    if (error) {
      throw new BadGatewayException({
        message: 'Failed to send meeting request email by Resend.',
        error,
      });
    }

    return data?.id ? String(data.id) : null;
  }

  private buildAttachments(filePath?: string | null): EmailAttachment[] {
    if (!filePath) {
      return [];
    }

    const cleanPath = filePath.replace(/^\/+/, '');
    const fullPath = join(process.cwd(), cleanPath);

    if (!existsSync(fullPath)) {
      console.warn('Meeting request letter file not found:', fullPath);
      return [];
    }

    return [
      {
        filename: basename(fullPath),
        content: readFileSync(fullPath).toString('base64'),
      },
    ];
  }

  private buildHtml(
    params: SendMeetingRequestMailParams & {
      requestUrl: string;
      replyTo?: string;
    },
  ): string {
    const issueRows = params.issues?.length
      ? params.issues
          .map((issue, index) => {
            return `
              <tr>
                <td style="padding:8px;border:1px solid #ddd;">${index + 1}</td>
                <td style="padding:8px;border:1px solid #ddd;">${this.renderTextEditorHtml(
                  issue.title || '-',
                )}</td>
                <td style="padding:8px;border:1px solid #ddd;">${this.escapeHtml(
                  issue.category?.name || '-',
                )}</td>
                <td style="padding:8px;border:1px solid #ddd;">${this.escapeHtml(
                  issue.issueStatus?.name || '-',
                )}</td>
              </tr>
            `;
          })
          .join('')
      : `
          <tr>
            <td colspan="4" style="padding:8px;border:1px solid #ddd;">
              No issues attached.
            </td>
          </tr>
        `;

    return `
      <div style="font-family: Arial, sans-serif; line-height: 1.6; color: #111;">
        <h2>New Meeting Request</h2>

        <p>Dear ${this.escapeHtml(params.ministryName)},</p>

        <p>A new meeting request has been submitted to your ministry.</p>

        <p><strong>Request ID:</strong> #${params.requestId}</p>

        <p>
          <strong>Title:</strong>
          ${this.escapeHtml(params.title)}
        </p>

        <div style="margin: 12px 0;">
          <strong>Description:</strong>
          <div style="margin-top: 6px;">
            ${this.renderTextEditorHtml(params.description)}
          </div>
        </div>

        <p>
          <strong>From Working Group:</strong>
          ${this.escapeHtml(params.workingGroupName)}
        </p>

        ${
          params.replyTo
            ? `<p><strong>Reply Email:</strong> ${this.escapeHtml(
                params.replyTo,
              )}</p>`
            : ''
        }

        <h3>Issues</h3>

        <table style="border-collapse: collapse; width: 100%;">
          <thead>
            <tr>
              <th style="padding:8px;border:1px solid #ddd;text-align:left;">#</th>
              <th style="padding:8px;border:1px solid #ddd;text-align:left;">Title</th>
              <th style="padding:8px;border:1px solid #ddd;text-align:left;">Category</th>
              <th style="padding:8px;border:1px solid #ddd;text-align:left;">Status</th>
            </tr>
          </thead>
          <tbody>
            ${issueRows}
          </tbody>
        </table>

        <p style="margin-top: 20px;">
          <a
            href="${this.escapeHtml(params.requestUrl)}"
            style="display:inline-block;padding:10px 16px;background:#0f766e;color:#fff;text-decoration:none;border-radius:6px;"
          >
            View Meeting Request
          </a>
        </p>

        <p>Please review the attached meeting request letter if available.</p>

        <p>
          Best regards,<br/>
          G-PSF MIS
        </p>
      </div>
    `;
  }

  private buildText(
    params: SendMeetingRequestMailParams & {
      requestUrl: string;
      replyTo?: string;
    },
  ): string {
    const issueText =
      params.issues
        ?.map((issue, index) => {
          return `${index + 1}. ${this.stripHtml(issue.title || '-')} | ${
            issue.category?.name || '-'
          } | ${issue.issueStatus?.name || '-'}`;
        })
        .join('\n') || 'No issues attached.';

    return `
New Meeting Request

Request ID: #${params.requestId}
Title: ${params.title}
Description: ${this.stripHtml(params.description)}
Ministry: ${params.ministryName}
From Working Group: ${params.workingGroupName}
Reply Email: ${params.replyTo || '-'}

Issues:
${issueText}

View Meeting Request:
${params.requestUrl}

Best regards,
G-PSF MIS
    `.trim();
  }

  private renderTextEditorHtml(value?: string | null): string {
    if (!value || !value.trim()) {
      return '-';
    }

    return sanitizeHtml(value, {
      allowedTags: [
        'p',
        'br',
        'strong',
        'b',
        'em',
        'i',
        'u',
        's',
        'ul',
        'ol',
        'li',
        'span',
        'a',
        'h1',
        'h2',
        'h3',
        'blockquote',
        'pre',
        'code',
      ],
      allowedAttributes: {
        a: ['href', 'target', 'rel'],
        span: ['style'],
        p: ['style'],
        h1: ['style'],
        h2: ['style'],
        h3: ['style'],
        blockquote: ['style'],
      },
      allowedStyles: {
        '*': {
          color: [
            /^#[0-9a-fA-F]{3,8}$/,
            /^rgb\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*\)$/,
            /^rgba\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*,\s*(0|1|0?\.\d+)\s*\)$/,
          ],
          'background-color': [
            /^#[0-9a-fA-F]{3,8}$/,
            /^rgb\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*\)$/,
            /^rgba\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*,\s*(0|1|0?\.\d+)\s*\)$/,
          ],
          'text-align': [/^left$/, /^right$/, /^center$/, /^justify$/],
          'font-weight': [/^\d+$/, /^bold$/, /^normal$/],
          'font-style': [/^italic$/, /^normal$/],
          'text-decoration': [/^underline$/, /^line-through$/, /^none$/],
        },
      },
      allowedSchemes: ['http', 'https', 'mailto'],
      transformTags: {
        a: sanitizeHtml.simpleTransform('a', {
          target: '_blank',
          rel: 'noopener noreferrer',
        }),
      },
    });
  }

  private stripHtml(value?: string | null): string {
    if (!value || !value.trim()) {
      return '-';
    }

    return sanitizeHtml(value, {
      allowedTags: [],
      allowedAttributes: {},
    }).trim();
  }

  private isValidEmail(value?: string | null): value is string {
    if (!value) {
      return false;
    }

    return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value.trim());
  }

  private escapeHtml(value?: string | null): string {
    return String(value || '')
      .replace(/&/g, '&amp;')
      .replace(/</g, '&lt;')
      .replace(/>/g, '&gt;')
      .replace(/"/g, '&quot;')
      .replace(/'/g, '&#039;');
  }
}
