"use server";

import { revalidatePath } from "next/cache";
import { redirect } from "next/navigation";
import { PaymentMealType, PersonStatus, ReplacementItem } from "@prisma/client";
import { z } from "zod";
import { loginUser, logoutUser } from "@/lib/auth";
import { createReplacementLog } from "@/lib/delivery";
import { prisma } from "@/lib/prisma";
import { startOfDay } from "@/lib/utils";

const personSchema = z.object({
  name: z.string().min(2),
  takesLunch: z.coerce.boolean(),
  takesMandazi: z.coerce.boolean(),
  defaultMandaziQty: z.coerce.number().int().min(1).max(20)
});

function describeMode(mode: string) {
  if (mode === "paused") {
    return "paused";
  }

  if (mode === "on_leave") {
    return "on leave";
  }

  return "active";
}

function formatMealsState(takesLunch: boolean, takesMandazi: boolean) {
  return `lunch ${takesLunch ? "on" : "off"}, mandazi ${takesMandazi ? "on" : "off"}`;
}

async function upsertRecentActivityLog({
  type,
  subject,
  description
}: {
  type: string;
  subject: string;
  description: string;
}) {
  const threshold = new Date(Date.now() - 1000 * 60 * 10);
  const existing = await prisma.activityLog.findFirst({
    where: {
      type,
      description: {
        startsWith: `${subject} —`
      },
      createdAt: {
        gte: threshold
      }
    },
    orderBy: { createdAt: "desc" }
  });

  if (existing) {
    return prisma.activityLog.update({
      where: { id: existing.id },
      data: {
        description,
        createdAt: new Date()
      }
    });
  }

  return prisma.activityLog.create({
    data: {
      type,
      description
    }
  });
}

export async function loginAction(formData: FormData) {
  const email = String(formData.get("email") ?? "");
  const password = String(formData.get("password") ?? "");

  const user = await loginUser(email, password);

  if (!user) {
    redirect("/login?error=1");
  }

  redirect("/today");
}

export async function logoutAction() {
  await logoutUser();
  redirect("/login");
}

export async function addPersonAction(formData: FormData) {
  const values = {
    name: String(formData.get("name") ?? ""),
    takesLunch: formData.get("takesLunch") === "on",
    takesMandazi: formData.get("takesMandazi") === "on",
    defaultMandaziQty: Number(formData.get("defaultMandaziQty") ?? 1)
  };

  const parsed = personSchema.safeParse(values);

  if (!parsed.success) {
    return;
  }

  const person = await prisma.person.create({
    data: parsed.data
  });

  await prisma.activityLog.create({
    data: {
      type: "person_added",
      description: `Added ${person.name}`
    }
  });

  revalidatePath("/today");
  revalidatePath("/people");
}

export async function updatePersonAction(formData: FormData) {
  const personId = Number(formData.get("personId"));
  const status = String(formData.get("status")) as PersonStatus;
  const defaultMandaziQty = Number(formData.get("defaultMandaziQty") ?? 1);
  const leaveStartValue = String(formData.get("leaveStart") ?? "");
  const leaveEndValue = String(formData.get("leaveEnd") ?? "");

  await prisma.person.update({
    where: { id: personId },
    data: {
      status,
      defaultMandaziQty,
      leaveStart: leaveStartValue ? new Date(leaveStartValue) : null,
      leaveEnd: leaveEndValue ? new Date(leaveEndValue) : null
    }
  });

  await prisma.activityLog.create({
    data: {
      type: "person_updated",
      description: `Updated person #${personId}`
    }
  });

  revalidatePath("/today");
  revalidatePath("/people");
  revalidatePath(`/people/${personId}`);
}

