import { prisma } from "../../config/prisma";

export function findClientByUserId(userId: string) {
  return prisma.client.findFirst({
    where: { userId, status: "ACTIVE" },
  });
}

export function findInvoiceForPayment(invoiceId: string, clientId: string) {
  return prisma.invoice.findFirst({
    where: { id: invoiceId, clientId },
    include: { items: { include: { service: true } } },
  });
}

export function findInvoiceWithClient(invoiceId: string) {
  return prisma.invoice.findUnique({
    where: { id: invoiceId },
    include: { client: { select: { id: true, email: true, name: true } } },
  });
}

export function updateInvoicePaymentLink(
  invoiceId: string,
  paymentLinkUrl: string
) {
  return prisma.invoice.update({
    where: { id: invoiceId },
    data: { paymentLinkUrl },
  });
}

export function createPayment(data: {
  invoiceId: string;
  clientId: string;
  amount: number;
  method: "CARD";
  transactionRef?: string;
}) {
  return prisma.payment.create({
    data: {
      invoiceId: data.invoiceId,
      clientId: data.clientId,
      amount: data.amount,
      method: data.method,
      status: "INITIATED",
      transactionRef: data.transactionRef,
    },
  });
}

// Find existing INITIATED payment for an invoice (to avoid duplicate rows)
export function findInitiatedPayment(invoiceId: string) {
  return prisma.payment.findFirst({
    where: { invoiceId, status: "INITIATED" },
  });
}

// Update transactionRef on existing payment instead of creating new one
export function updatePaymentTransactionRef(paymentId: string, transactionRef: string) {
  return prisma.payment.update({
    where: { id: paymentId },
    data: { transactionRef },
  });
}

export function findInvoiceForClient(invoiceId: string, clientId: string) {
  return prisma.invoice.findFirst({
    where: { id: invoiceId, clientId },
    include: {
      items: { include: { service: true } },
      payments: {
        orderBy: { createdAt: "desc" },
        select: {
          id: true,
          amount: true,
          method: true,
          status: true,
          transactionRef: true,
          paidAt: true,
          createdAt: true,
        },
      },
    },
  });
}

export async function markInvoicePaid(
  invoiceId: string,
  transactionRef: string
) {
  return prisma.$transaction(async (tx) => {
    const invoice = await tx.invoice.findUnique({
      where: { id: invoiceId },
      select: { status: true, taskId: true },
    });
    if (invoice?.status === "PAID") return;

    await tx.invoice.update({
      where: { id: invoiceId },
      data: { status: "PAID" },
    });
    await tx.payment.updateMany({
      where: { invoiceId },
      data: { status: "SUCCESS", paidAt: new Date() },
    });

    if (invoice?.taskId) {
      await tx.task.update({
        where: { id: invoice.taskId },
        data: { status: "COMPLETED" },
      });
    }
  });
}

export async function markPaymentFailed(invoiceId: string) {
  await prisma.payment.updateMany({
    where: { invoiceId, status: "INITIATED" },
    data: { status: "FAILED" },
  });
}

export async function markTaskPaidStatus(taskId: string) {
  return prisma.task.update({
    where: { id: taskId },
    data: { status: "COMPLETED" },
  });
}

// Find invoice via payment's transactionRef (Stripe session ID)
export function findInvoiceBySessionId(sessionId: string) {
  return prisma.payment.findFirst({
    where: { transactionRef: sessionId },
    select: {
      invoiceId: true,
      invoice: { select: { taskId: true } },
    },
  });
}

export function findInvoiceForAdmin(invoiceId: string) {
  return prisma.invoice.findUnique({
    where: { id: invoiceId },
    include: {
      client: {
        select: { id: true, name: true, email: true, companyName: true },
      },
      items: {
        include: {
          service: { select: { id: true, name: true, category: true } },
        },
      },
      payments: {
        orderBy: { createdAt: "desc" },
        select: {
          id: true,
          amount: true,
          method: true,
          status: true,
          transactionRef: true,
          paidAt: true,
          createdAt: true,
        },
      },
    },
  });
}

export async function findAdminTransactions(
  organizationId: string,
  page: number,
  limit: number,
  status?: string
) {
  const where: any = { invoice: { client: { organizationId } } };
  if (status && status !== "ALL") where.status = status;

  const [data, total] = await Promise.all([
    prisma.payment.findMany({
      where,
      orderBy: { createdAt: "desc" },
      skip: (page - 1) * limit,
      take: limit,
      select: {
        id: true,
        amount: true,
        method: true,
        status: true,
        transactionRef: true,
        paidAt: true,
        createdAt: true,
        invoice: {
          select: {
            id: true,
            invoiceNumber: true,
            totalAmount: true,
            status: true,
            task: { select: { id: true, title: true } },
          },
        },
        client: {
          select: { id: true, name: true, email: true, companyName: true },
        },
      },
    }),
    prisma.payment.count({ where }),
  ]);

  return {
    data,
    meta: {
      total,
      page,
      limit,
      totalPages: Math.ceil(total / limit),
    },
  };
}

export async function findClientTransactions(
  clientId: string,
  page: number,
  limit: number,
  status?: string
) {
  const where: any = { clientId };
  if (status && status !== "ALL") where.status = status;

  const [data, total] = await Promise.all([
    prisma.payment.findMany({
      where,
      orderBy: { createdAt: "desc" },
      skip: (page - 1) * limit,
      take: limit,
      select: {
        id: true,
        amount: true,
        method: true,
        status: true,
        transactionRef: true,
        paidAt: true,
        createdAt: true,
        invoice: {
          select: {
            id: true,
            invoiceNumber: true,
            totalAmount: true,
            status: true,
            task: { select: { id: true, title: true } },
          },
        },
      },
    }),
    prisma.payment.count({ where }),
  ]);

  return {
    data,
    meta: { total, page, limit, totalPages: Math.ceil(total / limit) },
  };
}
