import {
  ChangeDetectionStrategy,
  Component,
  Injector,
  OnDestroy,
  OnInit,
  computed,
  inject,
  signal,
} from '@angular/core';
import { HttpErrorResponse } from '@angular/common/http';
import { ActivatedRoute, Router } from '@angular/router';
import { Subscription } from 'rxjs';

import { CartService } from '../../../../core/services/cart/cart.service';
import { AuthService } from '../../../../core/services/auth/auth.service';
import { CatalogFeaturedGroup } from '../../../../core/services/catalog/catalog.interface';
import { CatalogService } from '../../../../core/services/catalog/catalog.service';
import { TenantService } from '../../../../core/services/tenant.service';
import { ToastService } from '../../../../core/services/toast.service';
import { CheckoutService } from '../../../../core/services/checkout.service';
import {
  ProductListComponent,
  ProductListCartEvent,
  ProductListBuyEvent,
} from '../../../../shared/components/product-list/product-list.component';
import { HeroBannerComponent } from '../../../../shared/components/hero-banner/hero-banner.component';
import { MainCarouselComponent } from '../../../../shared/components/main-carousel/main-carousel.component';
import { StoreSectionComponent } from '../../../../shared/components/store-section/store-section.component';
import {
  STORE_HOME_PRODUCTS_ERROR_MESSAGE,
  StoreHomeCatalogResolvedData,
} from './store-home-page.resolver';

@Component({
  selector: 'app-store-home-page',
  imports: [
    StoreSectionComponent,
    ProductListComponent,
    HeroBannerComponent,
    MainCarouselComponent,
  ],
  templateUrl: './store-home-page.component.html',
  styleUrl: './store-home-page.component.scss',
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class StoreHomePageComponent implements OnInit, OnDestroy {
  private readonly cartService = inject(CartService);
  private readonly catalogService = inject(CatalogService);
  private readonly injector = inject(Injector);
  private readonly route = inject(ActivatedRoute);
  private readonly router = inject(Router);
  private readonly tenantService = inject(TenantService);
  private readonly toastService = inject(ToastService);

  protected readonly tenant = this.tenantService.tenant;
  protected readonly catalog = signal<CatalogFeaturedGroup[]>([]);
  protected readonly loading = signal(false);
  protected readonly loadingGroupIds = signal<ReadonlySet<number>>(new Set());
  protected readonly error = signal<string | null>(null);
  protected readonly mainCarouselReady = signal(false);
  protected readonly creatingDirectPurchase = signal(false);
  protected readonly hasMainCarouselImages = computed(
    () => (this.tenant()?.main_carousel_images?.length ?? 0) > 0,
  );

  private catalogRequestSubscription: Subscription | null = null;
  private readonly groupRequestSubscriptions = new Map<number, Subscription>();

  ngOnInit(): void {
    const resolvedData = this.route.snapshot.data['catalogData'] as
      | StoreHomeCatalogResolvedData
      | undefined;

    if (resolvedData) {
      this.applyResolvedData(resolvedData);
      return;
    }

    this.loadCatalog();
  }

  ngOnDestroy(): void {
    this.catalogRequestSubscription?.unsubscribe();
    this.groupRequestSubscriptions.forEach((subscription) => subscription.unsubscribe());
  }

  protected isGroupLoading(groupId: number): boolean {
    return this.loadingGroupIds().has(groupId);
  }

  protected onPageChange(groupId: number, page: number): void {
    const group = this.catalog().find((candidate) => candidate.id === groupId);

    if (
      !group ||
      Array.isArray(group.items) ||
      page < 1 ||
      page === group.items.meta.current_page ||
      this.isGroupLoading(groupId)
    ) {
      return;
    }

    this.setGroupLoading(groupId, true);
    this.groupRequestSubscriptions.get(groupId)?.unsubscribe();

    const subscription = this.catalogService
      .withCustomLoading()
      .getFeaturedGroupItems(groupId, { page })
      .subscribe({
      next: (items) => {
        this.catalog.update((groups) =>
          groups.map((candidate) =>
            candidate.id === groupId ? { ...candidate, items } : candidate,
          ),
        );
        this.error.set(null);
      },
      error: () => {
        this.error.set(STORE_HOME_PRODUCTS_ERROR_MESSAGE);
        this.setGroupLoading(groupId, false);
      },
      complete: () => this.setGroupLoading(groupId, false),
    });

    this.groupRequestSubscriptions.set(groupId, subscription);
  }

  protected async onBuyProduct(event: ProductListBuyEvent): Promise<void> {
    if (!event.directPurchase) {
      await this.router.navigate(['/producto', event.product.id]);
      return;
    }

    if (this.creatingDirectPurchase()) {
      return;
    }

    if (!this.injector.get(AuthService).user()) {
      await this.router.navigate(['/login'], {
        queryParams: { returnUrl: `/producto/${event.product.id}` },
      });
      return;
    }

    const tenant = this.tenantService.tenant();
    if (!tenant) {
      this.toastService.danger('No se pudo identificar la tienda.');
      return;
    }

    this.creatingDirectPurchase.set(true);
    try {
      const purchase = await this.injector.get(CheckoutService).startCheckout(tenant.codigo, {
        direct_item: {
          catalog_item_id: event.product.id,
          variant_id: event.variant ?? null,
          cantidad: event.quantity,
        },
      });
      await this.router.navigate(['/checkout'], { queryParams: { purchase: purchase.id } });
    } catch (error) {
      console.error('Failed to create direct purchase:', error);
      this.toastService.danger('No se pudo iniciar la compra directa.');
    } finally {
      this.creatingDirectPurchase.set(false);
    }
  }

  protected onAddToCart(event: ProductListCartEvent): void {
    this.cartService.addItem(event.product.id, event.variant ?? null, event.quantity).subscribe({
      next: (response) => {
        this.toastService.success(response.message || 'Producto agregado al carrito');
      },
      error: (error: HttpErrorResponse) => {
        const message = error.error?.message || 'No se pudo agregar el producto al carrito.';
        this.toastService.danger(message);
      },
    });
  }

  private loadCatalog(): void {
    this.loading.set(true);
    this.error.set(null);
    this.catalogRequestSubscription?.unsubscribe();

    this.catalogRequestSubscription = this.catalogService
      .withCustomLoading()
      .getCatalog()
      .subscribe({
      next: (catalog) => this.catalog.set(catalog),
      error: () => {
        this.catalog.set([]);
        this.loading.set(false);
        this.error.set(STORE_HOME_PRODUCTS_ERROR_MESSAGE);
      },
      complete: () => this.loading.set(false),
    });
  }

  private applyResolvedData(resolvedData: StoreHomeCatalogResolvedData): void {
    this.catalog.set(resolvedData.response ?? []);
    this.loading.set(false);
    this.error.set(resolvedData.error);
  }

  private setGroupLoading(groupId: number, loading: boolean): void {
    this.loadingGroupIds.update((current) => {
      const updated = new Set(current);
      loading ? updated.add(groupId) : updated.delete(groupId);
      return updated;
    });
  }
}
