"use server";

import { revalidatePath } from "next/cache";
import { api } from "../../../convex/_generated/api";
import { m, q } from "@/lib/convex-server";
import { run, ActionError, type ActionResult } from "@/lib/action";
import type { RESERVATION_STATUSES } from "@/lib/domain";

export interface CreateReservationInput {
  customerId: string;
  apartmentId: string;
  checkIn: string;
  checkOut: string;
  adults: number;
  children?: number;
  source: string;
  status?: "INQUIRY" | "PENDING" | "CONFIRMED";
  nightlyPrice?: number;
  discount?: number;
  deposit?: number;
  amountPaid?: number;
  paymentMethod?: string | null;
  assignedToId?: string | null;
  internalNotes?: string | null;
  customerRequests?: string | null;
  externalRef?: string | null;
  riskOverride?: boolean;
  allowSecondStay?: boolean;
}

function revalidateAll(id?: string) {
  for (const p of ["/dashboard", "/reservations", "/calendar", "/apartments", "/customers", "/payments"]) revalidatePath(p);
  if (id) revalidatePath(`/reservations/${id}`);
}

const num = (x: unknown) => (x === undefined || x === null || x === "" ? undefined : Number(x));
const opt = <T,>(x: T | undefined | null | "") => (x === "" ? null : x);

export async function createReservation(input: CreateReservationInput): Promise<ActionResult<{ id: string; code: string }>> {
  return run(async () => {
    const res = await m(api.reservations.create, { customerId: input.customerId, apartmentId: input.apartmentId, checkIn: input.checkIn, checkOut: input.checkOut, adults: Number(input.adults), children: num(input.children) ?? 0, source: input.source, status: input.status ?? "CONFIRMED", nightlyPrice: num(input.nightlyPrice), discount: num(input.discount) ?? 0, deposit: num(input.deposit) ?? 0, amountPaid: num(input.amountPaid) ?? 0, paymentMethod: opt(input.paymentMethod) ?? null, assignedToId: opt(input.assignedToId) ?? null, internalNotes: opt(input.internalNotes) ?? null, customerRequests: opt(input.customerRequests) ?? null, externalRef: opt(input.externalRef) ?? null, riskOverride: input.riskOverride, allowSecondStay: input.allowSecondStay });
    const out = res as { id: string; code: string } | { blocked: true; message: string };
    if ("blocked" in out) throw new ActionError(out.message, "PERMISSION");
    revalidateAll(out.id);
    return { id: out.id, code: out.code };
  });
}

export async function editReservation(input: { id: string; adults?: number; children?: number; source?: string; assignedToId?: string | null; internalNotes?: string | null; customerRequests?: string | null; externalRef?: string | null; deposit?: number }): Promise<ActionResult<undefined>> {
  return run(async () => {
    await m(api.reservations.edit, { id: input.id, adults: num(input.adults), children: num(input.children), source: input.source, assignedToId: input.assignedToId === "" ? null : input.assignedToId, internalNotes: input.internalNotes, customerRequests: input.customerRequests, externalRef: input.externalRef, deposit: num(input.deposit) });
    revalidateAll(input.id);
    return undefined;
  });
}

export async function changeReservationStatus(id: string, status: (typeof RESERVATION_STATUSES)[number], reason?: string): Promise<ActionResult<undefined>> {
  return run(async () => {
    await m(api.reservations.changeStatus, { id, status, reason });
    revalidateAll(id);
    return undefined;
  });
}

export async function changeApartment(input: { id: string; apartmentId: string; reason?: string; recalculate: boolean }): Promise<ActionResult<{ priceDifference: number }>> {
  return run(async () => {
    const r = await m(api.reservations.changeApartment, input);
    revalidateAll(input.id);
    return r;
  });
}

export async function changeDates(input: { id: string; checkIn: string; checkOut: string; reason?: string; recalculate: boolean }): Promise<ActionResult<{ priceDifference: number }>> {
  return run(async () => {
    const r = await m(api.reservations.changeDates, input);
    revalidateAll(input.id);
    return r;
  });
}

export async function changePrice(input: { id: string; nightlyPrice?: number; discount?: number; reason?: string }): Promise<ActionResult<undefined>> {
  return run(async () => {
    await m(api.reservations.changePrice, { id: input.id, nightlyPrice: num(input.nightlyPrice), discount: num(input.discount), reason: input.reason });
    revalidateAll(input.id);
    return undefined;
  });
}

export interface CheckInChecklist {
  identityVerified: boolean;
  documentsUploaded: boolean;
  contractGenerated: boolean;
  contractSigned: boolean;
  depositCollected: boolean;
  paymentOk: boolean;
  apartmentReady: boolean;
  cleaningDone: boolean;
}

export async function getCheckInReadiness(id: string) {
  const r = await q(api.reservations.readiness, { id: id as never });
  return r ?? { documentsUploaded: false, contractGenerated: false, contractSigned: false, depositCollected: false, paymentOk: false, apartmentReady: false, apartmentStatus: "AVAILABLE", remaining: 0 };
}

export async function checkIn(input: { id: string; checklist: CheckInChecklist; notes?: string; force?: boolean }): Promise<ActionResult<undefined>> {
  return run(async () => {
    await m(api.reservations.checkIn, input);
    revalidateAll(input.id);
    return undefined;
  });
}

export interface CheckOutChecklist {
  guestLeft: boolean;
  keysReturned: boolean;
  inspected: boolean;
  damageReported: boolean;
  balanceCollected: boolean;
  cleaningRequested: boolean;
  depositRefunded: boolean;
}

export async function checkOut(input: { id: string; checklist: CheckOutChecklist; notes?: string; damageNotes?: string; refundDeposit?: number }): Promise<ActionResult<undefined>> {
  return run(async () => {
    await m(api.reservations.checkOut, { ...input, refundDeposit: num(input.refundDeposit) });
    revalidateAll(input.id);
    return undefined;
  });
}

/** Prepares the post-stay Google review request (text + guest phone) and records that it was sent. */
export async function requestReview(reservationId: string): Promise<ActionResult<{ text: string; phone: string }>> {
  return run(async () => {
    const r = await m(api.leads.reviewRequested, { reservationId });
    revalidatePath(`/reservations/${reservationId}`);
    return r as { text: string; phone: string };
  });
}

export async function deleteReservation(id: string, reason: string): Promise<ActionResult<undefined>> {
  return run(async () => {
    await m(api.reservations.remove, { id, reason });
    revalidateAll();
    return undefined;
  });
}
