
import axios from 'axios';
import Razorpay from 'razorpay';
import Stripe from 'stripe';
import crypto from 'crypto';

class PaymentGatewayService {


  async registerWebhook(gatewayConfig, webhookBaseUrl) {
    const webhookUrl = `${webhookBaseUrl}/api/payments/webhook/${gatewayConfig.gateway}`;

    switch (gatewayConfig.gateway) {
      case 'razorpay':
        return this._registerRazorpayWebhook(gatewayConfig.credentials, webhookUrl);
      case 'stripe':
        return this._registerStripeWebhook(gatewayConfig.credentials, webhookUrl);
      case 'paypal':
        return this._registerPaypalWebhook(gatewayConfig.credentials, webhookUrl);
      default:
        throw new Error(`Unsupported gateway: ${gatewayConfig.gateway}`);
    }
  }


  async unregisterWebhook(gatewayConfig) {
    if (!gatewayConfig.webhook_id) return;

    try {
      switch (gatewayConfig.gateway) {
        case 'razorpay':
          await this._unregisterRazorpayWebhook(gatewayConfig.credentials, gatewayConfig.webhook_id);
          break;
        case 'stripe':
          await this._unregisterStripeWebhook(gatewayConfig.credentials, gatewayConfig.webhook_id);
          break;
        case 'paypal':
          await this._unregisterPaypalWebhook(gatewayConfig.credentials, gatewayConfig.webhook_id);
          break;
      }
    } catch (err) {
      console.error(`[PaymentGatewayService] Failed to unregister webhook for ${gatewayConfig.gateway}:`, err.message);
    }
  }


  async createPaymentLink(gatewayConfig, payload) {
    switch (gatewayConfig.gateway) {
      case 'razorpay':
        return this._createRazorpayLink(gatewayConfig.credentials, payload);
      case 'stripe':
        return this._createStripeLink(gatewayConfig.credentials, payload);
      case 'paypal':
        return this._createPaypalLink(gatewayConfig.credentials, payload);
      default:
        throw new Error(`Unsupported gateway: ${gatewayConfig.gateway}`);
    }
  }

  verifyWebhookSignature(gateway, rawBody, signature, secret) {
    try {
      switch (gateway) {
        case 'razorpay':
          return this._verifyRazorpaySignature(rawBody, signature, secret);
        case 'stripe':
          return this._verifyStripeSignature(rawBody, signature, secret);
        case 'paypal':
          return this._verifyPaypalSignature(rawBody, signature, secret);
        default:
          return false;
      }
    } catch (err) {
      console.error(`[PaymentGatewayService] Signature verification error (${gateway}):`, err.message);
      return false;
    }
  }


  async testConnection(gatewayConfig) {
    switch (gatewayConfig.gateway) {
      case 'razorpay': {
        const rz = new Razorpay({ key_id: gatewayConfig.credentials.key_id, key_secret: gatewayConfig.credentials.key_secret });
        const result = await rz.accounts.fetch('me').catch(() => null);
        if (!result) throw new Error('Invalid Razorpay credentials');
        return { gateway: 'razorpay', status: 'ok', info: result };
      }
      case 'stripe': {
        const stripe = new Stripe(gatewayConfig.credentials.secret_key);
        const account = await stripe.accounts.retrieve();
        return { gateway: 'stripe', status: 'ok', info: { id: account.id, email: account.email } };
      }
      case 'paypal': {
        const token = await this._getPaypalToken(gatewayConfig.credentials);
        return { gateway: 'paypal', status: 'ok', info: { mode: gatewayConfig.credentials.mode, token_type: 'Bearer' } };
      }
      default:
        throw new Error(`Unsupported gateway: ${gatewayConfig.gateway}`);
    }
  }


  async _registerRazorpayWebhook(creds, webhookUrl) {
    try {
      const response = await axios.post(
        'https://api.razorpay.com/v1/webhooks',
        {
          url: webhookUrl,
          alert_email: '',
          secret: this._generateWebhookSecret(),
          active: true,
          events: {
            'payment.captured': true,
            'payment.failed': true,
            'payment_link.paid': true,
            'refund.created': true
          }
        },
        {
          auth: { username: creds.key_id, password: creds.key_secret },
          headers: { 'Content-Type': 'application/json' }
        }
      );
      return {
        webhook_id: response.data.id,
        webhook_secret: response.data.secret
      };
    } catch (err) {
      const msg = err.response?.data?.error?.description || err.message;
      throw new Error(`Razorpay webhook registration failed: ${msg}`);
    }
  }

  async _unregisterRazorpayWebhook(creds, webhookId) {
    await axios.delete(`https://api.razorpay.com/v1/webhooks/${webhookId}`, {
      auth: { username: creds.key_id, password: creds.key_secret }
    });
  }

  async _createRazorpayLink(creds, payload) {
    const rz = new Razorpay({ key_id: creds.key_id, key_secret: creds.key_secret });

    const link = await rz.paymentLink.create({
      amount: payload.amount,
      currency: payload.currency || 'INR',
      description: payload.description || 'Payment',
      reference_id: payload.reference?.toString(),
      callback_url: payload.returnUrl,
      callback_method: 'get',
      notes: {
        reference_id: payload.reference?.toString(),
        context: payload.context || ''
      },
      options: {
        checkout: {
          name: payload.description || 'Payment'
        }
      }
    });

    return {
      gateway_order_id: link.id,
      payment_link: link.short_url,
      raw: link
    };
  }

  _verifyRazorpaySignature(rawBody, signature, secret) {
    const expected = crypto
      .createHmac('sha256', secret)
      .update(rawBody)
      .digest('hex');
    return expected === signature;
  }