export async function setPersonModeAction(formData: FormData) {
  const personId = Number(formData.get("personId"));
  const mode = String(formData.get("mode") ?? "active");
  const today = startOfDay(new Date());
  const person = await prisma.person.findUnique({
    where: { id: personId }
  });

  if (!person) {
    return;
  }

  const previousMode =
    person.status === PersonStatus.paused ? "paused" : person.leaveStart || person.leaveEnd ? "on_leave" : "active";

  if (previousMode === mode) {
    return;
  }

  const data =
    mode === "paused"
      ? {
          status: PersonStatus.paused,
          leaveStart: null,
          leaveEnd: null
        }
      : mode === "on_leave"
        ? {
            status: PersonStatus.active,
            leaveStart: person.leaveStart ?? today,
            leaveEnd: person.leaveEnd ?? today
          }
        : {
            status: PersonStatus.active,
            leaveStart: null,
            leaveEnd: null
          };

  await prisma.person.update({
    where: { id: personId },
    data
  });

  await upsertRecentActivityLog({
    type: "status_changed",
    subject: person.name,
    description: `${person.name} — Status changed: ${describeMode(previousMode)} → ${describeMode(mode)}`
  });

  revalidatePath("/today");
  revalidatePath("/people");
  revalidatePath(`/people/${personId}`);
}

export async function adjustPersonMandaziQtyAction(formData: FormData) {
  const personId = Number(formData.get("personId"));
  const currentQuantity = Number(formData.get("quantity") ?? 1);
  const delta = Number(formData.get("delta") ?? 0);
  const nextQuantity = Math.max(1, currentQuantity + delta);

  if (nextQuantity === currentQuantity) {
    return;
  }

  const person = await prisma.person.update({
    where: { id: personId },
    data: {
      defaultMandaziQty: nextQuantity
    }
  });

  await upsertRecentActivityLog({
    type: "mandazi_quantity_updated",
    subject: person.name,
    description: `${person.name} — Mandazi quantity updated to ${nextQuantity}`
  });

  revalidatePath("/today");
  revalidatePath("/people");
  revalidatePath(`/people/${personId}`);
}

export async function setPersonLeaveDateAction(formData: FormData) {
  const personId = Number(formData.get("personId"));
  const field = String(formData.get("field") ?? "");
  const value = String(formData.get("value") ?? "");

  if (field !== "leaveStart" && field !== "leaveEnd") {
    return;
  }

  const existingPerson = await prisma.person.findUnique({
    where: { id: personId }
  });

  if (!existingPerson) {
    return;
  }

  const person = await prisma.person.update({
    where: { id: personId },
    data: {
      [field]: value ? new Date(value) : null
    }
  });

  const nextLeaveStart = field === "leaveStart" ? (value ? new Date(value) : null) : existingPerson.leaveStart;
  const nextLeaveEnd = field === "leaveEnd" ? (value ? new Date(value) : null) : existingPerson.leaveEnd;
  const leaveSummary = `${nextLeaveStart ? nextLeaveStart.toISOString().split("T")[0] : "unset"} → ${
    nextLeaveEnd ? nextLeaveEnd.toISOString().split("T")[0] : "unset"
  }`;

  await upsertRecentActivityLog({
    type: "leave_updated",
    subject: person.name,
    description: `${person.name} — Leave dates updated: ${leaveSummary}`
  });

  revalidatePath("/today");
  revalidatePath("/people");
  revalidatePath(`/people/${personId}`);
}

export async function togglePersonMealAction(formData: FormData) {
  const personId = Number(formData.get("personId"));
  const meal = String(formData.get("meal") ?? "");
  const enabled = formData.get("enabled") === "true";

  if (meal !== "lunch" && meal !== "mandazi") {
    return;
  }

  const existingPerson = await prisma.person.findUnique({
    where: { id: personId }
  });

  if (!existingPerson) {
    return;
  }

  const currentValue = meal === "lunch" ? existingPerson.takesLunch : existingPerson.takesMandazi;

  if (currentValue === enabled) {
    return;
  }

  const person = await prisma.person.update({
    where: { id: personId },
    data: {
      [meal === "lunch" ? "takesLunch" : "takesMandazi"]: enabled
    }
  });

  await upsertRecentActivityLog({
    type: "meals_updated",
    subject: person.name,
    description: `${person.name} — Meals updated: ${formatMealsState(person.takesLunch, person.takesMandazi)}`
  });

  revalidatePath("/today");
  revalidatePath("/people");
  revalidatePath(`/people/${personId}`);
}

export async function markAbsentAction(formData: FormData) {
  const personId = Number(formData.get("personId"));
  const date = startOfDay(new Date());
  const isAbsent = formData.get("isAbsent") === "true";

  await prisma.dailyOverride.upsert({
    where: {
      personId_date: {
        personId,
        date
      }
    },
    update: {
      isAbsent
    },
    create: {
      personId,
      date,
      isAbsent
    }
  });

  const person = await prisma.person.findUnique({ where: { id: personId } });

  await prisma.activityLog.create({
    data: {
      type: "absence_marked",
      description: `${person?.name ?? "Person"} — Marked ${isAbsent ? "absent" : "present"}`
    }
  });

  revalidatePath("/today");
}

