"use server";

import {auth} from "@/auth";
import {prisma} from "@/lib/db/prisma";
import {getTenantDb} from "@/lib/db/tenant";
import {revalidatePath} from "next/cache";
import {z} from "zod";

export type BookingActionResult = {success: boolean; error?: string; id?: string};

// ─────────────────────────────────────────────────────────
// Create Booking (manual from dashboard)
// ─────────────────────────────────────────────────────────
const createBookingSchema = z.object({
  tenantSlug: z.string().min(1),
  customerProfileId: z.string().min(1, "Customer is required"),
  vehicleId: z.string().min(1, "Vehicle is required"),
  pickupBranchId: z.string().min(1, "Pickup branch is required"),
  dropoffBranchId: z.string().min(1, "Dropoff branch is required"),
  pickupAt: z.string().min(1, "Pickup date is required"),
  dropoffAt: z.string().min(1, "Dropoff date is required"),
  notes: z.string().optional(),
  internalNotes: z.string().optional()
});

export async function createBooking(formData: FormData): Promise<BookingActionResult> {
  const session = await auth();
  if (!session?.user?.id) return {success: false, error: "Unauthorized"};

  const raw = Object.fromEntries(formData.entries());
  const parsed = createBookingSchema.safeParse(raw);
  if (!parsed.success) {
    return {success: false, error: parsed.error.issues[0]?.message ?? "Validation error"};
  }

  const d = parsed.data;
  const tenant = await prisma.tenant.findUnique({where: {slug: d.tenantSlug}});
  if (!tenant) return {success: false, error: "Tenant not found"};

  try {
    const db = getTenantDb(tenant.id);

    const profile = await db.customerProfile.findFirst({where: {id: d.customerProfileId}});
    if (!profile) return {success: false, error: "Customer profile not found"};

    const vehicle = await db.vehicle.findFirst({where: {id: d.vehicleId}});
    if (!vehicle) return {success: false, error: "Vehicle not found"};

    const pickupAt = new Date(d.pickupAt);
    const dropoffAt = new Date(d.dropoffAt);
    const rentalMs = dropoffAt.getTime() - pickupAt.getTime();
    const rentalDays = Math.max(1, Math.ceil(rentalMs / (1000 * 60 * 60 * 24)));
    const dailyRate = Number(vehicle.dailyRate);
    const subtotal = rentalDays * dailyRate;
    const taxRate = Number(tenant.taxRate ?? 0) / 100;
    const taxAmount = subtotal * taxRate;
    const depositAmount = Number(vehicle.depositAmount);
    const totalAmount = subtotal + taxAmount;

    const prefix = tenant.bookingPrefix ?? "BKG";
    const random = Math.random().toString(36).substring(2, 7).toUpperCase();
    const bookingNumber = `${prefix}-${new Date().getFullYear()}-${random}`;

    const booking = await db.booking.create({
      data: {
        tenantId: tenant.id,
        bookingNumber,
        source: "TENANT_DASHBOARD",
        status: "PENDING_APPROVAL",
        customerUserId: profile.userId,
        customerProfileId: d.customerProfileId,
        vehicleId: d.vehicleId,
        pickupBranchId: d.pickupBranchId,
        dropoffBranchId: d.dropoffBranchId,
        pickupAt,
        dropoffAt,
        rentalDays,
        dailyRate,
        subtotal,
        taxAmount,
        depositAmount,
        totalAmount,
        paidAmount: 0,
        remainingAmount: totalAmount,
        currency: tenant.currency,
        notes: d.notes ?? null,
        internalNotes: d.internalNotes ?? null,
        createdById: session.user.id
      }
    });

    revalidatePath(`/company/${d.tenantSlug}/bookings`);
    return {success: true, id: booking.id};
  } catch (err: unknown) {
    const message = err instanceof Error ? err.message : "Unknown error";
    return {success: false, error: "Failed to create booking: " + message};
  }
}

