import { NextResponse } from 'next/server';
import { eq } from 'drizzle-orm';
import { z } from 'zod';

import { withAuth, withPermission } from '@/lib/api/helpers';
import { db } from '@/lib/db';
import { ports } from '@/lib/db/schema/ports';
import { errorResponse, NotFoundError, ValidationError } from '@/lib/errors';
import { parseBody } from '@/lib/api/route-helpers';
import { getPortBrandingConfig } from '@/lib/services/port-config';
import { getBrandingShell } from '@/lib/email/branding-resolver';
import { renderShell } from '@/lib/email/shell';
import { sendEmail } from '@/lib/email';
import { findTestTemplate } from '@/lib/email/test-registry';

const SAMPLE_SUBJECT_SUFFIX = ' - branding preview';

function buildSampleEmail(branding: {
  logoUrl: string | null;
  emailBackgroundUrl: string | null;
  primaryColor: string;
  appName: string;
  emailHeaderHtml: string | null;
  emailFooterHtml: string | null;
}): { subject: string; html: string } {
  const subject = `${branding.appName}${SAMPLE_SUBJECT_SUFFIX}`;
  const body = `
    <h1 style="font-size:20px;margin:0 0 12px;color:${branding.primaryColor};">A sample notification</h1>
    <p style="margin:0 0 12px;color:#334155;">Hi there,</p>
    <p style="margin:0 0 12px;color:#334155;">
      This is a preview of how transactional emails from <strong>${branding.appName}</strong>
      will look using the current branding settings (logo, background image, primary color,
      and any custom header/footer HTML you've added).
    </p>
    <p style="margin:0 0 12px;">
      <a href="https://example.com" style="display:inline-block;padding:10px 18px;background-color:${branding.primaryColor};color:#ffffff;text-decoration:none;border-radius:6px;font-weight:600;">
        Primary action button
      </a>
    </p>
    <p style="margin:0;color:#64748b;font-size:13px;">
      Adjust the values in the Identity and Email branding cards above, save, then refresh the
      preview to see your changes.
    </p>
  `;
  const html = renderShell({
    title: subject,
    body,
    branding: {
      logoUrl: branding.logoUrl,
      backgroundUrl: branding.emailBackgroundUrl,
      primaryColor: branding.primaryColor,
      emailHeaderHtml: branding.emailHeaderHtml,
      emailFooterHtml: branding.emailFooterHtml,
    },
  });
  return { subject, html };
}

/**
 * Render one of the registered transactional templates with realistic
 * sample fixtures + the current port's branding. Falls back to the
 * generic "branding preview" sample when no templateId is supplied
 * (preserves the original card behaviour).
 */
async function renderTemplatePreview(
  portId: string,
  templateId: string | null,
): Promise<{ subject: string; html: string }> {
  if (!templateId) {
    const branding = await getPortBrandingConfig(portId);
    return buildSampleEmail(branding);
  }
  const template = findTestTemplate(templateId);
  if (!template) throw new ValidationError(`Unknown templateId: ${templateId}`);
  const port = await db.query.ports.findFirst({ where: eq(ports.id, portId) });
  if (!port) throw new NotFoundError('Port');
  const branding = await getBrandingShell(portId);
  const rendered = await template.render({
    recipientName: 'Sample Recipient',
    recipientEmail: 'sample@example.com',
    portName: port.name,
    portUrl: `https://${port.slug}.example`,
    branding,
  });
  return { subject: rendered.subject, html: rendered.html };
}

// GET - return the sample email rendered with the current port's branding.
// Optional ?templateId=<id> renders a real transactional template instead
// of the generic sample (e.g. crm_invite, portal_activation, signing_*).
export const GET = withAuth(
  withPermission('admin', 'manage_settings', async (req, ctx) => {
    try {
      if (!ctx.portId) throw new ValidationError('No active port');
      const templateId = new URL(req.url).searchParams.get('templateId');
      const { subject, html } = await renderTemplatePreview(ctx.portId, templateId);
      return NextResponse.json({ data: { subject, html } });
    } catch (error) {
      return errorResponse(error);
    }
  }),
);

const sendTestSchema = z.object({
  recipient: z.string().email('Enter a valid email address'),
  /** Optional - same templateId surface as the GET endpoint. */
  templateId: z.string().optional().nullable(),
});

// POST - actually send the sample email to a single recipient.
export const POST = withAuth(
  withPermission('admin', 'manage_settings', async (req, ctx) => {
    try {
      if (!ctx.portId) throw new ValidationError('No active port');
      const { recipient, templateId } = await parseBody(req, sendTestSchema);
      const { subject, html } = await renderTemplatePreview(ctx.portId, templateId ?? null);
      await sendEmail(recipient, subject, html);
      return NextResponse.json({ data: { sent: true, recipient } });
    } catch (error) {
      return errorResponse(error);
    }
  }),
);