export async function updateMandaziOverrideAction(formData: FormData) {
  const personId = Number(formData.get("personId"));
  const currentQuantity = Number(formData.get("quantity") ?? 1);
  const delta = Number(formData.get("delta") ?? 0);
  const quantity = Math.max(1, currentQuantity + delta);
  const date = startOfDay(new Date());

  await prisma.dailyOverride.upsert({
    where: {
      personId_date: {
        personId,
        date
      }
    },
    update: {
      mandaziQtyOverride: quantity
    },
    create: {
      personId,
      date,
      mandaziQtyOverride: quantity
    }
  });

  const person = await prisma.person.findUnique({
    where: { id: personId }
  });

  await upsertRecentActivityLog({
    type: "mandazi_quantity_updated",
    subject: person?.name ?? `Person ${personId}`,
    description: `${person?.name ?? `Person ${personId}`} — Mandazi quantity updated to ${quantity}`
  });

  revalidatePath("/today");
}

export async function addReplacementAction(formData: FormData) {
  const name = String(formData.get("name") ?? "");
  const item = String(formData.get("item") ?? "mandazi") as ReplacementItem;
  const quantity = Number(formData.get("quantity") ?? 1);

  if (!name || quantity < 1) {
    return;
  }

  await createReplacementLog(item, name, quantity);
  revalidatePath("/today");
}

export async function createPaymentAction(formData: FormData) {
  const personId = Number(formData.get("personId"));
  const mealType = String(formData.get("mealType") ?? "both") as PaymentMealType;
  const coverageDays = Number(formData.get("coverageDays") ?? 2);

  await prisma.payment.create({
    data: {
      personId,
      mealType,
      coverageDays,
      remainingDays: coverageDays
    }
  });

  const person = await prisma.person.findUnique({ where: { id: personId } });

  await prisma.activityLog.create({
    data: {
      type: "payment_recorded",
      description: `${person?.name ?? `Person ${personId}`} — Paid • ${
        mealType === "both" ? "both meals" : mealType
      } • ${coverageDays} days`
    }
  });

  revalidatePath("/payments");
  revalidatePath("/history");
}

export async function convertAwaitingPaymentAction(formData: FormData) {
  const awaitingId = Number(formData.get("awaitingId"));
  const rawPersonId = formData.get("personId");
  const personId = rawPersonId ? Number(rawPersonId) : null;
  const coverageDays = Number(formData.get("coverageDays") ?? 2);
  const awaiting = await prisma.awaitingPayment.findUnique({
    where: { id: awaitingId }
  });

  if (!awaiting) {
    return;
  }

  const mealType =
    awaiting.item === "lunch" ? PaymentMealType.lunch : PaymentMealType.mandazi;

  const person =
    personId
      ? await prisma.person.findUnique({ where: { id: personId } })
      : await prisma.person.findFirst({
          where: {
            name: awaiting.name
          }
        });

  const ensuredPerson =
    person ??
    (await prisma.person.create({
      data: {
        name: awaiting.name,
        takesLunch: awaiting.item === "lunch",
        takesMandazi: awaiting.item === "mandazi",
        defaultMandaziQty: awaiting.item === "mandazi" ? awaiting.quantity : 1
      }
    }));

  await prisma.$transaction([
    prisma.payment.create({
      data: {
        personId: ensuredPerson.id,
        mealType,
        coverageDays,
        remainingDays: coverageDays
      }
    }),
    prisma.awaitingPayment.delete({
      where: { id: awaitingId }
    }),
    prisma.activityLog.create({
      data: {
        type: "payment_recorded",
        description: `${awaiting.name} — Paid • ${mealType} • ${coverageDays} days`
      }
    }),
    ...(person
      ? []
      : [
          prisma.activityLog.create({
            data: {
              type: "person_added",
              description: `Added ${ensuredPerson.name} from awaiting payment`
            }
          })
        ])
  ]);

  revalidatePath("/payments");
  revalidatePath("/people");
  revalidatePath("/history");
}
