import { ChangeDetectionStrategy, Component, DestroyRef, computed, inject, signal } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
import { forkJoin, of } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { Product } from '../../../../core/products/models/product-domain.model';
import { EngagementListResult, Question, RatingSummary, Review, SubmitQuestionInput, SubmitReviewInput } from '../../../../core/products/models/product-engagement.model';
import { ConfigService } from '../../../../core/config/config.service';
import { ProductFacade } from '../../../../facades/platform/product.facade';
import { UserExperienceFacade } from '../../../../facades/platform/user-experience.facade';
import { TranslatePipe } from '../../../../i18n/translate.pipe';
import { TranslateService } from '../../../../i18n/translate.service';
import { LangRoutePipe } from '../../../../pipes/lang-route.pipe';
import { CartService } from '../../../../services';
import { LanguageService } from '../../../../services/language.service';
import { DEFAULT_PRODUCT_PAGE_CONFIG, DEFAULT_USER_EXPERIENCE_CONFIG, ProductPageConfig } from '../../../../shared/models/config';
import { getStockStatus, getTranslatedField } from '../../../../utils/item.utils';
import { ProductShareService } from '../../user-experience/services/product-share.service';
import { SeoService } from '../../../../services/seo.service';
import { AnalyticsService } from '../../../../core/analytics/services/analytics.service';
import { ApiService } from '../../../../services/api.service';
import { LocalStorageService } from '../../../../core/storage/local-storage.service';
import { UserNotificationService } from '../../user-experience/services/user-notification.service';
import { AuthService } from '@marketplaces/auth';

const RESTOCK_SUBSCRIPTIONS_KEY = 'restockSubscriptions';
import { ProductDeliveryInformationComponent } from '../components/delivery-information/delivery-information.component';
import { ProductActionsComponent } from '../components/product-actions/product-actions.component';
import { ProductGalleryComponent } from '../components/product-gallery/product-gallery.component';
import { ProductInformationComponent } from '../components/product-information/product-information.component';
import { ProductDescriptionComponent } from '../components/product-description/product-description.component';
import { ProductSpecificationsComponent } from '../components/product-specifications/product-specifications.component';
import { ProductWarrantyComponent } from '../components/product-warranty/product-warranty.component';
import { RelatedCollectionViewModel, RelatedProductsComponent } from '../components/related-products/related-products.component';
import { ProductVariantSelectorComponent, VariantOptionGroup } from '../components/variant-selector/variant-selector.component';
import { ProductTabItem, ProductTabKey, ProductTabsComponent } from '../engagement/components/product-tabs/product-tabs.component';
import { QuestionListComponent } from '../engagement/components/question-list/question-list.component';
import { ReviewListComponent } from '../engagement/components/review-list/review-list.component';
import { EmptyStateComponent } from '../../../../shared/ui/empty-state/empty-state.component';
import { SkeletonComponent } from '../../../../shared/ui/skeleton/skeleton.component';
import { ButtonComponent } from '../../../../shared/ui/button/button.component';

