import { Injectable, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import * as crypto from 'crypto';
import {
  PaymentProviderPort,
  PaymentProviderType,
  CreatePaymentParams,
  PaymentSession,
  PaymentResult,
  WebhookResult,
} from '../../../domain/ports/payment-provider.port';

@Injectable()
export class CryptoProvider implements PaymentProviderPort {
  readonly providerType = PaymentProviderType.CRYPTO;
  private readonly logger = new Logger(CryptoProvider.name);
  private apiKey: string;
  private webhookSecret: string;
  private configured = false;

  private static readonly BASE_URL = 'https://api.commerce.coinbase.com';

  constructor(private readonly configService: ConfigService) {
    this.apiKey = this.configService.get<string>('COINBASE_COMMERCE_API_KEY', '');
    this.webhookSecret = this.configService.get<string>('COINBASE_COMMERCE_WEBHOOK_SECRET', '');
    this.configured = !!(this.apiKey && this.webhookSecret);
  }

  isConfigured(): boolean {
    return this.configured;
  }

  async createPaymentSession(params: CreatePaymentParams): Promise<PaymentSession> {
    if (!this.configured) throw new Error('Coinbase Commerce not configured');

    // Convert cents to dollar amount
    const amount = (params.amount / 100).toFixed(2);

    const response = await fetch(`${CryptoProvider.BASE_URL}/charges`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-CC-Api-Key': this.apiKey,
        'X-CC-Version': '2018-03-22',
      },
      body: JSON.stringify({
        name: 'IT0 Platform',
        description: params.description,
        local_price: { amount, currency: 'USD' },
        pricing_type: 'fixed_price',
        metadata: {
          invoiceId: params.invoiceId,
          tenantId: params.tenantId,
        },
        redirect_url: params.returnUrl,
      }),
    });

    if (!response.ok) {
      const text = await response.text();
      throw new Error(`Coinbase Commerce API error ${response.status}: ${text}`);
    }

    const data = await response.json();
    const charge = data.data;

    return {
      providerPaymentId: charge.id,
      redirectUrl: charge.hosted_url,
      expiresAt: new Date(charge.expires_at),
    };
  }

  async confirmPayment(providerPaymentId: string): Promise<PaymentResult> {
    // Coinbase Commerce uses async webhook notification
    return { providerPaymentId, status: 'pending', amount: 0, currency: 'USD' };
  }

  async handleWebhook(rawBody: Buffer, headers: Record<string, string>): Promise<WebhookResult> {
    if (!this.configured) throw new Error('Coinbase Commerce not configured');

    const signature = headers['x-cc-webhook-signature'];
    const expectedSig = crypto
      .createHmac('sha256', this.webhookSecret)
      .update(rawBody)
      .digest('hex');

    if (!crypto.timingSafeEqual(Buffer.from(signature, 'hex'), Buffer.from(expectedSig, 'hex'))) {
      throw new Error('Coinbase Commerce webhook signature invalid');
    }

    const payload = JSON.parse(rawBody.toString());
    const eventType = payload.event?.type;
    const chargeCode = payload.event?.data?.code;

    if (eventType === 'charge:confirmed' || eventType === 'charge:resolved') {
      return { type: 'payment_succeeded', providerPaymentId: chargeCode };
    } else if (eventType === 'charge:failed' || eventType === 'charge:delayed') {
      return { type: 'payment_failed', providerPaymentId: chargeCode };
    }

    return { type: 'unknown' };
  }
}