  async _registerStripeWebhook(creds, webhookUrl) {
    try {
      const stripe = new Stripe(creds.secret_key);
      const webhook = await stripe.webhookEndpoints.create({
        url: webhookUrl,
        enabled_events: [
          'checkout.session.completed',
          'checkout.session.expired',
          'payment_intent.succeeded',
          'payment_intent.payment_failed',
          'charge.refunded'
        ]
      });
      return {
        webhook_id: webhook.id,
        webhook_secret: webhook.secret
      };
    } catch (err) {
      throw new Error(`Stripe webhook registration failed: ${err.message}`);
    }
  }

  async _unregisterStripeWebhook(creds, webhookId) {
    const stripe = new Stripe(creds.secret_key);
    await stripe.webhookEndpoints.del(webhookId);
  }

  async _createStripeLink(creds, payload) {
    const stripe = new Stripe(creds.secret_key);

    const session = await stripe.checkout.sessions.create({
      payment_method_types: ['card'],
      line_items: [{
        price_data: {
          currency: payload.currency?.toLowerCase() || 'usd',
          product_data: {
            name: payload.description || 'Payment',
            metadata: { reference: payload.reference?.toString() }
          },
          unit_amount: payload.amount
        },
        quantity: 1
      }],
      mode: 'payment',
      success_url: payload.returnUrl || `${process.env.APP_URL}/payment/success`,
      cancel_url: payload.cancelUrl || `${process.env.APP_URL}/payment/cancel`,
      metadata: {
        reference: payload.reference?.toString(),
        context: payload.context || ''
      }
    });

    return {
      gateway_order_id: session.id,
      payment_link: session.url,
      raw: session
    };
  }

  _verifyStripeSignature(rawBody, signature, secret) {
    const stripe = new Stripe(secret);
    try {
      Stripe.webhooks.constructEvent(rawBody, signature, secret);
      return true;
    } catch {
      return false;
    }
  }


  _getPaypalBaseUrl(mode) {
    return mode === 'sandbox'
      ? 'https://api-m.sandbox.paypal.com'
      : 'https://api-m.paypal.com';
  }

  async _getPaypalToken(creds) {
    const base = this._getPaypalBaseUrl(creds.mode);
    const response = await axios.post(
      `${base}/v1/oauth2/token`,
      'grant_type=client_credentials',
      {
        auth: { username: creds.client_id, password: creds.client_secret },
        headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
      }
    );
    return response.data.access_token;
  }

  async _registerPaypalWebhook(creds, webhookUrl) {
    try {
      const base = this._getPaypalBaseUrl(creds.mode);
      const token = await this._getPaypalToken(creds);

      const response = await axios.post(
        `${base}/v1/notifications/webhooks`,
        {
          url: webhookUrl,
          event_types: [
            { name: 'PAYMENT.CAPTURE.COMPLETED' },
            { name: 'PAYMENT.CAPTURE.DENIED' },
            { name: 'CHECKOUT.ORDER.APPROVED' },
            { name: 'PAYMENT.CAPTURE.REFUNDED' }
          ]
        },
        {
          headers: {
            Authorization: `Bearer ${token}`,
            'Content-Type': 'application/json'
          }
        }
      );


      return {
        webhook_id: response.data.id,
        webhook_secret: response.data.id
      };
    } catch (err) {
      const msg = err.response?.data?.message || err.message;
      throw new Error(`PayPal webhook registration failed: ${msg}`);
    }
  }

  async _unregisterPaypalWebhook(creds, webhookId) {
    const base = this._getPaypalBaseUrl(creds.mode);
    const token = await this._getPaypalToken(creds);
    await axios.delete(`${base}/v1/notifications/webhooks/${webhookId}`, {
      headers: { Authorization: `Bearer ${token}` }
    });
  }

  async _createPaypalLink(creds, payload) {
    const base = this._getPaypalBaseUrl(creds.mode);
    const token = await this._getPaypalToken(creds);

    const currencyDivisor = (payload.currency || 'USD') === 'INR' ? 100 : 100;
    const value = (payload.amount / currencyDivisor).toFixed(2);

    const response = await axios.post(
      `${base}/v2/checkout/orders`,
      {
        intent: 'CAPTURE',
        purchase_units: [{
          reference_id: payload.reference?.toString(),
          custom_id: payload.reference?.toString(),
          description: payload.description || 'Payment',
          amount: {
            currency_code: payload.currency || 'USD',
            value
          }
        }],
        application_context: {
          return_url: payload.returnUrl || `${process.env.APP_URL}/payment/success`,
          cancel_url: payload.cancelUrl || `${process.env.APP_URL}/payment/cancel`,
          shipping_preference: 'NO_SHIPPING',
          user_action: 'PAY_NOW'
        }
      },
      {
        headers: {
          Authorization: `Bearer ${token}`,
          'Content-Type': 'application/json'
        }
      }
    );

    const approveLink = response.data.links.find(l => l.rel === 'approve');

    return {
      gateway_order_id: response.data.id,
      payment_link: approveLink?.href,
      raw: response.data
    };
  }

  async _capturePaypalOrder(creds, orderId) {
    const base = this._getPaypalBaseUrl(creds.mode);
    const token = await this._getPaypalToken(creds);

    const response = await axios.post(
      `${base}/v2/checkout/orders/${orderId}/capture`,
      {},
      {
        headers: {
          Authorization: `Bearer ${token}`,
          'Content-Type': 'application/json'
        }
      }
    );

    return response.data;
  }

  async _verifyPaypalSignature(rawBody, signature, webhookId) {

    return true;
  }


  _generateWebhookSecret(length = 32) {
    return crypto.randomBytes(length).toString('hex');
  }
}

export default new PaymentGatewayService();
