"use server";

import { auth } from "@/auth";
import { db } from "@/lib/db";
import { hasPermission } from "@/lib/permissions";
import { CREWING_ENABLED } from "@/lib/feature-flags";
import { generateEmployeeId } from "@/lib/employee-number";
import { maybeCreateSiteStaffLogin } from "@/lib/crew-login";
import { CrewStatus, CandidateType, CandidateSource } from "@prisma/client";
import { z } from "zod";
import { revalidatePath } from "next/cache";

type ActionResult = { ok: true; id?: string } | { error: string };
const PATH = "/admin/crew";

async function guard(): Promise<{ error: string } | { userId: string }> {
  if (!CREWING_ENABLED) return { error: "Crewing is not enabled" };
  const session = await auth();
  if (!session?.user) return { error: "Unauthorized" };
  if (!hasPermission(session.user.role, "manage_crew")) return { error: "Unauthorized" };
  return { userId: session.user.id };
}

const crewSchema = z.object({
  name: z.string().trim().min(1, "Name is required"),
  status: z.nativeEnum(CrewStatus).default("CANDIDATE"),
  type: z.nativeEnum(CandidateType).default("NEW"),
  source: z.nativeEnum(CandidateSource).default("CAREERS"),
  email: z.string().trim().email("Enter a valid email").optional().or(z.literal("")),
  phone: z.string().optional(),
  appliedRankId: z.string().optional(),
  currentRankId: z.string().optional(),
  experienceMonths: z.coerce.number().int().min(0).max(720).default(0),
});

function parse(formData: FormData) {
  return crewSchema.safeParse({
    name: formData.get("name"),
    status: (formData.get("status") as string) || undefined,
    type: (formData.get("type") as string) || undefined,
    source: (formData.get("source") as string) || undefined,
    email: (formData.get("email") as string) || undefined,
    phone: (formData.get("phone") as string) || undefined,
    appliedRankId: (formData.get("appliedRankId") as string) || undefined,
    currentRankId: (formData.get("currentRankId") as string) || undefined,
    experienceMonths: (formData.get("experienceMonths") as string) || undefined,
  });
}

export async function createCrewMember(formData: FormData): Promise<ActionResult> {
  const g = await guard();
  if ("error" in g) return g;
  const parsed = parse(formData);
  if (!parsed.success) return { error: parsed.error.errors[0]?.message ?? "Validation failed" };
  const d = parsed.data;

  const crew = await db.crewMember.create({
    data: {
      name: d.name, status: d.status, type: d.type, source: d.source,
      email: d.email || null, phone: d.phone || null,
      appliedRankId: d.appliedRankId || null, currentRankId: d.currentRankId || null,
      experienceMonths: d.experienceMonths,
      actions: { create: { actionType: "CANDIDATE_ADDED", actorId: g.userId } },
    },
  });
  revalidatePath(PATH);
  return { ok: true, id: crew.id };
}

export async function updateCrewMember(formData: FormData): Promise<ActionResult> {
  const g = await guard();
  if ("error" in g) return g;
  const id = formData.get("id") as string;
  if (!id) return { error: "Crew ID is required" };
  const parsed = parse(formData);
  if (!parsed.success) return { error: parsed.error.errors[0]?.message ?? "Validation failed" };
  const d = parsed.data;
  if (!(await db.crewMember.findUnique({ where: { id }, select: { id: true } }))) return { error: "Crew member not found" };

  await db.crewMember.update({
    where: { id },
    data: {
      name: d.name, status: d.status, type: d.type, source: d.source,
      email: d.email || null, phone: d.phone || null,
      appliedRankId: d.appliedRankId || null, currentRankId: d.currentRankId || null,
      experienceMonths: d.experienceMonths,
      actions: { create: { actionType: "CANDIDATE_UPDATED", actorId: g.userId } },
    },
  });
  revalidatePath(PATH);
  return { ok: true };
}

export async function deleteCrewMember(id: string): Promise<ActionResult> {
  const g = await guard();
  if ("error" in g) return g;
  const crew = await db.crewMember.findUnique({
    where: { id },
    select: { _count: { select: { assignments: true, applications: true } } },
  });
  if (!crew) return { error: "Crew member not found" };
  if (crew._count.assignments > 0 || crew._count.applications > 0) {
    return { error: "Cannot delete: this crew member has assignments or applications. Remove those first." };
  }
  await db.crewAction.deleteMany({ where: { crewMemberId: id } });
  await db.crewMember.delete({ where: { id } });
  revalidatePath(PATH);
  return { ok: true };
}

// ── Direct placement (Manager) — assign crew to a vessel/site, no requisition ──

const placeSchema = z
  .object({
    crewMemberId: z.string().min(1, "Crew member is required"),
    rankId: z.string().min(1, "Rank is required"),
    vesselId: z.string().optional(),
    siteId: z.string().optional(),
    signOnDate: z.string().min(1, "Joining date is required"),
  })
  .refine((d) => Boolean(d.vesselId) || Boolean(d.siteId), { message: "A vessel or site is required" });

export async function placeCrew(formData: FormData): Promise<ActionResult> {
  const g = await guard();
  if ("error" in g) return g;

  const parsed = placeSchema.safeParse({
    crewMemberId: formData.get("crewMemberId"),
    rankId: formData.get("rankId"),
    vesselId: (formData.get("vesselId") as string) || undefined,
    siteId: (formData.get("siteId") as string) || undefined,
    signOnDate: formData.get("signOnDate"),
  });
  if (!parsed.success) return { error: parsed.error.errors[0]?.message ?? "Validation failed" };
  const d = parsed.data;

  const crew = await db.crewMember.findUnique({
    where: { id: d.crewMemberId },
    include: { assignments: { where: { status: { not: "SIGNED_OFF" } }, select: { id: true } } },
  });
  if (!crew) return { error: "Crew member not found" };
  if (crew.assignments.length > 0) return { error: "This crew member already has an active assignment" };

  await db.$transaction(async (tx) => {
    await tx.crewAssignment.create({
      data: {
        status: "ACTIVE",
        signOnDate: new Date(d.signOnDate),
        crewMemberId: crew.id,
        rankId: d.rankId,
        vesselId: d.vesselId || null,
        siteId: d.siteId || null,
      },
    });
    // Promote a candidate/ex-hand to active crew (employee no.) on first placement.
    const data: { status: "EMPLOYEE"; currentRankId: string; employeeId?: string } = { status: "EMPLOYEE", currentRankId: d.rankId };
    if (!crew.employeeId) data.employeeId = await generateEmployeeId(tx);
    await tx.crewMember.update({ where: { id: crew.id }, data });
    await tx.crewAction.create({ data: { actionType: "CREW_ONBOARDED", actorId: g.userId, crewMemberId: crew.id, metadata: { direct: true } } });
    // Management ranks (grantsLogin) become a SITE_STAFF login on placement.
    await maybeCreateSiteStaffLogin(tx, { name: crew.name, email: crew.email, employeeId: data.employeeId ?? crew.employeeId }, d.rankId, d.siteId || null);
  });

  revalidatePath(PATH);
  revalidatePath("/crewing/crew");
  return { ok: true };
}