// ─────────────────────────────────────────────────────────
// Confirm Booking + auto-create invoice
// ─────────────────────────────────────────────────────────
export async function confirmBooking(bookingId: string, tenantSlug: string): Promise<BookingActionResult> {
  const session = await auth();
  if (!session?.user?.id) return {success: false, error: "Unauthorized"};

  const tenant = await prisma.tenant.findUnique({where: {slug: tenantSlug}});
  if (!tenant) return {success: false, error: "Tenant not found"};

  try {
    const db = getTenantDb(tenant.id);
    const booking = await db.booking.findFirst({where: {id: bookingId}});
    if (!booking) return {success: false, error: "Booking not found"};

    await db.booking.updateMany({
      where: {id: bookingId},
      data: {status: "CONFIRMED", confirmedAt: new Date()}
    });

    // Auto-create invoice if not exists
    const existing = await db.invoice.findFirst({where: {bookingId}});
    if (!existing) {
      const prefix = tenant.invoicePrefix ?? "INV";
      const random = Math.random().toString(36).substring(2, 6).toUpperCase();
      const invoiceNumber = `${prefix}-${new Date().getFullYear()}-${random}`;

      await db.invoice.create({
        data: {
          tenantId: tenant.id,
          bookingId,
          invoiceNumber,
          status: "ISSUED",
          issueDate: new Date(),
          dueDate: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000),
          subtotal: booking.subtotal,
          discountAmount: booking.discountAmount,
          taxAmount: booking.taxAmount,
          totalAmount: booking.totalAmount,
          paidAmount: booking.paidAmount,
          currency: booking.currency
        }
      });
    }

    revalidatePath(`/company/${tenantSlug}/bookings`);
    revalidatePath(`/company/${tenantSlug}/bookings/${bookingId}`);
    return {success: true};
  } catch (err: unknown) {
    const message = err instanceof Error ? err.message : "Unknown error";
    return {success: false, error: "Failed to confirm booking: " + message};
  }
}

// ─────────────────────────────────────────────────────────
// Cancel Booking
// ─────────────────────────────────────────────────────────
export async function cancelBooking(
  bookingId: string,
  tenantSlug: string,
  reason?: string
): Promise<BookingActionResult> {
  const session = await auth();
  if (!session?.user?.id) return {success: false, error: "Unauthorized"};

  const tenant = await prisma.tenant.findUnique({where: {slug: tenantSlug}});
  if (!tenant) return {success: false, error: "Tenant not found"};

  try {
    const db = getTenantDb(tenant.id);
    const booking = await db.booking.findFirst({where: {id: bookingId}});
    if (!booking) return {success: false, error: "Booking not found"};

    await db.booking.updateMany({
      where: {id: bookingId},
      data: {
        status: "CANCELLED",
        cancelledAt: new Date(),
        cancelReason: reason ?? null
      }
    });

    // Release vehicle back to AVAILABLE if it was RESERVED
    if (booking.status === "CONFIRMED" || booking.status === "PENDING_APPROVAL") {
      await db.vehicle.updateMany({
        where: {id: booking.vehicleId},
        data: {status: "AVAILABLE"}
      });
    }

    revalidatePath(`/company/${tenantSlug}/bookings`);
    revalidatePath(`/company/${tenantSlug}/bookings/${bookingId}`);
    return {success: true};
  } catch (err: unknown) {
    const message = err instanceof Error ? err.message : "Unknown error";
    return {success: false, error: "Failed to cancel booking: " + message};
  }
}

// ─────────────────────────────────────────────────────────
// Pickup Vehicle (start rental)
// ─────────────────────────────────────────────────────────
export async function pickupVehicle(bookingId: string, tenantSlug: string): Promise<BookingActionResult> {
  const session = await auth();
  if (!session?.user?.id) return {success: false, error: "Unauthorized"};

  const tenant = await prisma.tenant.findUnique({where: {slug: tenantSlug}});
  if (!tenant) return {success: false, error: "Tenant not found"};

  try {
    const db = getTenantDb(tenant.id);
    const booking = await db.booking.findFirst({where: {id: bookingId}});
    if (!booking) return {success: false, error: "Booking not found"};
    if (booking.status !== "CONFIRMED") return {success: false, error: "Booking must be CONFIRMED to pickup"};

    await db.booking.updateMany({
      where: {id: bookingId},
      data: {status: "ACTIVE", actualPickupAt: new Date()}
    });

    // Mark vehicle as RENTED
    await db.vehicle.updateMany({
      where: {id: booking.vehicleId},
      data: {status: "RENTED"}
    });

    revalidatePath(`/company/${tenantSlug}/bookings`);
    revalidatePath(`/company/${tenantSlug}/bookings/${bookingId}`);
    revalidatePath(`/company/${tenantSlug}/fleet`);
    revalidatePath(`/company/${tenantSlug}/fleet/${booking.vehicleId}`);
    return {success: true};
  } catch (err: unknown) {
    const message = err instanceof Error ? err.message : "Unknown error";
    return {success: false, error: "Failed to process pickup: " + message};
  }
}

