import { NextRequest, NextResponse } from "next/server";
import crypto from "node:crypto";
import { z } from "zod";
import { db, supportTickets, supportTicketAttachments, eq, desc } from "@epicure/db";
import { requireSession } from "@/lib/api-auth";
import { sendEmail, supportTicketReceivedHtml } from "@/lib/email";
import { createGiteaIssue, buildGiteaIssueBody } from "@/lib/gitea";
import { getPublicUrl, isOwnedSupportAttachmentKey } from "@/lib/storage";
import { dispatchAdminWebhook } from "@/lib/admin-webhooks";

const MAX_ATTACHMENTS = 5;

const CreateTicketBody = z.object({
  type: z.enum(["bug", "suggestion", "question"]),
  title: z.string().trim().min(3).max(200),
  description: z.string().trim().min(10).max(5000),
  attachments: z
    .array(z.object({
      key: z.string().min(1).max(500),
      contentType: z.string().min(1).max(100),
      sizeBytes: z.number().int().positive(),
    }))
    .max(MAX_ATTACHMENTS)
    .default([]),
});

export async function GET() {
  const { session, response } = await requireSession();
  if (response) return response;

  const rows = await db.query.supportTickets.findMany({
    where: eq(supportTickets.userId, session!.user.id),
    orderBy: desc(supportTickets.createdAt),
    with: { attachments: true },
  });

  return NextResponse.json(
    rows.map((r) => ({
      ...r,
      attachments: r.attachments.map((a) => ({ ...a, url: getPublicUrl(a.storageKey) })),
    }))
  );
}

export async function POST(req: NextRequest) {
  const { session, response } = await requireSession();
  if (response) return response;

  const body = (await req.json()) as unknown;
  const parsed = CreateTicketBody.safeParse(body);
  if (!parsed.success) {
    return NextResponse.json(
      { error: "Validation error", issues: parsed.error.issues },
      { status: 400 }
    );
  }

  const { type, title, description, attachments } = parsed.data;

  for (const a of attachments) {
    if (!isOwnedSupportAttachmentKey(a.key, session!.user.id)) {
      return NextResponse.json({ error: "Invalid attachment" }, { status: 400 });
    }
  }

  const id = crypto.randomUUID();
  const now = new Date();

  const { url: giteaIssueUrl, number: giteaIssueNumber, error: giteaError } = await createGiteaIssue({
    type,
    title,
    body: buildGiteaIssueBody({ description, userId: session!.user.id, attachments }),
  });

  await db.insert(supportTickets).values({
    id,
    userId: session!.user.id,
    type,
    title,
    description,
    status: "open",
    giteaIssueUrl,
    giteaIssueNumber,
    giteaError,
    createdAt: now,
    updatedAt: now,
  });

  void dispatchAdminWebhook("support_ticket.created", { id, userId: session!.user.id, type, title });

  if (attachments.length > 0) {
    await db.insert(supportTicketAttachments).values(
      attachments.map((a) => ({
        id: crypto.randomUUID(),
        ticketId: id,
        storageKey: a.key,
        contentType: a.contentType,
        sizeBytes: a.sizeBytes,
        createdAt: now,
      }))
    );
  }

  const baseUrl = process.env["BETTER_AUTH_URL"] ?? "http://localhost:3000";
  const ticketUrl = `${baseUrl}/support`;
  if (session!.user.email) {
    try {
      await sendEmail({
        to: session!.user.email,
        subject: "We got your message — Epicure",
        html: supportTicketReceivedHtml({ type, title, ticketUrl, giteaIssueUrl }),
      });
    } catch {
      // Ticket is saved either way — email failure shouldn't fail the request.
    }
  }

  return NextResponse.json(
    {
      id,
      userId: session!.user.id,
      type,
      title,
      description,
      status: "open" as const,
      giteaIssueUrl,
      giteaError,
      createdAt: now.toISOString(),
      updatedAt: now.toISOString(),
      attachments: attachments.map((a) => ({
        id: "",
        storageKey: a.key,
        contentType: a.contentType,
        sizeBytes: a.sizeBytes,
        url: getPublicUrl(a.key),
      })),
    },
    { status: 201 }
  );
}
