import { inject, Injectable, signal } from '@angular/core';
import { catchError, map, Observable, tap } from 'rxjs';

import { ApiResponse } from '../api-response.interface';
import { BaseApiService } from '../base-api.service';
import { CatalogAvailabilityService } from '../catalog/catalog-availability.service';
import { TenantService } from '../tenant.service';
import { Cart } from './cart.interface';

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

  private readonly cartState = signal<Cart | null>(null);
  readonly cart = this.cartState.asReadonly();

  private readonly isUpdatingState = signal<boolean>(false);
  readonly isUpdating = this.isUpdatingState.asReadonly();

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

  clearCart(): void {
    this.cartState.set({
      id: null,
      tenant_codigo: this.tenantService.tenant()?.codigo ?? '',
      status: 'active',
      items: [],
      subtotal: '0.00',
    });
  }

  loadCart(refreshCatalogAvailability = false): Observable<Cart> {
    return this.http
      .get<ApiResponse<Cart>>(`${this.tenantApiUrl}/cart`, {
        withCredentials: true,
      })
      .pipe(
        map((response) => response.data),
        tap((cart) => {
          this.cartState.set(cart);
          if (refreshCatalogAvailability) {
            this.catalogAvailabilityService.notifyAvailabilityChanged();
          }
        }),
      );
  }

  addItem(
    catalogItemId: number,
    variantId: number | null,
    cantidad: number,
  ): Observable<ApiResponse<Cart>> {
    this.isUpdatingState.set(true);
    return this.http
      .post<ApiResponse<Cart>>(
        `${this.tenantApiUrl}/cart/items`,
        { catalog_item_id: catalogItemId, variant_id: variantId, cantidad },
        {
          withCredentials: true,
        },
      )
      .pipe(
        tap((response) => {
          this.cartState.set(response.data);
          this.catalogAvailabilityService.notifyAvailabilityChanged();
          this.isUpdatingState.set(false);
        }),
        catchError((error) => {
          this.isUpdatingState.set(false);
          throw error;
        }),
      );
  }

  updateItemQuantity(cartItemId: number, cantidad: number): Observable<ApiResponse<Cart>> {
    return this.updateItem(cartItemId, { cantidad });
  }

  updateItemVariant(
    cartItemId: number,
    cantidad: number,
    variantId: number,
  ): Observable<ApiResponse<Cart>> {
    return this.updateItem(cartItemId, { cantidad, variant_id: variantId });
  }

  private updateItem(
    cartItemId: number,
    payload: { cantidad: number; variant_id?: number },
  ): Observable<ApiResponse<Cart>> {
    this.isUpdatingState.set(true);
    return this.http
      .patch<ApiResponse<Cart>>(`${this.tenantApiUrl}/cart/items/${cartItemId}`, payload, {
        withCredentials: true,
      })
      .pipe(
        tap((response) => {
          this.cartState.set(response.data);
          this.catalogAvailabilityService.notifyAvailabilityChanged();
          this.isUpdatingState.set(false);
        }),
        catchError((error) => {
          this.isUpdatingState.set(false);
          throw error;
        }),
      );
  }

  removeItem(cartItemId: number): Observable<ApiResponse<Cart>> {
    this.isUpdatingState.set(true);
    return this.http
      .delete<ApiResponse<Cart>>(`${this.tenantApiUrl}/cart/items/${cartItemId}`, {
        withCredentials: true,
      })
      .pipe(
        tap((response) => {
          this.cartState.set(response.data);
          this.catalogAvailabilityService.notifyAvailabilityChanged();
          this.isUpdatingState.set(false);
        }),
        catchError((error) => {
          this.isUpdatingState.set(false);
          throw error;
        }),
      );
  }
}
