import { BadRequestException, Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import crypto from 'crypto';

@Injectable()
export class EasebuzzService {
  constructor(private readonly config: ConfigService) {}

  private get key() {
    return this.config.get<string>('payments.easebuzz.key') ?? '';
  }
  private get salt() {
    return this.config.get<string>('payments.easebuzz.salt') ?? '';
  }
  private get apiPath() {
    return (
      this.config.get<string>('payments.easebuzz.apiPath') ??
      'https://pay.easebuzz.in'
    ).replace(/\/+$/, '');
  }
  private get payPath() {
    return (
      this.config.get<string>('payments.easebuzz.payPath') ??
      'https://pay.easebuzz.in/pay/'
    );
  }

  private sha512Lower(input: string) {
    return crypto
      .createHash('sha512')
      .update(input)
      .digest('hex')
      .toLowerCase();
  }

  private buildRequestHash(params: Record<string, string>) {
    // key|txnid|amount|productinfo|firstname|email|udf1..udf10|salt
    const seq = [
      'key',
      'txnid',
      'amount',
      'productinfo',
      'firstname',
      'email',
      'udf1',
      'udf2',
      'udf3',
      'udf4',
      'udf5',
      'udf6',
      'udf7',
      'udf8',
      'udf9',
      'udf10',
    ];
    const base = seq.map((k) => params[k] ?? '').join('|') + `|${this.salt}`;
    return this.sha512Lower(base);
  }

  verifyResponseHash(payload: Record<string, any>) {
    const status = (payload.status ?? '').toString();
    const seq = [
      'udf10',
      'udf9',
      'udf8',
      'udf7',
      'udf6',
      'udf5',
      'udf4',
      'udf3',
      'udf2',
      'udf1',
      'email',
      'firstname',
      'productinfo',
      'amount',
      'txnid',
      'key',
    ];
    let base = `${this.salt}|${status}`;
    for (const k of seq)
      base += `|${payload[k] != null ? String(payload[k]) : ''}`;
    const expected = this.sha512Lower(base);
    const got = (payload.hash ?? '').toString().toLowerCase();
    if (!got) return false;
    if (expected.length !== got.length) return false;
    return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(got));
  }

  async initiatePaymentLink(args: {
    txnid: string;
    amountInr: number;
    productinfo: string;
    firstname: string;
    email: string;
    phone: string;
    surl: string;
    furl: string;
    udf?: Record<string, string | undefined>;
  }): Promise<{ accessKey: string; checkoutUrl: string; raw: any }> {
    if (!this.key || !this.salt) {
      throw new BadRequestException('Easebuzz is not configured');
    }

    const amount = Number(args.amountInr);
    if (!Number.isFinite(amount) || amount <= 0) {
      throw new BadRequestException('Invalid amount');
    }

    const params: Record<string, string> = {
      key: this.key,
      txnid: args.txnid,
      amount: amount.toFixed(2),
      productinfo: args.productinfo,
      firstname: args.firstname,
      email: args.email,
      phone: args.phone,
      surl: args.surl,
      furl: args.furl,
      udf1: args.udf?.udf1 ?? '',
      udf2: args.udf?.udf2 ?? '',
      udf3: args.udf?.udf3 ?? '',
      udf4: args.udf?.udf4 ?? '',
      udf5: args.udf?.udf5 ?? '',
      udf6: args.udf?.udf6 ?? '',
      udf7: args.udf?.udf7 ?? '',
      udf8: args.udf?.udf8 ?? '',
      udf9: args.udf?.udf9 ?? '',
      udf10: args.udf?.udf10 ?? '',
    };

    params.hash = this.buildRequestHash(params);

    const body = new URLSearchParams(params).toString();
    const res = await fetch(`${this.apiPath}/payment/initiateLink`, {
      method: 'POST',
      headers: { 'content-type': 'application/x-www-form-urlencoded' },
      body,
    });
    const rawText = await res.text();
    let raw: any;
    try {
      raw = JSON.parse(rawText);
    } catch {
      raw = { rawText };
    }
    if (!res.ok) {
      const msg =
        (raw?.data && typeof raw.data === 'string' ? raw.data : null) ||
        (raw?.message && typeof raw.message === 'string'
          ? raw.message
          : null) ||
        'Easebuzz initiateLink failed';
      throw new BadRequestException({
        message: msg,
        easebuzzRaw: raw,
      });
    }

    const status = raw?.status;
    const accessKey =
      raw?.data ??
      raw?.access_key ??
      raw?.accessKey ??
      raw?.data?.access_key ??
      raw?.data?.accessKey ??
      null;
    if (!(status === 1 || status === '1') || !accessKey) {
      const msg =
        (raw?.data && typeof raw.data === 'string' ? raw.data : null) ||
        (raw?.message && typeof raw.message === 'string'
          ? raw.message
          : null) ||
        `Easebuzz initiateLink failed (status=${String(status ?? '') || 'unknown'})`;
      throw new BadRequestException({
        message: msg,
        easebuzzRaw: raw,
      });
    }
    return {
      accessKey: String(accessKey),
      checkoutUrl: `${this.payPath}${String(accessKey)}`,
      raw,
    };
  }
}
