"use server";

import { getServerSession } from "next-auth";
import { revalidatePath } from "next/cache";
import { authOptions } from "@/lib/auth";
import { isAdminEmail } from "@/lib/admin";
import { refundService } from "@/server/services/refund.service";
import { auditLog } from "@/server/services/audit-log.service";
import { emailService } from "@/lib/email/send";
import { prisma } from "@/lib/prisma";
import { createRefundSchema, refundDecisionSchema } from "./schemas";

async function requireAdmin() {
  const session = await getServerSession(authOptions);
  if (!session?.user || !isAdminEmail(session.user.email)) {
    return null;
  }
  return session.user;
}

export async function createRefundAction(formData: FormData) {
  const admin = await requireAdmin();
  if (!admin) return { error: "Tidak memiliki akses admin" };

  const parsed = createRefundSchema.safeParse({
    bookingId: formData.get("bookingId") as string,
    reason: formData.get("reason") as string,
    reportedBy: formData.get("reportedBy") as string,
    reportNote: formData.get("reportNote") as string,
    amount: (formData.get("amount") as string) || undefined,
  });
  if (!parsed.success) {
    return { error: parsed.error.issues[0].message };
  }

  try {
    const refund = await refundService.requestRefund({
      bookingId: parsed.data.bookingId,
      reason: parsed.data.reason,
      reportedBy: parsed.data.reportedBy,
      reportNote: parsed.data.reportNote,
      amount: parsed.data.amount,
      initiatedByAdminId: admin.id,
    });
    await auditLog.record({
      admin: { id: admin.id, email: admin.email },
      action: "REFUND_CREATE",
      entityType: "Refund",
      entityId: refund.id,
      payload: {
        bookingId: parsed.data.bookingId,
        amount: parsed.data.amount,
        reason: parsed.data.reason,
      },
    });

    void notifyRefundCreated(refund.id);

    revalidatePath("/admin/refunds");
    return { success: true };
  } catch (err) {
    return { error: (err as Error).message };
  }
}

async function notifyRefundCreated(refundId: string) {
  const refund = await prisma.refund.findUnique({
    where: { id: refundId },
    include: {
      booking: {
        include: {
          user: { select: { email: true, name: true } },
          trip: { select: { title: true } },
        },
      },
    },
  });
  if (!refund) return;
  await emailService.send({
    to: refund.booking.user.email,
    idempotencyKey: `refund_created-${refund.id}`,
    template: {
      template: "refund_created",
      data: {
        userName: refund.booking.user.name,
        tripTitle: refund.booking.trip.title,
        amount: refund.amount,
        reason: refund.reason,
      },
    },
  });
}

async function notifyRefundDecision(
  refundId: string,
  decision: "SUCCEEDED" | "FAILED",
  adminNote: string
) {
  const refund = await prisma.refund.findUnique({
    where: { id: refundId },
    include: {
      booking: {
        include: {
          user: { select: { email: true, name: true } },
          trip: { select: { title: true } },
        },
      },
    },
  });
  if (!refund) return;
  await emailService.send({
    to: refund.booking.user.email,
    idempotencyKey: `refund_${decision.toLowerCase()}-${refund.id}`,
    template:
      decision === "SUCCEEDED"
        ? {
            template: "refund_succeeded",
            data: {
              userName: refund.booking.user.name,
              tripTitle: refund.booking.trip.title,
              amount: refund.amount,
              adminNote,
            },
          }
        : {
            template: "refund_failed",
            data: {
              userName: refund.booking.user.name,
              tripTitle: refund.booking.trip.title,
              amount: refund.amount,
              adminNote,
            },
          },
  });
}

export async function decideRefundAction(formData: FormData) {
  const admin = await requireAdmin();
  if (!admin) return { error: "Tidak memiliki akses admin" };

  const parsed = refundDecisionSchema.safeParse({
    refundId: formData.get("refundId") as string,
    decision: formData.get("decision") as string,
    adminNote: (formData.get("adminNote") as string) || undefined,
  });
  if (!parsed.success) {
    return { error: parsed.error.issues[0].message };
  }

  const { refundId, decision, adminNote } = parsed.data;
  const needsNote = decision === "REJECT" || decision === "SUCCEEDED" || decision === "FAILED";
  if (needsNote && (!adminNote || !adminNote.trim())) {
    return { error: "Catatan/alasan admin wajib diisi untuk tindakan ini" };
  }

  try {
    if (decision === "APPROVE") {
      await refundService.approveRefund({
        refundId,
        adminId: admin.id,
        adminNote,
      });
    } else if (decision === "REJECT") {
      await refundService.rejectRefund({
        refundId,
        adminId: admin.id,
        adminNote: adminNote!,
      });
    } else if (decision === "SUCCEEDED") {
      await refundService.markSucceededManual({
        refundId,
        adminId: admin.id,
        adminNote: adminNote!,
      });
    } else {
      await refundService.markFailed({
        refundId,
        adminId: admin.id,
        adminNote: adminNote!,
      });
    }
    await auditLog.record({
      admin: { id: admin.id, email: admin.email },
      action: `REFUND_${decision}`,
      entityType: "Refund",
      entityId: refundId,
      payload: adminNote ? { adminNote } : undefined,
    });

    // Notif email user kalau decision final (SUCCEEDED/FAILED) — APPROVE/REJECT
    // intermediate, refund_created sudah dikirim sebelumnya.
    if (decision === "SUCCEEDED" || decision === "FAILED") {
      void notifyRefundDecision(refundId, decision, adminNote ?? "");
    }

    revalidatePath("/admin/refunds");
    return { success: true };
  } catch (err) {
    return { error: (err as Error).message };
  }
}
