import { HttpClient, HttpErrorResponse, HttpParams } from '@angular/common/http';
import { Injectable, inject } from '@angular/core';
import { Observable, of } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { InventoryRecord, Offer, OfferLookupQuery } from '../models/offer.model';
import { OfferGateway } from './offer-gateway.interface';

/** Contract: docs/backend/PHASE-3-CATALOG-OFFER-FULFILLMENT-CONTRACT.md §7. */
@Injectable({ providedIn: 'root' })
export class OfferApiGateway implements OfferGateway {
  private readonly http = inject(HttpClient);

  loadOffers(sellerId?: string): Observable<Offer[]> {
    const params = sellerId ? new HttpParams().set('sellerId', sellerId) : undefined;
    return this.http.get<Offer[]>('/api/admin/v2/offers', { params });
  }

  lookup(query: OfferLookupQuery): Observable<Offer[]> {
    let params = new HttpParams();
    for (const [key, value] of Object.entries(query)) {
      if (value) {
        params = params.set(key, value);
      }
    }
    return this.http.get<Offer[]>('/api/admin/v2/offers/lookup', { params });
  }

  loadInventory(offerId: string): Observable<InventoryRecord | null> {
    // §7 does not define a dedicated inventory-by-offer endpoint - inferred
    // as a sub-resource of the offer, consistent with this contract's
    // {id}/publish pattern.
    return this.http.get<InventoryRecord | null>(
      `/api/admin/v2/offers/${encodeURIComponent(offerId)}/inventory`,
    );
  }

  publish(offerId: string): Observable<{ ok: true } | { ok: false; errors: string[] }> {
    // §7: publish runs the §5 executability check and fails with 422 +
    // details[], not a 200 body - translated here into the interface's
    // ok:false shape so callers get a value, not an error to catch.
    return this.http
      .post<{ ok: true }>(`/api/admin/v2/offers/${encodeURIComponent(offerId)}/publish`, {})
      .pipe(
        catchError((err: HttpErrorResponse) => {
          if (err.status === 422) {
            const details = err.error?.error?.details ?? [];
            const errors = Array.isArray(details) && details.length > 0
              ? details.map((d: { message?: string }) => d.message ?? 'Validation failed')
              : ['Offer is not executable.'];
            return of({ ok: false as const, errors });
          }
          throw err;
        }),
      );
  }
}
