import { BadRequestException, Injectable } from "@nestjs/common";
import { PrismaService } from "../../prisma/prisma.service";
import { BookingRequestStatus, BookingStatus, PaymentIntentType, PaymentMethod, PaymentStatus } from "@prisma/client";
import { PushService } from "../push/push.service";

@Injectable()
export class PaymentsService {
  constructor(private prisma: PrismaService, private push: PushService) {}

  async initiateDeposit(dto: { bookingId: string; amount: number; method: PaymentMethod; payerPhone: string }) {
    const now = new Date();

    return this.prisma.$transaction(async (tx) => {
      const booking = await tx.booking.findUnique({ where: { id: dto.bookingId } });
      if (!booking) throw new BadRequestException("Booking not found");
      if (booking.status !== BookingStatus.pending_deposit) throw new BadRequestException("Booking not awaiting deposit");
      if (booking.depositDeadlineAt <= now) throw new BadRequestException("Deposit window expired");

      const min = Number(booking.minDepositAmount);
      const max = Number(booking.maxDepositAmount);
      const amount = Number(dto.amount);

      if (!(amount >= min && amount <= max)) {
        throw new BadRequestException(`Deposit must be between ${min} and ${max}`);
      }

      await tx.booking.update({
        where: { id: booking.id },
        data: { depositAmountSelected: amount as any, updatedAt: now },
      });

      const intent = await tx.paymentIntent.create({
        data: {
          bookingId: booking.id,
          type: PaymentIntentType.DEPOSIT,
          amount: amount as any,
          currency: booking.currency,
          method: dto.method,
          status: PaymentStatus.initiated,
        },
      });

      // In production: create real payment intent with Orange/MyZaka/Card provider here.
      // For this starter template, return intentId so you can simulate webhook.
      return {
        intentId: intent.id,
        status: intent.status,
        method: intent.method,
        amount,
        instructions: { payerPhone: dto.payerPhone },
      };
    });
  }

  async handleWebhook(method: "ORANGE_MONEY" | "MYZAKA" | "CARD", payload: any) {
    // Starter: payload = { intentId: "...", success: true, providerReference?: "..." }
    const intentId = payload.intentId;
    const success = !!payload.success;

    return this.prisma.$transaction(async (tx) => {
      const pi = await tx.paymentIntent.findUnique({ where: { id: intentId } });
      if (!pi) throw new BadRequestException("Payment intent not found");
      if (pi.status === PaymentStatus.succeeded) return { ok: true };

      await tx.paymentIntent.update({
        where: { id: pi.id },
        data: {
          status: success ? PaymentStatus.succeeded : PaymentStatus.failed,
          updatedAt: new Date(),
          providerReference: payload.providerReference ?? pi.providerReference ?? null,
        },
      });

      if (!success) return { ok: true, status: "failed" };

      const booking = await tx.booking.findUnique({ where: { id: pi.bookingId } });
      if (!booking) throw new BadRequestException("Booking not found");

      if (booking.status !== BookingStatus.pending_deposit) {
        return { ok: true, status: "ignored_booking_state" };
      }

      await tx.booking.update({
        where: { id: booking.id },
        data: { status: BookingStatus.confirmed, updatedAt: new Date() },
      });

      await tx.bookingStatusEvent.create({
        data: { bookingId: booking.id, status: "confirmed", actorUserId: null, meta: { paymentIntentId: pi.id, method } },
      });

      await tx.bookingRequest.update({
        where: { id: booking.bookingRequestId },
        data: { status: BookingRequestStatus.matched, updatedAt: new Date() },
      });

      // Push both
      await this.push.sendToUser(booking.clientId, {
        title: "Booking confirmed ✅",
        body: "Deposit received. Your booking is confirmed.",
        data: { type: "BOOKING_CONFIRMED", bookingId: booking.id },
      });

      const provider = await tx.provider.findUnique({ where: { id: booking.providerId } });
      if (provider) {
        await this.push.sendToUser(provider.userId, {
          title: "Booking confirmed ✅",
          body: "Client paid deposit. Prepare for the appointment.",
          data: { type: "BOOKING_CONFIRMED", bookingId: booking.id },
        });
      }

      return { ok: true, status: "confirmed" };
    });
  }

  async getPaymentStatus(intentId: string) {
    const pi = await this.prisma.paymentIntent.findUnique({ where: { id: intentId } });
    if (!pi) throw new BadRequestException("Not found");
    return { intentId: pi.id, status: pi.status, amount: Number(pi.amount), method: pi.method };
  }
}
