import { Injectable, NotFoundException, BadRequestException } from '@nestjs/common';
import { PaymentProviderRegistry } from '../../infrastructure/payment-providers/payment-provider.registry';
import { PaymentRepository } from '../../infrastructure/repositories/payment.repository';
import { InvoiceRepository } from '../../infrastructure/repositories/invoice.repository';
import { SubscriptionRepository } from '../../infrastructure/repositories/subscription.repository';
import { Payment, PaymentStatus } from '../../domain/entities/payment.entity';
import { PaymentProviderType } from '../../domain/ports/payment-provider.port';
import { InvoiceStatus } from '../../domain/entities/invoice.entity';

export interface CreatePaymentSessionDto {
  tenantId: string;
  invoiceId: string;
  provider: PaymentProviderType;
  returnUrl?: string;
}

@Injectable()
export class CreatePaymentSessionUseCase {
  constructor(
    private readonly providerRegistry: PaymentProviderRegistry,
    private readonly paymentRepo: PaymentRepository,
    private readonly invoiceRepo: InvoiceRepository,
    private readonly subscriptionRepo: SubscriptionRepository,
  ) {}

  async execute(dto: CreatePaymentSessionDto) {
    const { tenantId, invoiceId, provider, returnUrl } = dto;

    const invoice = await this.invoiceRepo.findById(invoiceId);
    if (!invoice || invoice.tenantId !== tenantId) {
      throw new NotFoundException('Invoice not found');
    }
    if (invoice.status === InvoiceStatus.PAID) {
      throw new BadRequestException('Invoice is already paid');
    }

    const paymentProvider = this.providerRegistry.get(provider);
    if (!paymentProvider) {
      throw new BadRequestException(`Payment provider '${provider}' is not configured`);
    }

    const session = await paymentProvider.createPaymentSession({
      invoiceId,
      tenantId,
      amount: invoice.amountDueCents,
      currency: invoice.currency,
      description: `IT0 Invoice ${invoice.invoiceNumber}`,
      returnUrl: returnUrl ?? '',
    });

    // Create a pending payment record
    const payment = new Payment();
    payment.tenantId = tenantId;
    payment.invoiceId = invoiceId;
    payment.provider = provider;
    payment.providerPaymentId = session.providerPaymentId;
    payment.amountCents = invoice.amountDueCents;
    payment.currency = invoice.currency;
    payment.status = PaymentStatus.PENDING;
    payment.metadata = { provider };

    await this.paymentRepo.savePayment(payment);

    return session;
  }
}
