import { HttpParams } from '@angular/common/http';
import { inject, Injectable } from '@angular/core';
import { map, Observable } from 'rxjs';

import { ApiPaginationQueryParams } from '../api-pagination-query-params.interface';
import { ApiPaginatedResponse } from '../api-paginated-response.interface';
import { ApiResponse } from '../api-response.interface';
import { BaseApiService } from '../base-api.service';
import { TenantService } from '../tenant.service';
import {
  CatalogFeaturedGroup,
  CatalogFeaturedItem,
  CatalogFeaturedItems,
  CatalogItemDetail,
  CatalogVariantOptionsResponse,
  CategoryItemsResponse,
} from './catalog.interface';

type HttpParamValue = string | number | boolean | readonly (string | number | boolean)[];

export interface CatalogSearchQueryParams extends ApiPaginationQueryParams {
  q: string;
}

@Injectable({
  providedIn: 'root',
})
export class CatalogService extends BaseApiService {
  private readonly tenantService = inject(TenantService);

  private get tenantApiUrl(): string {
    return this.tenantService.getTenantApiUrl();
  }

  getCatalog(): Observable<CatalogFeaturedGroup[]> {
    return this.http.get<CatalogFeaturedGroup[]>(`${this.tenantApiUrl}/catalog`);
  }

  searchCatalog(
    params: CatalogSearchQueryParams,
  ): Observable<ApiPaginatedResponse<CatalogFeaturedItem[]>> {
    return this.http.get<ApiPaginatedResponse<CatalogFeaturedItem[]>>(
      `${this.tenantApiUrl}/catalog-items`,
      {
        params: this.buildHttpParams(params),
      },
    );
  }

  getCategoryItems(
    categoryId: number,
    params?: ApiPaginationQueryParams,
  ): Observable<CategoryItemsResponse> {
    return this.http.get<CategoryItemsResponse>(`${this.tenantApiUrl}/categories/${categoryId}`, {
      params: this.buildHttpParams(params),
    });
  }

  getFeaturedGroupItems(
    featuredGroupId: number,
    params?: ApiPaginationQueryParams,
  ): Observable<CatalogFeaturedItems> {
    return this.http.get<CatalogFeaturedItems>(
      `${this.tenantApiUrl}/catalog/featured-groups/${featuredGroupId}/items`,
      {
        params: this.buildHttpParams(params),
      },
    );
  }

  getCatalogItem(id: number, variantId?: number): Observable<CatalogItemDetail> {
    let params = new HttpParams();
    if (variantId) {
      params = params.set('variant_id', variantId);
    }

    return this.http
      .get<ApiResponse<CatalogItemDetail>>(`${this.tenantApiUrl}/catalog-items/${id}`, {
        params,
      })
      .pipe(map((response) => response.data));
  }

  getVariantOptions(
    catalogItemId: number,
    payload: {
      selected_values: Record<string, string | string[]>;
      cart_item_id?: number | null;
    },
  ): Observable<CatalogVariantOptionsResponse> {
    return this.http
      .post<
        ApiResponse<CatalogVariantOptionsResponse>
      >(`${this.tenantApiUrl}/catalog-items/${catalogItemId}/variant-options`, payload, { withCredentials: true })
      .pipe(map((response) => response.data));
  }

  private buildHttpParams(params?: ApiPaginationQueryParams): HttpParams {
    if (!params) {
      return new HttpParams();
    }

    const fromObject = Object.entries(params).reduce<Record<string, HttpParamValue>>(
      (acc, [key, value]) => {
        if (value !== undefined) {
          acc[key] = value;
        }

        return acc;
      },
      {},
    );

    return new HttpParams({ fromObject });
  }
}
