/**
 * @ai-summary Donations business logic and payment processing
 * @ai-context Manages one-time donations with Stripe PaymentIntent
 */

import { Pool } from 'pg';
import { logger } from '../../../core/logging/logger';
import { SubscriptionsRepository } from '../data/subscriptions.repository';
import { StripeClient } from '../external/stripe/stripe.client';
import { Donation, DonationResponse } from './subscriptions.types';

export class DonationsService {
  constructor(
    private repository: SubscriptionsRepository,
    private stripeClient: StripeClient,
    _pool: Pool
  ) {}

  /**
   * Create a payment intent for donation
   */
  async createDonation(
    userId: string,
    amountCents: number,
    currency: string = 'usd'
  ): Promise<{ clientSecret: string; donationId: string }> {
    try {
      logger.info('Creating donation', { userId, amountCents, currency });

      // Validate amount (must be positive, Stripe has $0.50 minimum)
      if (amountCents < 50) {
        throw new Error('Donation amount must be at least $0.50');
      }

      if (amountCents <= 0) {
        throw new Error('Donation amount must be positive');
      }

      // Create Stripe PaymentIntent
      const paymentIntent = await this.stripeClient.createPaymentIntent(
        amountCents,
        currency
      );

      // Create donation record in database (status: pending)
      const donation = await this.repository.createDonation({
        userId,
        stripePaymentIntentId: paymentIntent.id,
        amountCents,
        currency,
      });

      logger.info('Donation created', {
        donationId: donation.id,
        paymentIntentId: paymentIntent.id,
        userId,
        amountCents,
      });

      // Return clientSecret for frontend to complete payment
      if (!paymentIntent.client_secret) {
        throw new Error('Payment intent did not return client_secret');
      }

      return {
        clientSecret: paymentIntent.client_secret,
        donationId: donation.id,
      };
    } catch (error: any) {
      logger.error('Failed to create donation', {
        userId,
        amountCents,
        currency,
        error: error.message,
      });
      throw error;
    }
  }

  /**
   * Complete donation after payment succeeds
   */
  async completeDonation(
    stripePaymentIntentId: string
  ): Promise<Donation | null> {
    try {
      logger.info('Completing donation', { stripePaymentIntentId });

      // Find donation by payment intent ID
      const donation = await this.repository.findDonationByPaymentIntentId(
        stripePaymentIntentId
      );

      if (!donation) {
        logger.warn('Donation not found for payment intent', { stripePaymentIntentId });
        return null;
      }

      // Update donation status to 'succeeded'
      const updatedDonation = await this.repository.updateDonation(donation.id, {
        status: 'succeeded',
      });

      logger.info('Donation completed', {
        donationId: donation.id,
        stripePaymentIntentId,
      });

      return updatedDonation;
    } catch (error: any) {
      logger.error('Failed to complete donation', {
        stripePaymentIntentId,
        error: error.message,
      });
      throw error;
    }
  }

  /**
   * Get user's donation history
   */
  async getUserDonations(userId: string): Promise<DonationResponse[]> {
    try {
      const donations = await this.repository.findDonationsByUserId(userId);
      return donations.map(donation => this.mapToResponse(donation));
    } catch (error: any) {
      logger.error('Failed to get user donations', {
        userId,
        error: error.message,
      });
      throw error;
    }
  }

  /**
   * Map donation entity to response DTO
   */
  private mapToResponse(donation: Donation): DonationResponse {
    return {
      id: donation.id,
      userId: donation.userId,
      stripePaymentIntentId: donation.stripePaymentIntentId,
      amountCents: donation.amountCents,
      currency: donation.currency,
      status: donation.status,
      createdAt: donation.createdAt.toISOString(),
      updatedAt: donation.updatedAt.toISOString(),
    };
  }
}
