import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { ClsService } from 'nestjs-cls';
import { BookingActivityItemEntity } from '../../../entities/booking-activity-item.entity';
import {
  ActivityTicketItemEntity,
  TicketItemStatus,
} from '../../../entities/activity-ticket-item.entity';
import { MailerService } from '../../mailer/mailer.service';
import { CLS_TENANT_ID, CLS_USER_ID } from '../../../common/cls/cls.constants';

/** Minimal HTML escape for values interpolated into the email body. */
function esc(v: unknown): string {
  return String(v ?? '')
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, '&#39;');
}

/**
 * Emails an activity ticket link from the Movement Dashboard. Phase-1
 * recipient is the logged-in user (client decision 2026-10-14) — a
 * per-tenant recipient list can replace it later without FE changes.
 */
@Injectable()
export class ActivityTicketMailService {
  constructor(
    @InjectRepository(BookingActivityItemEntity)
    private readonly activityItemRepo: Repository<BookingActivityItemEntity>,
    @InjectRepository(ActivityTicketItemEntity)
    private readonly ticketItemRepo: Repository<ActivityTicketItemEntity>,
    private readonly mailer: MailerService,
    private readonly cls: ClsService,
  ) {}

  /**
   * @param apiOrigin  public origin serving `/api/uploads/*` — used to
   *                   turn the stored relative link into a clickable one.
   */
  async emailTicket(itemId: string, apiOrigin: string): Promise<{ sent_to: string }> {
    const tenantId = this.cls.get<string>(CLS_TENANT_ID);
    const userId = this.cls.get<string>(CLS_USER_ID);
    if (!tenantId || !userId) throw new BadRequestException('No user context');

    const item = await this.activityItemRepo.findOne({
      where: { id: itemId, tenant_id: tenantId, is_deleted: false },
      relations: { booking: { query: true }, activity: true, ticket: true },
    });
    if (!item) throw new NotFoundException('Activity item not found');

    const assigned = await this.ticketItemRepo.findOne({
      where: {
        booking_activity_item_id: itemId,
        tenant_id: tenantId,
        status: TicketItemStatus.ASSIGNED,
        is_deleted: false,
      },
      select: { id: true, ticket_ref_no: true, document_url: true },
    });
    const rawUrl = assigned?.document_url || item.ticket_file_url;
    if (!rawUrl) throw new BadRequestException('No ticket file on this activity yet');
    const link = rawUrl.startsWith('/') ? `${apiOrigin.replace(/\/+$/, '')}${rawUrl}` : rawUrl;

    const users: Array<{ email: string; name: string | null }> =
      await this.activityItemRepo.manager.query(
        `SELECT email, name FROM users WHERE id = $1 AND tenant_id = $2 AND is_deleted = false LIMIT 1`,
        [userId, tenantId],
      );
    const user = users[0];
    if (!user?.email) throw new BadRequestException('Your account has no email address');

    const company: Array<{ company_name: string | null }> =
      await this.activityItemRepo.manager.query(
        `SELECT company_name FROM tenant_settings WHERE tenant_id = $1 LIMIT 1`,
        [tenantId],
      );

    const q = item.booking?.query;
    const rows: Array<[string, unknown]> = [
      ['Booking', item.booking?.booking_number],
      ['Guest', q?.guest_name],
      ['Guest mobile', q?.guest_mobile],
      ['Activity', item.activity?.name],
      ['Ticket type', item.ticket?.name],
      ['Date', item.date],
      ['Ticket ref', assigned?.ticket_ref_no],
    ];
    const html = `
      <p>Hi ${esc(user.name || '')},</p>
      <p>The ticket for this activity is ready:</p>
      <table cellpadding="4" style="border-collapse:collapse;font-family:Arial,sans-serif;font-size:14px">
        ${rows
          .filter(([, v]) => v)
          .map(
            ([k, v]) =>
              `<tr><td style="color:#6b7280">${esc(k)}</td><td><b>${esc(v)}</b></td></tr>`,
          )
          .join('')}
      </table>
      <p><a href="${esc(link)}">View / download ticket</a></p>
      <p style="color:#6b7280;font-size:12px">Sent from the Movement Dashboard.</p>`;

    await this.mailer.send({
      to: { email: user.email, ...(user.name ? { name: user.name } : {}) },
      subject:
        `Ticket — ${item.activity?.name ?? 'Activity'} · ${item.booking?.booking_number ?? ''}`.trim(),
      html,
      fromName: company[0]?.company_name || undefined,
    });
    return { sent_to: user.email };
  }
}
