import { BadGatewayException, Injectable, Logger } from "@nestjs/common";
import { HttpService } from "@nestjs/axios";
import { AxiosError } from "axios";
import { firstValueFrom } from "rxjs";
import {
  InitiatePaymentRequest,
  PaymentIntentSnapshot,
  PaymentReferenceType,
  PaymentService,
} from "@edr/types";

/**
 * Thin HTTP client for the payment microservice (apps/edr-payment-api) — the passenger app's
 * side of the Phase 6 cutover (docs/payment-service §10). Domain validation stays here;
 * provider calls, intents, and webhooks live in the payment service.
 */
@Injectable()
export class PaymentClientService {
  private readonly logger = new Logger(PaymentClientService.name);
  private readonly baseUrl = (
    process.env.PAYMENT_API_URL ?? "http://localhost:3003"
  ).replace(/\/$/, "");
  private readonly serviceToken = process.env.SERVICE_AUTH_TOKEN ?? "";

  constructor(private readonly http: HttpService) {}

  /** POST /payments/initiate — idempotent per (service, referenceType, referenceId). */
  async initiate(
    request: InitiatePaymentRequest,
  ): Promise<PaymentIntentSnapshot> {
    return this.call("POST", "/payments/initiate", request);
  }

  /** GET /payments/intents?… — active intent by domain reference; null when none exists. */
  async getIntentByReference(
    referenceType: PaymentReferenceType,
    referenceId: string,
  ): Promise<PaymentIntentSnapshot | null> {
    const query = new URLSearchParams({
      service: PaymentService.PASSENGER,
      referenceType,
      referenceId,
    });
    try {
      return await this.call("GET", `/payments/intents?${query.toString()}`);
    } catch (err) {
      if (err instanceof AxiosError && err.response?.status === 404)
        return null;
      throw err;
    }
  }

  private async call<T>(
    method: "GET" | "POST",
    path: string,
    body?: unknown,
  ): Promise<T> {
    const url = `${this.baseUrl}${path}`;
    this.logger.log("=====================================================================");
    this.logger.log(`URL ${url}`);
    this.logger.log("=====================================================================");
    try {
      const response = await firstValueFrom(
        this.http.request<T>({
          method,
          url,
          data: body,
          headers: this.serviceToken
            ? { "x-service-token": this.serviceToken }
            : {},
        }),
      );
      return response.data;
    } catch (err) {
      if (err instanceof AxiosError && err.response) {
        // 4xx/5xx from the payment service: propagate 404 to callers that handle it;
        // everything else is a gateway-level failure from the client's perspective.
        if (err.response.status === 404) throw err;
        const detail =
          (err.response.data as { message?: string | string[] })?.message ??
          err.message;
        this.logger.error(
          `payment service ${method} ${path} → ${err.response.status}: ${detail}`,
        );
        throw new BadGatewayException(`Payment service error: ${detail}`);
      }
      const message =
        err instanceof Error && err.message ? err.message : String(err);
      this.logger.error(
        `payment service unreachable (${method} ${path}): ${message}`,
      );
      throw new BadGatewayException("Payment service unreachable");
    }
  }
}
