import { CommonModule } from '@angular/common';
import {
  Component,
  DestroyRef,
  Injector,
  computed,
  inject,
  input,
  signal,
} from '@angular/core';
import { takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop';
import { Router, RouterLink } from '@angular/router';
import { TranslateModule, TranslateService } from '@ngx-translate/core';
import {
  catchError,
  combineLatest,
  finalize,
  forkJoin,
  of,
  switchMap,
  tap,
} from 'rxjs';
import { SeoService } from '../../core/services/seo.service';
import { LanguageService } from '../../core/services/language.service';
import { AppButtonComponent } from '../../shared/components/app-button/app-button.component';
import { AppCardComponent } from '../../shared/components/app-card/app-card.component';
import { ProductCardComponent } from './components/product-card/product-card.component';
import {
  ShopCategoryDetail,
  ShopCategoryNavNode,
  ShopCategoryTree,
  ShopCartItem,
  ShopProductSummary,
  ShopService,
} from './services/shop.service';
import { ShopRouteService } from './services/shop-route.service';

@Component({
  selector: 'app-shop-page',
  standalone: true,
  imports: [
    CommonModule,
    TranslateModule,
    RouterLink,
    AppButtonComponent,
    AppCardComponent,
    ProductCardComponent,
  ],
  templateUrl: './shop-page.component.html',
  styleUrl: './shop-page.component.scss',
})
export class ShopPageComponent {
  private readonly destroyRef = inject(DestroyRef);
  private readonly injector = inject(Injector);
  private readonly router = inject(Router);
  private readonly translate = inject(TranslateService);
  private readonly seoService = inject(SeoService);
  private readonly languageService = inject(LanguageService);
  private readonly shopRouteService = inject(ShopRouteService);
  readonly shopService = inject(ShopService);

  readonly categorySlug = input<string | undefined>();

  readonly loading = signal(true);
  readonly error = signal<string | null>(null);
  readonly categories = signal<ShopCategoryTree[]>([]);
  readonly categoryNodes = signal<ShopCategoryNavNode[]>([]);
  readonly selectedCategory = signal<ShopCategoryDetail | null>(null);
  readonly products = signal<ShopProductSummary[]>([]);

  readonly cartMutating = signal(false);
  readonly busyLineItemId = signal<string | null>(null);

  readonly cart = this.shopService.cart;
  readonly cartLoading = this.shopService.cartLoading;
  readonly cartItemCount = this.shopService.cartItemCount;
  readonly currentCategorySlug = computed(
    () => this.selectedCategory()?.slug ?? this.categorySlug() ?? null,
  );
  readonly cartItems = computed(() =>
    (this.cart()?.items ?? []).filter(
      (item) => item.lineItemType === 'SHOP_PRODUCT',
    ),
  );
  readonly cartHasItems = computed(() => this.cartItems().length > 0);

  constructor() {
    if (!this.shopService.cartLoaded()) {
      this.shopService
        .loadCart()
        .pipe(takeUntilDestroyed(this.destroyRef))
        .subscribe({
          error: () => {
            this.shopService.cart.set(null);
          },
        });
    }

    combineLatest([
      toObservable(this.categorySlug, { injector: this.injector }),
      toObservable(this.languageService.currentLang, {
        injector: this.injector,
      }),
    ])
      .pipe(
        tap(() => {
          this.loading.set(true);
          this.error.set(null);
        }),
        switchMap(([categorySlug]) =>
          forkJoin({
            categories: this.shopService.getCategories(),
            catalog: this.shopService.getProductCatalog(categorySlug ?? null),
          }).pipe(
            catchError((error) => {
              this.categories.set([]);
              this.categoryNodes.set([]);
              this.selectedCategory.set(null);
              this.products.set([]);
              this.error.set(
                error?.status === 404 ? 'SHOP.NOT_FOUND' : 'SHOP.LOAD_ERROR',
              );
              this.applyDefaultSeo();
              return of(null);
            }),
            finalize(() => this.loading.set(false)),
          ),
        ),
        takeUntilDestroyed(this.destroyRef),
      )
      .subscribe((result) => {
        if (!result) {
          return;
        }

        this.categories.set(result.categories);
        this.categoryNodes.set(
          this.shopService.flattenCategoryTree(
            result.categories,
            result.catalog.category?.slug ?? this.categorySlug() ?? null,
          ),
        );
        this.selectedCategory.set(result.catalog.category ?? null);
        this.products.set(result.catalog.products);
        this.applySeo(result.catalog.category ?? null);
      });
  }

  productCartQuantity(productId: string): number {
    return this.shopService.quantityForProduct(productId);
  }

  cartItemName(item: ShopCartItem): string {
    return (
      item.displayName || item.shopProductName || item.originalFilename || '-'
    );
  }

  cartItemVariant(item: ShopCartItem): string | null {
    return item.shopVariantLabel || item.shopVariantColorName || null;
  }

  cartItemColor(item: ShopCartItem): string | null {
    return item.shopVariantColorName || item.colorCode || null;
  }

  cartItemColorHex(item: ShopCartItem): string {
    return item.shopVariantColorHex || '#c9ced6';
  }

  navigateToCategory(slug?: string | null): void {
    this.router.navigate(this.shopRouteService.shopRootCommands(slug));
  }

  increaseQuantity(item: ShopCartItem): void {
    this.updateItemQuantity(item, (item.quantity ?? 0) + 1);
  }

  decreaseQuantity(item: ShopCartItem): void {
    const nextQuantity = Math.max(1, (item.quantity ?? 1) - 1);
    this.updateItemQuantity(item, nextQuantity);
  }

  removeItem(item: ShopCartItem): void {
    this.cartMutating.set(true);
    this.busyLineItemId.set(item.id);
    this.shopService
      .removeCartItem(item.id)
      .pipe(
        finalize(() => {
          this.cartMutating.set(false);
          this.busyLineItemId.set(null);
        }),
        takeUntilDestroyed(this.destroyRef),
      )
      .subscribe({
        error: () => {
          this.error.set('SHOP.CART_UPDATE_ERROR');
        },
      });
  }

  clearCart(): void {
    this.cartMutating.set(true);
    this.busyLineItemId.set(null);
    this.shopService
      .clearCart()
      .pipe(
        finalize(() => {
          this.cartMutating.set(false);
        }),
        takeUntilDestroyed(this.destroyRef),
      )
      .subscribe({
        error: () => {
          this.error.set('SHOP.CART_UPDATE_ERROR');
        },
      });
  }

  goToCheckout(): void {
    const sessionId = this.shopService.cartSessionId();
    if (!sessionId) {
      return;
    }
    this.router.navigate(['/checkout'], {
      queryParams: {
        session: sessionId,
      },
    });
  }

  trackByCategory(_index: number, item: ShopCategoryNavNode): string {
    return item.id;
  }

  trackByProduct(_index: number, product: ShopProductSummary): string {
    return product.id;
  }

  trackByCartItem(_index: number, item: ShopCartItem): string {
    return item.id;
  }

  private updateItemQuantity(item: ShopCartItem, quantity: number): void {
    this.cartMutating.set(true);
    this.busyLineItemId.set(item.id);
    this.shopService
      .updateCartItem(item.id, quantity)
      .pipe(
        finalize(() => {
          this.cartMutating.set(false);
          this.busyLineItemId.set(null);
        }),
        takeUntilDestroyed(this.destroyRef),
      )
      .subscribe({
        error: () => {
          this.error.set('SHOP.CART_UPDATE_ERROR');
        },
      });
  }

  private applySeo(category: ShopCategoryDetail | null): void {
    if (!category) {
      this.applyDefaultSeo();
      return;
    }

    const title =
      category.seoTitle ||
      `${category.name} | ${this.translate.instant('SHOP.TITLE')} | 3D fab`;
    const description =
      category.seoDescription ||
      category.description ||
      this.translate.instant('SHOP.CATALOG_META_DESCRIPTION');
    const robots =
      category.indexable === false ? 'noindex, nofollow' : 'index, follow';

    this.seoService.applyPageSeo({
      title,
      description,
      robots,
      ogTitle: category.ogTitle || title,
      ogDescription: category.ogDescription || description,
    });
  }

  private applyDefaultSeo(): void {
    const title = `${this.translate.instant('SHOP.TITLE')} | 3D fab`;
    const description = this.translate.instant('SHOP.CATALOG_META_DESCRIPTION');

    this.seoService.applyPageSeo({
      title,
      description,
      robots: 'index, follow',
      ogTitle: title,
      ogDescription: description,
    });
  }
}
