import type { ActionFunctionArgs } from "react-router";
import { authenticate } from "../shopify.server";
import db from "../db.server";
import { generateInvoice } from "../services/invoice/generateInvoice.server";
import { sendInvoiceEmail } from "../services/invoice/email.server";

/**
 * Flow action endpoint: "Send invoice email to customer".
 *
 * Generates the invoice if missing, then sends it via the shop's configured
 * SMTP. Marks the invoice as `sent`, locking it from in-place regeneration.
 *
 * Expected payload properties:
 *   - order_id (required)
 *   - recipient_email_override (optional)
 */
export const action = async ({ request }: ActionFunctionArgs) => {
  const { session, admin, payload } = await authenticate.flow(request);

  const orderId = extractOrderId(payload);
  if (!orderId) {
    return Response.json(
      { ok: false, error: "Missing 'order_id' in Flow payload properties." },
      { status: 400 },
    );
  }
  const recipientOverride = extractProp(payload, "recipient_email_override");

  try {
    // Make sure an invoice exists.
    const orderGid = orderId.startsWith("gid://")
      ? orderId
      : `gid://shopify/Order/${orderId}`;
    let invoice = await db.invoice.findFirst({
      where: {
        shopDomain: session.shop,
        orderId: orderGid,
        kind: "invoice",
        cancelledAt: null,
      },
      orderBy: [{ version: "desc" }, { createdAt: "desc" }],
    });
    if (!invoice) {
      const generated = await generateInvoice({
        shopDomain: session.shop,
        admin,
        orderId,
      });
      invoice = await db.invoice.findUnique({ where: { id: generated.invoiceId } });
    }
    if (!invoice) throw new Error("Failed to materialise an invoice for this order.");

    const result = await sendInvoiceEmail({
      shopDomain: session.shop,
      invoiceId: invoice.id,
      toAddress: recipientOverride || undefined,
    });

    if (!result.ok) {
      return Response.json(
        { ok: false, error: result.errorMessage ?? "Email send failed." },
        { status: 422 },
      );
    }
    return { ok: true, invoiceNumber: invoice.invoiceNumber, toAddress: result.toAddress };
  } catch (err) {
    const message = err instanceof Error ? err.message : String(err);
    console.error("flow.send-invoice-email failed:", err);
    return Response.json({ ok: false, error: message }, { status: 422 });
  }
};

function extractOrderId(payload: unknown): string | null {
  if (!payload || typeof payload !== "object") return null;
  const props = (payload as { properties?: Record<string, unknown> }).properties;
  if (!props || typeof props !== "object") return null;
  const raw = props["order_id"];
  if (typeof raw === "string" && raw.length > 0) return raw;
  if (typeof raw === "number") return String(raw);
  return null;
}

function extractProp(payload: unknown, key: string): string | null {
  if (!payload || typeof payload !== "object") return null;
  const props = (payload as { properties?: Record<string, unknown> }).properties;
  if (!props || typeof props !== "object") return null;
  const raw = props[key];
  if (typeof raw === "string" && raw.length > 0) return raw;
  return null;
}
