import { prisma } from "@/lib/prisma";
import { Prisma } from "@/app/generated/prisma/client";

const refundListInclude = {
  booking: {
    include: {
      trip: { select: { id: true, title: true, date: true, organizerId: true } },
      user: { select: { id: true, name: true, email: true, image: true } },
      payments: {
        orderBy: { createdAt: "desc" },
        select: {
          id: true,
          provider: true,
          method: true,
          amount: true,
          status: true,
          paidAt: true,
        },
      },
    },
  },
  payment: {
    select: {
      id: true,
      provider: true,
      method: true,
      amount: true,
      status: true,
    },
  },
  reviewedBy: { select: { id: true, name: true, email: true } },
} satisfies Prisma.RefundInclude;

export const refundRepo = {
  async findById(id: string) {
    return prisma.refund.findUnique({
      where: { id },
      include: refundListInclude,
    });
  },

  async listByStatus(
    status?: "PENDING" | "APPROVED" | "REJECTED" | "PROCESSING" | "SUCCEEDED" | "FAILED",
    filters?: {
      dateFrom?: Date;
      dateTo?: Date;
      reviewerEmail?: string;
      reason?:
        | "USER_CANCELLATION"
        | "ORGANIZER_CANCELLED"
        | "TRIP_ISSUE"
        | "ADMIN_ADJUSTMENT"
        | "DISPUTE_RESOLVED";
    }
  ) {
    const where: Prisma.RefundWhereInput = {};
    if (status) where.status = status;
    if (filters?.dateFrom || filters?.dateTo) {
      where.createdAt = {
        ...(filters.dateFrom && { gte: filters.dateFrom }),
        ...(filters.dateTo && { lte: filters.dateTo }),
      };
    }
    if (filters?.reviewerEmail) {
      where.reviewedBy = { email: filters.reviewerEmail };
    }
    if (filters?.reason) {
      where.reason = filters.reason;
    }
    return prisma.refund.findMany({
      where,
      orderBy: { createdAt: "desc" },
      include: refundListInclude,
    });
  },

  async countByStatus(
    status: "PENDING" | "APPROVED" | "REJECTED" | "PROCESSING" | "SUCCEEDED" | "FAILED"
  ) {
    return prisma.refund.count({ where: { status } });
  },

  /** Refund terbaru untuk satu status — dipakai dashboard admin. */
  async listRecent(
    status: "PENDING" | "APPROVED" | "REJECTED" | "PROCESSING" | "SUCCEEDED" | "FAILED",
    limit = 3
  ) {
    return prisma.refund.findMany({
      where: { status },
      orderBy: { createdAt: "desc" },
      take: limit,
      select: {
        id: true,
        amount: true,
        reason: true,
        createdAt: true,
        booking: {
          select: {
            user: { select: { id: true, name: true } },
            trip: { select: { id: true, title: true } },
          },
        },
      },
    });
  },

  async listByBooking(bookingId: string) {
    return prisma.refund.findMany({
      where: { bookingId },
      orderBy: { createdAt: "desc" },
    });
  },

  /** Total nominal yang sudah SUCCEEDED untuk satu booking. Dipakai service untuk
   *  validasi `SUM(SUCCEEDED) + new.amount <= payment.amount`. */
  async sumSucceededAmount(bookingId: string, tx?: Prisma.TransactionClient): Promise<number> {
    const client = tx ?? prisma;
    const agg = await client.refund.aggregate({
      where: { bookingId, status: "SUCCEEDED" },
      _sum: { amount: true },
    });
    return agg._sum.amount ?? 0;
  },

  /** Pending + approved + processing — refund yang "in-flight" (belum settled).
   *  Dipakai untuk cek apakah booking masih punya refund aktif. */
  async hasActiveRefund(bookingId: string, tx?: Prisma.TransactionClient): Promise<boolean> {
    const client = tx ?? prisma;
    const count = await client.refund.count({
      where: {
        bookingId,
        status: { in: ["PENDING", "APPROVED", "PROCESSING"] },
      },
    });
    return count > 0;
  },

  async create(
    data: Pick<
      Prisma.RefundUncheckedCreateInput,
      | "bookingId"
      | "paymentId"
      | "amount"
      | "reason"
      | "reportedBy"
      | "reportNote"
      | "initiatedBy"
      | "idempotencyKey"
    >,
    tx?: Prisma.TransactionClient
  ) {
    const client = tx ?? prisma;
    return client.refund.create({ data });
  },

  async update(
    id: string,
    data: Prisma.RefundUncheckedUpdateInput,
    tx?: Prisma.TransactionClient
  ) {
    const client = tx ?? prisma;
    return client.refund.update({ where: { id }, data });
  },
};

export type RefundWithRelations = Awaited<ReturnType<typeof refundRepo.findById>>;
