/**
 * Quotation Portal Service
 *
 * Public-facing service for customer quotation portal.
 * All functions use portal tokens for security (no auth required).
 */

import { prisma } from "@/lib/db";
import { getStripeClient } from "@/lib/stripe/client";

/**
 * Get a quotation by its portal token.
 * Returns sanitized data excluding internal fields.
 */
export async function getQuotationByPortalToken(token: string) {
  const quotation = await prisma.quotations.findUnique({
    where: { portalToken: token },
    include: {
      items: { orderBy: { sortOrder: "asc" } },
      customer: { select: { id: true, name: true, email: true, phone: true } },
      payments: {
        orderBy: { paidAt: "desc" },
        select: {
          id: true,
          amount: true,
          currency: true,
          method: true,
          reference: true,
          paidAt: true,
        },
      },
    },
  });

  if (!quotation) return null;

  // Return sanitized data (exclude userId, internal metadata)
  return {
    id: quotation.id,
    quotationNumber: quotation.quotationNumber,
    title: quotation.title,
    notes: quotation.notes,
    status: quotation.status,
    currency: quotation.currency,
    subtotal: quotation.subtotal,
    taxRate: quotation.taxRate,
    taxAmount: quotation.taxAmount,
    discountRate: quotation.discountRate,
    discountAmount: quotation.discountAmount,
    total: quotation.total,
    validUntil: quotation.validUntil,
    sentAt: quotation.sentAt,
    viewedAt: quotation.viewedAt,
    respondedAt: quotation.respondedAt,
    paymentStatus: quotation.paymentStatus,
    amountPaid: quotation.amountPaid,
    dueDate: quotation.dueDate,
    penaltyAmount: quotation.penaltyAmount,
    penaltyAppliedAt: quotation.penaltyAppliedAt,
    createdAt: quotation.createdAt,
    customer: quotation.customer,
    items: quotation.items.map((item) => ({
      id: item.id,
      description: item.description,
      quantity: item.quantity,
      unitPrice: item.unitPrice,
      total: item.total,
      sortOrder: item.sortOrder,
    })),
    payments: quotation.payments,
  };
}

/**
 * Mark a quotation as viewed (idempotent).
 * Only transitions from SENT to VIEWED.
 */
export async function markQuotationViewed(token: string) {
  const quotation = await prisma.quotations.findUnique({
    where: { portalToken: token },
    select: { id: true, status: true, viewedAt: true },
  });

  if (!quotation) return null;

  // Only mark as VIEWED if currently SENT
  if (quotation.status === "SENT") {
    return prisma.quotations.update({
      where: { id: quotation.id },
      data: {
        status: "VIEWED",
        viewedAt: new Date(),
      },
    });
  }

  return quotation;
}

/**
 * Accept a quotation via portal token.
 * Only allowed if status is SENT or VIEWED.
 */
export async function acceptQuotation(token: string) {
  const quotation = await prisma.quotations.findUnique({
    where: { portalToken: token },
    select: { id: true, status: true },
  });

  if (!quotation) return { success: false, error: "Quotation not found" };

  if (quotation.status !== "SENT" && quotation.status !== "VIEWED") {
    return {
      success: false,
      error: `Cannot accept quotation with status ${quotation.status}`,
    };
  }

  await prisma.quotations.update({
    where: { id: quotation.id },
    data: {
      status: "ACCEPTED",
      respondedAt: new Date(),
    },
  });

  return { success: true };
}

/**
 * Decline a quotation via portal token.
 * Only allowed if status is SENT or VIEWED.
 */
export async function declineQuotation(token: string, reason?: string) {
  const quotation = await prisma.quotations.findUnique({
    where: { portalToken: token },
    select: { id: true, status: true, metadata: true },
  });

  if (!quotation) return { success: false, error: "Quotation not found" };

  if (quotation.status !== "SENT" && quotation.status !== "VIEWED") {
    return {
      success: false,
      error: `Cannot decline quotation with status ${quotation.status}`,
    };
  }

  const existingMeta =
    typeof quotation.metadata === "object" && quotation.metadata !== null
      ? (quotation.metadata as Record<string, unknown>)
      : {};

  await prisma.quotations.update({
    where: { id: quotation.id },
    data: {
      status: "DECLINED",
      respondedAt: new Date(),
      metadata: { ...existingMeta, declineReason: reason || undefined },
    },
  });

  return { success: true };
}

/**
 * Create a Stripe checkout session for portal payment.
 * Charges remaining balance (total + penaltyAmount - amountPaid).
 */
export async function createPortalCheckoutSession(
  token: string,
  successUrl: string,
  cancelUrl: string,
) {
  const quotation = await prisma.quotations.findUnique({
    where: { portalToken: token },
    select: {
      id: true,
      quotationNumber: true,
      title: true,
      total: true,
      penaltyAmount: true,
      amountPaid: true,
      currency: true,
      paymentStatus: true,
      customer: { select: { name: true, email: true } },
    },
  });

  if (!quotation) {
    return { success: false, error: "Quotation not found" };
  }

  if (quotation.paymentStatus === "PAID") {
    return { success: false, error: "Quotation is already fully paid" };
  }

  const remaining =
    quotation.total + quotation.penaltyAmount - quotation.amountPaid;
  if (remaining <= 0) {
    return { success: false, error: "No balance remaining" };
  }

  // Stripe expects amounts in smallest currency unit (cents/fils)
  const amountInSmallestUnit = Math.round(remaining * 100);

  const stripe = getStripeClient();
  const session = await stripe.checkout.sessions.create({
    mode: "payment",
    payment_method_types: ["card"],
    line_items: [
      {
        price_data: {
          currency: quotation.currency.toLowerCase(),
          product_data: {
            name: `${quotation.quotationNumber} - ${quotation.title}`,
          },
          unit_amount: amountInSmallestUnit,
        },
        quantity: 1,
      },
    ],
    metadata: {
      quotationId: quotation.id,
      portalToken: token,
      type: "quotation_payment",
    },
    customer_email: quotation.customer?.email || undefined,
    success_url: successUrl,
    cancel_url: cancelUrl,
  });

  // Store checkout session reference
  await prisma.quotations.update({
    where: { id: quotation.id },
    data: {
      stripeCheckoutUrl: session.url,
      stripeSessionId: session.id,
    },
  });

  return { success: true, checkoutUrl: session.url };
}