@Component({
  selector: 'app-product-details-container',
  standalone: true,
  imports: [
    RouterLink,
    LangRoutePipe,
    TranslatePipe,
    ProductActionsComponent,
    ProductGalleryComponent,
    ProductInformationComponent,
    ProductVariantSelectorComponent,
    ProductDeliveryInformationComponent,
    ProductDescriptionComponent,
    ProductSpecificationsComponent,
    ProductWarrantyComponent,
    ProductTabsComponent,
    ReviewListComponent,
    QuestionListComponent,
    RelatedProductsComponent,
    EmptyStateComponent,
    SkeletonComponent,
    ButtonComponent,
  ],
  templateUrl: './product-details-container.component.html',
  styleUrls: ['./product-details-container.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class ProductDetailsContainerComponent {
  private readonly route = inject(ActivatedRoute);
  private readonly router = inject(Router);
  private readonly destroyRef = inject(DestroyRef);
  private readonly configService = inject(ConfigService);
  private readonly productFacade = inject(ProductFacade);
  private readonly uxFacade = inject(UserExperienceFacade);
  private readonly cartService = inject(CartService);
  private readonly languageService = inject(LanguageService);
  private readonly translate = inject(TranslateService);
  private readonly shareService = inject(ProductShareService);
  private readonly seoService = inject(SeoService);
  private readonly analytics = inject(AnalyticsService);
  private readonly apiService = inject(ApiService);
  private readonly storage = inject(LocalStorageService);
  private readonly notifications = inject(UserNotificationService);
  private readonly authService = inject(AuthService);

  readonly productPageConfigState = signal<Required<ProductPageConfig>>(this.resolveProductPageConfig());
  readonly userExperienceConfig = signal(this.resolveUserExperienceConfig());

  readonly product = signal<Product | null>(null);
  readonly relatedProducts = signal<Product[]>([]);
  readonly relatedCollections = signal<RelatedCollectionViewModel[]>([]);
  readonly selectedPhotoIndex = signal(0);
  readonly selectedOptions = signal<Record<string, string>>({});
  readonly selectedColour = signal<string | null>(null);
  readonly selectedSize = signal<string | null>(null);
  readonly loading = signal(true);
  readonly error = signal<string | null>(null);
  readonly missing = signal(false);

  readonly activeTab = signal<ProductTabKey>('description');

  readonly ratingSummary = signal<RatingSummary | null>(null);
  readonly reviewsResult = signal<EngagementListResult<Review> | null>(null);
  readonly questionsResult = signal<EngagementListResult<Question> | null>(null);

  readonly ratingLoading = signal(false);
  readonly reviewsLoading = signal(false);
  readonly questionsLoading = signal(false);
  readonly reviewSubmitting = signal(false);
  readonly questionSubmitting = signal(false);

  readonly reviewsPageSize = computed(() => this.productPageConfigState().reviews.pageSize ?? 5);
  readonly questionsPageSize = computed(() => this.productPageConfigState().questions.pageSize ?? 5);
  readonly reviewsMode = computed(() => this.productPageConfigState().reviews.mode ?? 'pages');

  readonly actionsConfig = computed(() => {
    const config = this.productPageConfigState().actions;
    return {
      addToCart: config.enabled !== false && config.addToCart !== false,
      buyNow: config.enabled !== false && config.buyNow !== false,
      wishlist: config.enabled !== false && config.wishlist !== false,
      compare: config.enabled !== false && config.compare !== false,
      share: config.enabled !== false && config.share !== false,
      notifyMe: config.enabled !== false && config.notifyMe !== false,
    };
  });

  readonly tabsEnabled = computed(() => this.productPageConfigState().tabs.enabled !== false);
  readonly tabs = computed<ProductTabItem[]>(() => {
    const config = this.productPageConfigState();
    const reviewCount = this.ratingSummary()?.totalReviews ?? this.reviewsResult()?.total ?? 0;
    const questionCount = this.questionsResult()?.total ?? 0;
    const defaultItems: ProductTabKey[] = ['description', 'specifications', 'reviews', 'questions', 'delivery', 'warranty'];
    const enabledItems = (config.tabs.items?.length ? config.tabs.items : defaultItems)
      .filter((key): key is ProductTabKey => this.isTabEnabled(key));

    return enabledItems.map(key => ({
      key,
      label: this.getTabLabel(key),
      count: key === 'reviews' ? reviewCount : key === 'questions' ? questionCount : undefined,
      enabled: true
    }));
  });

  readonly availableColours = computed(() => {
    const details = this.product()?.itemDetails;
    if (!details?.length) return [] as string[];
    return [...new Set(details.map(detail => detail.colour || detail.color).filter((colour): colour is string => !!colour))];
  });

  readonly availableSizes = computed(() => {
    const details = this.product()?.itemDetails;
    if (!details?.length) return [] as string[];
    const colour = this.selectedColour();
    const filtered = colour ? details.filter(detail => (detail.colour || detail.color) === colour) : details;
    return [...new Set(filtered.map(detail => detail.size).filter((size): size is string => !!size && size.toLowerCase() !== 'default'))];
  });

  readonly selectedDetail = computed(() => {
    const details = this.product()?.itemDetails;
    if (!details?.length) return null;
    const colour = this.selectedColour();
    const size = this.selectedSize();
    const selectedOptions = this.selectedOptions();
    return details.find(detail =>
      (!colour || (detail.colour || detail.color) === colour) &&
      (!size || detail.size === size) &&
      Object.entries(selectedOptions)
        .filter(([key]) => key !== 'colour' && key !== 'size')
        .every(([key, value]) => {
          const dynamicValue = (detail as any)[key];
          return !value || dynamicValue == null || String(dynamicValue) === value;
        })
    ) ?? null;
  });

  readonly variantOptionGroups = computed<VariantOptionGroup[]>(() => {
    const current = this.product();
    if (!current) {
      return [];
    }

    if (current.variantOptions?.length) {
      return current.variantOptions.map(group => ({
        key: group.key,
        label: group.label || group.key,
        options: group.options.map(option => ({
          value: option.value,
          label: option.label || option.value,
        }))
      }));
    }

    const groups: VariantOptionGroup[] = [];
    const colours = this.availableColours();
    const sizes = this.availableSizes();

    if (colours.length > 0) {
      groups.push({ key: 'colour', label: 'itemDetail.colour', options: colours.map(value => ({ value })) });
    }

    if (sizes.length > 0) {
      groups.push({ key: 'size', label: 'itemDetail.size', options: sizes.map(value => ({ value })) });
    }

    return groups;
  });

  readonly isInWishlist = computed(() => {
    const current = this.product();
    return current ? this.uxFacade.isInWishlist(current.itemID) : false;
  });

  readonly isInCompare = computed(() => {
    const current = this.product();
    return current ? this.uxFacade.isInCompare(current.itemID) : false;
  });

  readonly effectivePrice = computed(() => this.selectedDetail()?.price ?? this.product()?.price ?? 0);
  readonly effectiveCurrency = computed(() => this.selectedDetail()?.currency ?? this.product()?.currency ?? '');
  readonly effectiveRemaining = computed(() => this.selectedDetail()?.remaining ?? this.product()?.quantity ?? null);
  readonly discountedPrice = computed(() => {
    const current = this.product();
    if (!current) return 0;
    return this.effectivePrice() * (1 - (current.discount || 0) / 100);
  });
  readonly stockStatus = computed(() => {
    const current = this.product();
    if (!current) return 'high';
    const remaining = this.effectiveRemaining();
    if (remaining == null) return getStockStatus(current);
    if (remaining <= 0) return 'out';
    if (remaining <= 5) return 'low';
    if (remaining <= 20) return 'medium';
    return 'high';
  });

  constructor() {
    this.ensureInitialActiveTab();

    this.route.paramMap
      .pipe(takeUntilDestroyed(this.destroyRef))
      .subscribe(params => this.loadProduct(Number(params.get('id'))));

    this.destroyRef.onDestroy(() => this.seoService.resetToDefaults());
  }

  loadProduct(productId: number): void {
    if (!productId) {
      this.missing.set(true);
      this.loading.set(false);
      return;
    }

    this.loading.set(true);
    this.error.set(null);
    this.missing.set(false);
    this.product.set(null);
    this.relatedProducts.set([]);
    this.relatedCollections.set([]);
    this.selectedPhotoIndex.set(0);
    this.selectedOptions.set({});
    this.ratingSummary.set(null);
    this.reviewsResult.set(null);
    this.questionsResult.set(null);

    this.productFacade.getProduct(productId)
      .pipe(takeUntilDestroyed(this.destroyRef))
      .subscribe({
        next: product => {
          if (!product) {
            this.missing.set(true);
            this.loading.set(false);
            return;
          }

          this.product.set(product);
          this.seoService.setItemMeta(product);
          this.analytics.track('product_view', { itemID: product.itemID });
          if (this.userExperienceConfig().recentlyViewed.enabled) {
            this.uxFacade.trackRecentlyViewed(product, this.userExperienceConfig().recentlyViewed.maxItems);
          }
          this.initVariantSelection(product);
          this.loadRelatedProducts(product);
          this.loadEngagement(product.itemID);
          this.loading.set(false);
        },
        error: () => {
          this.error.set('productDetails.error');
          this.loading.set(false);
        }
      });
  }

  selectColour(colour: string): void {
    this.selectedColour.set(colour);
    this.selectedOptions.update(state => ({ ...state, colour }));
    const sizes = this.availableSizes();
    if (sizes.length && this.selectedSize() && !sizes.includes(this.selectedSize()!)) {
      this.selectedSize.set(sizes[0]);
    }
  }

  selectSize(size: string): void {
    this.selectedSize.set(size);
    this.selectedOptions.update(state => ({ ...state, size }));
  }

  selectVariantOption(payload: { groupKey: string; value: string }): void {
    this.selectedOptions.update(state => ({ ...state, [payload.groupKey]: payload.value }));

    if (payload.groupKey === 'colour') {
      this.selectColour(payload.value);
      return;
    }

    if (payload.groupKey === 'size') {
      this.selectSize(payload.value);
    }
  }

  addToCart(): Promise<void> {
    const current = this.product();
    if (!current) return Promise.resolve();
    this.analytics.track('add_to_cart', { itemID: current.itemID, price: this.effectivePrice(), currency: this.effectiveCurrency() });
    return this.cartService.addItem(current.itemID, 1, {
      colour: this.selectedColour() ?? undefined,
      size: this.selectedSize() ?? undefined,
      price: this.effectivePrice(),
      currency: this.effectiveCurrency(),
    });
  }

  async buyNow(): Promise<void> {
    try {
      await this.addToCart();
    } catch {
      this.notifications.show(this.translate.t('common.errorDescription'), 'warning');
      return;
    }
    void this.router.navigate([`/${this.languageService.currentLanguage()}/cart`]);
  }

  toggleWishlist(): void {
    const current = this.product();
    if (!current) {
      return;
    }

    this.uxFacade.toggleWishlist(current);
  }

  toggleCompare(): void {
    const current = this.product();
    if (!current) {
      return;
    }

    if (this.uxFacade.isInCompare(current.itemID)) {
      this.uxFacade.removeFromCompare(current.itemID);
      return;
    }

    const maxItems = Math.max(1, this.userExperienceConfig().compare.maxItems);
    this.uxFacade.addToCompare(current, maxItems);
  }

  async shareProduct(): Promise<void> {
    const current = this.product();
    if (!current || typeof window === 'undefined') {
      return;
    }

    const url = `${window.location.origin}/${this.languageService.currentLanguage()}/product/${current.itemID}`;
    await this.shareService.shareProduct(current, url);
  }

  /**
   * Back-in-stock subscription. Tries the backend endpoint first (not built
   * yet - see BACKEND-API-REFERENCE.md §12); falls back to a local-only
   * record on any failure so the request isn't silently lost while the
   * backend catches up. Either way the shopper sees the same confirmation.
   */
  notifyMe(): void {
    const current = this.product();
    if (!current) {
      return;
    }

    const telegramUserId = this.authService.session()?.userId != null
      ? String(this.authService.session()!.userId)
      : null;

    this.apiService.subscribeToRestock(current.itemID, { telegramUserId }).subscribe({
      next: () => this.notifications.show(this.translate.t('productDetails.notifyMeConfirmed'), 'success'),
      error: () => {
        this.saveRestockSubscriptionLocally(current.itemID);
        this.notifications.show(this.translate.t('productDetails.notifyMeConfirmed'), 'success');
      }
    });
  }

  private saveRestockSubscriptionLocally(itemID: number): void {
    const existing = this.storage.getJSON<number[]>(RESTOCK_SUBSCRIPTIONS_KEY) ?? [];
    if (!existing.includes(itemID)) {
      this.storage.setJSON(RESTOCK_SUBSCRIPTIONS_KEY, [...existing, itemID]);
    }
  }

  addRelatedToCart(payload: { product: Product; event: Event }): void {
    payload.event.preventDefault();
    payload.event.stopPropagation();
    this.cartService.addItem(payload.product.itemID);
  }

  selectRelatedProduct(product: Product): void {
    this.router.navigate([`/${this.languageService.currentLanguage()}/product`, product.itemID]);
  }

  productTitle(product: Product): string {
    return getTranslatedField(product, 'name', this.languageService.currentLanguage());
  }

  productDescription(product: Product): string {
    return getTranslatedField(product, 'simpleDescription', this.languageService.currentLanguage());
  }

  retry(): void {
    const productId = Number(this.route.snapshot.paramMap.get('id'));
    this.loadProduct(productId);
  }

  loadReviews(page: number, append = false): void {
    const current = this.product();
    if (!current || this.productPageConfigState().reviews.enabled === false) {
      return;
    }

    this.reviewsLoading.set(true);
    this.productFacade.loadReviews(current.itemID, {
      page,
      pageSize: this.reviewsPageSize()
    })
      .pipe(takeUntilDestroyed(this.destroyRef))
      .subscribe({
        next: result => {
          if (append && this.reviewsMode() === 'load-more') {
            const previous = this.reviewsResult();
            const mergedItems = [...(previous?.items ?? []), ...result.items]
              .filter((item, index, source) => source.findIndex(entry => entry.id === item.id) === index);

            this.reviewsResult.set({
              ...result,
              items: mergedItems,
            });
          } else {
            this.reviewsResult.set(result);
          }
          this.reviewsLoading.set(false);
        },
        error: () => {
          this.reviewsResult.set({ items: [], total: 0, page, pageSize: this.reviewsPageSize() });
          this.reviewsLoading.set(false);
        }
      });
  }

  loadQuestions(page: number): void {
    const current = this.product();
    if (!current || this.productPageConfigState().questions.enabled === false) {
      return;
    }

    this.questionsLoading.set(true);
    this.productFacade.loadQuestions(current.itemID, {
      page,
      pageSize: this.questionsPageSize()
    })
      .pipe(takeUntilDestroyed(this.destroyRef))
      .subscribe({
        next: result => {
          this.questionsResult.set(result);
          this.questionsLoading.set(false);
        },
        error: () => {
          this.questionsResult.set({ items: [], total: 0, page, pageSize: this.questionsPageSize() });
          this.questionsLoading.set(false);
        }
      });
  }

  submitReview(input: SubmitReviewInput): void {
    const current = this.product();
    if (!current) {
      return;
    }

    this.reviewSubmitting.set(true);
    this.productFacade.submitReview(current.itemID, input)
      .pipe(takeUntilDestroyed(this.destroyRef))
      .subscribe({
        next: () => {
          this.reviewSubmitting.set(false);
          this.loadRating(current.itemID);
          this.loadReviews(1, false);
        },
        error: () => this.reviewSubmitting.set(false)
      });
  }

  submitQuestion(input: SubmitQuestionInput): void {
    const current = this.product();
    if (!current) {
      return;
    }

    this.questionSubmitting.set(true);
    this.productFacade.submitQuestion(current.itemID, input)
      .pipe(takeUntilDestroyed(this.destroyRef))
      .subscribe({
        next: () => {
          this.questionSubmitting.set(false);
          this.loadQuestions(1);
        },
        error: () => this.questionSubmitting.set(false)
      });
  }

  isSectionEnabled(key: ProductTabKey): boolean {
    return this.isTabEnabled(key);
  }

  private initVariantSelection(product: Product): void {
    const details = product.itemDetails;
    if (details?.length) {
      this.selectedColour.set(details[0].colour || details[0].color || null);
      this.selectedSize.set(details[0].size && details[0].size.toLowerCase() !== 'default' ? details[0].size : null);
      this.selectedOptions.set({
        colour: details[0].colour || details[0].color || '',
        size: details[0].size && details[0].size.toLowerCase() !== 'default' ? details[0].size : ''
      });
      return;
    }

    this.selectedColour.set(product.colour ?? null);
    this.selectedSize.set(product.size && product.size.toLowerCase() !== 'default' ? product.size : null);
    this.selectedOptions.set({
      colour: product.colour ?? '',
      size: product.size && product.size.toLowerCase() !== 'default' ? product.size : ''
    });
  }

  private loadRelatedProducts(product: Product): void {
    if (this.productPageConfigState().relatedProducts.enabled === false) {
      this.relatedProducts.set([]);
      this.relatedCollections.set([]);
      return;
    }

    if (product.relatedCollections?.length) {
      const language = this.languageService.currentLanguage();
      const requests = product.relatedCollections.map(collection =>
        forkJoin(
          (collection.products ?? [])
            .filter(productID => productID !== product.itemID)
            .map(productID => this.productFacade.getProduct(productID).pipe(catchError(() => of(null))))
        ).pipe(
          catchError(() => of([] as Array<Product | null>))
        )
      );

      forkJoin(requests)
        .pipe(takeUntilDestroyed(this.destroyRef))
        .subscribe(result => {
          const collections = result.map((products, index) => {
            const config = product.relatedCollections![index];
            return {
              id: config.id,
              title: config.titles?.[language] || config.title || this.translate.t('itemDetail.relatedProducts'),
              products: products.filter((item): item is Product => !!item)
            } as RelatedCollectionViewModel;
          }).filter(collection => collection.products.length > 0);

          this.relatedCollections.set(collections);
          this.relatedProducts.set(collections[0]?.products ?? []);
        });
      return;
    }

    this.productFacade.getRelatedProducts({
      productID: product.itemID,
      categoryID: product.categoryID,
      count: 8,
    }).pipe(takeUntilDestroyed(this.destroyRef))
      .subscribe({
        next: result => {
          const products = result.items.filter(item => item.itemID !== product.itemID);
          this.relatedProducts.set(products);
          this.relatedCollections.set([{
            id: 'default-related',
            title: this.translate.t('itemDetail.relatedProducts'),
            products
          }]);
        },
        error: () => {
          this.relatedProducts.set([]);
          this.relatedCollections.set([]);
        },
      });
  }

  private loadEngagement(productID: number): void {
    if (this.productPageConfigState().rating.enabled !== false) {
      this.loadRating(productID);
    }

    if (this.productPageConfigState().reviews.enabled !== false) {
      this.loadReviews(1, false);
    }

    if (this.productPageConfigState().questions.enabled !== false) {
      this.loadQuestions(1);
    }
  }

  private loadRating(productID: number): void {
    this.ratingLoading.set(true);
    this.productFacade.loadRating(productID)
      .pipe(takeUntilDestroyed(this.destroyRef))
      .subscribe({
        next: summary => {
          this.ratingSummary.set(summary);
          this.ratingLoading.set(false);
        },
        error: () => {
          this.ratingSummary.set({
            average: 0,
            totalReviews: 0,
            distribution: [5, 4, 3, 2, 1].map(stars => ({ stars: stars as 1 | 2 | 3 | 4 | 5, count: 0, share: 0 }))
          });
          this.ratingLoading.set(false);
        }
      });
  }

  private ensureInitialActiveTab(): void {
    const tabs = this.tabs();
    if (tabs.length > 0) {
      this.activeTab.set(tabs[0].key);
    }
  }

  private isTabEnabled(key: ProductTabKey): boolean {
    const config = this.productPageConfigState();

    switch (key) {
      case 'reviews':
        return config.reviews.enabled !== false;
      case 'questions':
        return config.questions.enabled !== false;
      case 'delivery':
        return true;
      case 'description':
      case 'specifications':
      case 'warranty':
      default:
        return true;
    }
  }

  private getTabLabel(key: ProductTabKey): string {
    switch (key) {
      case 'description':
        return this.translate.t('itemDetail.description');
      case 'specifications':
        return this.translate.t('itemDetail.specifications');
      case 'reviews':
        return this.translate.t('itemDetail.reviews');
      case 'questions':
        return this.translate.t('itemDetail.qna');
      case 'delivery':
        return this.translate.t('cart.deliveryLabel');
      case 'warranty':
        return this.translate.t('footer.guarantee');
      default:
        return key;
    }
  }

  private resolveProductPageConfig(): Required<ProductPageConfig> {
    const bootstrapConfig = (this.configService.getBootstrapSnapshot() as any)?.productPage ?? {};

    return {
      rating: {
        ...DEFAULT_PRODUCT_PAGE_CONFIG.rating,
        ...(bootstrapConfig.rating ?? {})
      },
      reviews: {
        ...DEFAULT_PRODUCT_PAGE_CONFIG.reviews,
        ...(bootstrapConfig.reviews ?? {})
      },
      questions: {
        ...DEFAULT_PRODUCT_PAGE_CONFIG.questions,
        ...(bootstrapConfig.questions ?? {})
      },
      tabs: {
        ...DEFAULT_PRODUCT_PAGE_CONFIG.tabs,
        ...(bootstrapConfig.tabs ?? {}),
        items: Array.isArray(bootstrapConfig.tabs?.items) && bootstrapConfig.tabs.items.length > 0
          ? bootstrapConfig.tabs.items
          : DEFAULT_PRODUCT_PAGE_CONFIG.tabs.items
      },
      relatedProducts: {
        ...DEFAULT_PRODUCT_PAGE_CONFIG.relatedProducts,
        ...(bootstrapConfig.relatedProducts ?? {})
      },
      actions: {
        ...DEFAULT_PRODUCT_PAGE_CONFIG.actions,
        ...(bootstrapConfig.actions ?? {})
      }
    };
  }

  private resolveUserExperienceConfig() {
    const raw = (this.configService.getBootstrapSnapshot() as any)?.userExperience ?? {};

    return {
      ...DEFAULT_USER_EXPERIENCE_CONFIG,
      ...raw,
      recentlyViewed: {
        ...DEFAULT_USER_EXPERIENCE_CONFIG.recentlyViewed,
        ...(raw.recentlyViewed ?? {}),
        maxItems: Number.isFinite(raw.recentlyViewed?.maxItems)
          ? Math.max(1, Number(raw.recentlyViewed.maxItems))
          : DEFAULT_USER_EXPERIENCE_CONFIG.recentlyViewed.maxItems
      }
    };
  }
}
