// src/lib/support/actions.ts — client-side support ticketing server actions (ELEVA-104).
"use server";
import { randomUUID } from "node:crypto";
import { desc, eq } from "drizzle-orm";
import { revalidatePath } from "next/cache";
import { z } from "zod";
import { getActiveOrgId, getActiveUserId } from "@/lib/active-org";
import { isCurrentUserSuperAdmin } from "@/lib/auth/super-admin";
import { user } from "@/lib/db/auth-schema";
import { db } from "@/lib/db/client";
import { supportMessages, supportTickets } from "@/lib/db/domain-schema";
import type { Ticket, TicketMessage, TicketThread } from "./types";

const createTicketSchema = z.object({
  title: z.string().trim().min(1, "Titre requis").max(256),
  content: z.string().trim().min(1, "Message requis").max(5000),
  priority: z.enum(["low", "medium", "high"]),
});

const messageSchema = z.string().trim().min(1, "Message requis").max(5000);

/**
 * Open a new ticket (status "open") plus the first client message. Auth required.
 * Returns the new ticket id.
 */
export async function createTicketAction(input: {
  title: string;
  content: string;
  priority: string;
}): Promise<string> {
  const userId = await getActiveUserId();
  // orgId is best-effort context; null is allowed by the schema.
  let orgId: string | null = null;
  try {
    orgId = await getActiveOrgId();
  } catch {
    orgId = null;
  }

  const { title, content, priority } = createTicketSchema.parse(input);

  const ticketId = randomUUID();
  await db.insert(supportTickets).values({
    id: ticketId,
    title,
    status: "open",
    priority,
    userId,
    orgId,
  });
  await db.insert(supportMessages).values({
    id: randomUUID(),
    ticketId,
    senderId: userId,
    senderType: "client",
    content,
  });

  revalidatePath("/support");
  return ticketId;
}

/**
 * Post a reply to a ticket. Auth required. Access: ticket owner OR staff
 * (super-admin). Throws if the ticket is resolved (lock — UI also blocks).
 * senderType = "staff" when the caller is a super-admin, else "client".
 */
export async function postMessageAction(
  ticketId: string,
  content: string,
): Promise<void> {
  const userId = await getActiveUserId();
  const parsed = messageSchema.parse(content);

  const [ticket] = await db
    .select()
    .from(supportTickets)
    .where(eq(supportTickets.id, ticketId));
  if (!ticket) throw new Error("Ticket introuvable");

  const isStaff = await isCurrentUserSuperAdmin();
  const isOwner = ticket.userId === userId;
  if (!isOwner && !isStaff) throw new Error("Accès refusé");

  if (ticket.status === "resolved") {
    throw new Error("Ticket résolu — la réponse est fermée.");
  }

  await db.insert(supportMessages).values({
    id: randomUUID(),
    ticketId,
    senderId: userId,
    senderType: isStaff ? "staff" : "client",
    content: parsed,
  });
  await db
    .update(supportTickets)
    .set({ updatedAt: new Date() })
    .where(eq(supportTickets.id, ticketId));

  revalidatePath(`/support/${ticketId}`);
}

/** The caller's own tickets, newest-updated first. */
export async function getMyTicketsAction(): Promise<Ticket[]> {
  const userId = await getActiveUserId();
  const rows = await db
    .select()
    .from(supportTickets)
    .where(eq(supportTickets.userId, userId))
    .orderBy(desc(supportTickets.updatedAt));
  return rows;
}

/**
 * A ticket + its ordered messages (with sender display names). Access check:
 * owner OR staff. Returns null if not found or forbidden.
 */
export async function getTicketThreadAction(
  ticketId: string,
): Promise<TicketThread | null> {
  const userId = await getActiveUserId();

  const [ticket] = await db
    .select()
    .from(supportTickets)
    .where(eq(supportTickets.id, ticketId));
  if (!ticket) return null;

  const isStaff = await isCurrentUserSuperAdmin();
  if (ticket.userId !== userId && !isStaff) return null;

  const rows = await db
    .select({
      id: supportMessages.id,
      ticketId: supportMessages.ticketId,
      senderId: supportMessages.senderId,
      senderType: supportMessages.senderType,
      content: supportMessages.content,
      createdAt: supportMessages.createdAt,
      senderName: user.name,
    })
    .from(supportMessages)
    .leftJoin(user, eq(supportMessages.senderId, user.id))
    .where(eq(supportMessages.ticketId, ticketId))
    .orderBy(supportMessages.createdAt);

  const messages: TicketMessage[] = rows;
  return { ticket, messages };
}