// ─────────────────────────────────────────────────────────
// Return Vehicle (end rental + calculate fees)
// ─────────────────────────────────────────────────────────
export async function returnVehicle(
  bookingId: string,
  tenantSlug: string,
  additionalFees?: number
): Promise<BookingActionResult> {
  const session = await auth();
  if (!session?.user?.id) return {success: false, error: "Unauthorized"};

  const tenant = await prisma.tenant.findUnique({where: {slug: tenantSlug}, include: {settings: true}});
  if (!tenant) return {success: false, error: "Tenant not found"};

  try {
    const db = getTenantDb(tenant.id);
    const booking = await db.booking.findFirst({where: {id: bookingId}});
    if (!booking) return {success: false, error: "Booking not found"};
    if (booking.status !== "ACTIVE") return {success: false, error: "Booking must be ACTIVE to return"};

    const now = new Date();
    const plannedDropoff = new Date(booking.dropoffAt);

    // Calculate late fee if applicable
    let lateFee = 0;
    if (now > plannedDropoff && tenant.settings?.lateReturnFeePerHour) {
      const hoursLate = Math.ceil((now.getTime() - plannedDropoff.getTime()) / (1000 * 60 * 60));
      lateFee = hoursLate * Number(tenant.settings.lateReturnFeePerHour);
    }

    const extraFees = (additionalFees ?? 0) + lateFee;
    const newTotal = Number(booking.totalAmount) + extraFees;

    await db.booking.updateMany({
      where: {id: bookingId},
      data: {
        status: "COMPLETED",
        actualDropoffAt: now,
        completedAt: now,
        totalAmount: newTotal,
        remainingAmount: Math.max(0, newTotal - Number(booking.paidAmount))
      }
    });

    // Mark vehicle as AVAILABLE
    await db.vehicle.updateMany({
      where: {id: booking.vehicleId},
      data: {status: "AVAILABLE"}
    });

    // Update invoice if exists
    const invoice = await db.invoice.findFirst({where: {bookingId}});
    if (invoice) {
      await db.invoice.updateMany({
        where: {id: invoice.id},
        data: {
          totalAmount: newTotal,
          status: Number(booking.paidAmount) >= newTotal ? "PAID" : "ISSUED"
        }
      });
    }

    revalidatePath(`/company/${tenantSlug}/bookings`);
    revalidatePath(`/company/${tenantSlug}/bookings/${bookingId}`);
    revalidatePath(`/company/${tenantSlug}/fleet`);
    revalidatePath(`/company/${tenantSlug}/fleet/${booking.vehicleId}`);
    return {success: true};
  } catch (err: unknown) {
    const message = err instanceof Error ? err.message : "Unknown error";
    return {success: false, error: "Failed to process return: " + message};
  }
}

// ─────────────────────────────────────────────────────────
// Extend Booking
// ─────────────────────────────────────────────────────────
const extendBookingSchema = z.object({
  bookingId: z.string().min(1),
  tenantSlug: z.string().min(1),
  newDropoffAt: z.string().min(1, "New return date is required")
});

export async function extendBooking(formData: FormData): Promise<BookingActionResult> {
  const session = await auth();
  if (!session?.user?.id) return {success: false, error: "Unauthorized"};

  const raw = Object.fromEntries(formData.entries());
  const parsed = extendBookingSchema.safeParse(raw);
  if (!parsed.success) {
    return {success: false, error: parsed.error.issues[0]?.message ?? "Validation error"};
  }

  const d = parsed.data;
  const tenant = await prisma.tenant.findUnique({where: {slug: d.tenantSlug}});
  if (!tenant) return {success: false, error: "Tenant not found"};

  try {
    const db = getTenantDb(tenant.id);
    const booking = await db.booking.findFirst({where: {id: d.bookingId}});
    if (!booking) return {success: false, error: "Booking not found"};
    if (!["CONFIRMED", "ACTIVE"].includes(booking.status)) {
      return {success: false, error: "Only CONFIRMED or ACTIVE bookings can be extended"};
    }

    const newDropoffAt = new Date(d.newDropoffAt);
    const pickupAt = new Date(booking.pickupAt);
    if (newDropoffAt <= new Date(booking.dropoffAt)) {
      return {success: false, error: "New return date must be after current return date"};
    }

    const rentalMs = newDropoffAt.getTime() - pickupAt.getTime();
    const rentalDays = Math.max(1, Math.ceil(rentalMs / (1000 * 60 * 60 * 24)));
    const dailyRate = Number(booking.dailyRate);
    const subtotal = rentalDays * dailyRate;
    const taxRate = Number(tenant.taxRate ?? 0) / 100;
    const taxAmount = subtotal * taxRate;
    const totalAmount = subtotal + taxAmount + Number(booking.depositAmount);

    await db.booking.updateMany({
      where: {id: d.bookingId},
      data: {
        dropoffAt: newDropoffAt,
        rentalDays,
        subtotal,
        taxAmount,
        totalAmount,
        remainingAmount: Math.max(0, totalAmount - Number(booking.paidAmount))
      }
    });

    revalidatePath(`/company/${d.tenantSlug}/bookings`);
    revalidatePath(`/company/${d.tenantSlug}/bookings/${d.bookingId}`);
    return {success: true};
  } catch (err: unknown) {
    const message = err instanceof Error ? err.message : "Unknown error";
    return {success: false, error: "Failed to extend booking: " + message};
  }
}
