import {
  ChangeDetectionStrategy,
  Component,
  ElementRef,
  OnDestroy,
  OnInit,
  computed,
  effect,
  inject,
  signal,
  viewChild,
  PLATFORM_ID
} from '@angular/core';
import { CommonModule, isPlatformBrowser } from '@angular/common';
import { HttpErrorResponse } from '@angular/common/http';
import { ActivatedRoute, Router, RouterModule } from '@angular/router';
import { Subscription } from 'rxjs';

import { CatalogService } from '../../../../core/services/catalog/catalog.service';
import { ToastService } from '../../../../core/services/toast.service';
import { CartService } from '../../../../core/services/cart/cart.service';
import {
  ProductAttribute,
  ProductAttributeOption,
  ProductDetail,
  ProductVariant,
  ProductVariantMap
} from '../../../../core/services/catalog/catalog.interface';
import { ProductCarouselComponent } from '../../components/product-carousel/product-carousel.component';
import { ButtonComponent } from '../../../../shared/components/button/button.component';
import { ProductAttributeSelectorComponent } from '../../components/product-attribute-selector/product-attribute-selector.component';
import { QuantitySelectorComponent } from '../../../../shared/components/quantity-selector/quantity-selector.component';

@Component({
  selector: 'app-product-detail-page',
  standalone: true,
  imports: [
    CommonModule,
    RouterModule,
    ProductCarouselComponent,
    ButtonComponent,
    ProductAttributeSelectorComponent,
    QuantitySelectorComponent
  ],
  templateUrl: './product-detail-page.component.html',
  styleUrl: './product-detail-page.component.scss',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class ProductDetailPageComponent implements OnInit, OnDestroy {
  private readonly route = inject(ActivatedRoute);
  private readonly router = inject(Router);
  private readonly catalogService = inject(CatalogService);
  private readonly toastService = inject(ToastService);
  private readonly cartService = inject(CartService);
  private readonly attributeSelector = viewChild(ProductAttributeSelectorComponent);
  private readonly carouselHost = viewChild<ElementRef<HTMLElement>>('carouselHost');
  private readonly descriptionBody = viewChild<ElementRef<HTMLElement>>('descriptionBody');
  private readonly platformId = inject(PLATFORM_ID);
  private readonly isBrowser = isPlatformBrowser(this.platformId);

  private routeSub: Subscription | null = null;
  private productSub: Subscription | null = null;
  private carouselResizeObserver: ResizeObserver | null = null;
  private observedCarouselPreview: HTMLElement | null = null;
  private measurementTimer: ReturnType<typeof setTimeout> | null = null;

  protected readonly product = signal<ProductDetail | null>(null);
  protected readonly carouselImages = computed(() => {
    const prod = this.product();
    if (!prod) return [];
    if (prod.variant?.images && prod.variant.images.length > 0) {
      return prod.variant.images;
    }
    if (prod.images && prod.images.length > 0) {
      return prod.images;
    }
    return [];
  });
  protected readonly loading = signal(false);
  protected readonly variantLoading = signal(false);
  protected readonly addingToCart = signal(false);
  protected readonly error = signal<string | null>(null);
  protected readonly selectedVariant = signal<ProductVariantMap | null>(null);
  protected readonly quantity = signal(1);
  protected readonly descriptionExpanded = signal(false);
  protected readonly descriptionMaxHeight = signal(0);
  protected readonly descriptionHasOverflow = signal(false);
  protected readonly renderableAttributes = computed(() =>
    (this.product()?.attributes ?? []).filter((attribute) => attribute.options.length > 0)
  );
  protected readonly hasRenderableAttributes = computed(
    () => this.renderableAttributes().length > 0
  );
  protected readonly oldPrice = computed<string | null>(() => null);
  protected readonly showDescriptionToggle = computed(
    () => this.descriptionExpanded() || this.descriptionHasOverflow()
  );

  constructor() {
    effect(() => {
      this.carouselHost();
      this.descriptionBody();
      this.product();
      this.descriptionExpanded();

      if (this.isBrowser) {
        queueMicrotask(() => {
          this.bindCarouselResizeObserver();
          this.refreshMeasurements();
        });
      }
    });
  }

  ngOnInit(): void {
    this.routeSub = this.route.paramMap.subscribe((params) => {
      const id = this.parseIntegerParam(params.get('id'));
      if (id === null) {
        this.error.set('ID de producto inválido');
        return;
      }

      this.loadProduct(id);
    });
  }

  ngOnDestroy(): void {
    this.routeSub?.unsubscribe();
    this.productSub?.unsubscribe();
    this.carouselResizeObserver?.disconnect();
    this.clearMeasurementTimer();
  }

  private loadProduct(id: number): void {
    this.loading.set(true);
    this.error.set(null);
    this.product.set(null);

    this.productSub?.unsubscribe();
    this.productSub = this.catalogService.getProducto(id).subscribe({
      next: (prod) => {
        this.product.set(prod);
        const matchingVariant = prod.variants_map.find((v) => v.variant_id === prod.variant?.id) || null;
        this.selectedVariant.set(matchingVariant);
        this.quantity.set(1);
        this.descriptionExpanded.set(false);
        this.descriptionHasOverflow.set(false);
        this.loading.set(false);
      },
      error: () => {
        this.error.set('No pudimos cargar los detalles del producto.');
        this.loading.set(false);
      }
    });
  }

  private loadProductVariant(productId: number, variantId: number): void {
    this.variantLoading.set(true);

    this.productSub?.unsubscribe();
    this.productSub = this.catalogService.getProducto(productId, variantId).subscribe({
      next: (prod) => {
        this.product.set(prod);
        const matchingVariant = prod.variants_map.find((v) => v.variant_id === prod.variant?.id) || null;
        this.selectedVariant.set(matchingVariant);
        this.variantLoading.set(false);
      },
      error: (err: HttpErrorResponse) => {
        const errorMessage = err.error?.message || 'No pudimos cargar la variante seleccionada.';
        this.toastService.danger(errorMessage);
        this.variantLoading.set(false);

        this.product.update((currentProduct) => {
          if (!currentProduct) return null;
          const updatedVariantsMap = currentProduct.variants_map.map((v) => {
            if (v.variant_id === variantId) {
              return { ...v, cantidad_maxima: 0 };
            }
            return v;
          });
          return {
            ...currentProduct,
            variants_map: updatedVariantsMap
          };
        });

        this.attributeSelector()?.reset();
      }
    });
  }

  protected goBack(): void {
    this.router.navigate(['/']);
  }

  protected getFormattedPrice(priceStr: string | undefined): string {
    if (!priceStr) return '$0';
    const parsed = Number(priceStr);
    const value = Number.isFinite(parsed) ? parsed : 0;
    const rounded = Math.round(value);
    const parts = rounded.toString().split('.');
    parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, '.');
    return `$${parts.join(',')}`;
  }

  protected onVariantChange(variant: ProductVariantMap | null): void {
    if (this.selectedVariant()?.variant_id === variant?.variant_id) {
      return;
    }

    this.selectedVariant.set(variant);
    if (variant && this.quantity() > variant.cantidad_maxima) {
      this.quantity.set(Math.max(1, variant.cantidad_maxima));
    }

    const currentProduct = this.product();
    if (variant && currentProduct && currentProduct.variant?.id !== variant.variant_id) {
      this.loadProductVariant(currentProduct.id, variant.variant_id);
    }
  }



  protected addToCart(): void {
    const variant = this.selectedVariant();
    if (!variant) {
      this.toastService.danger('Por favor, selecciona una variante.');
      return;
    }

    this.addingToCart.set(true);
    this.cartService.addItem(variant.variant_id, this.quantity()).subscribe({
      next: (res) => {
        const msg = res.message || 'Producto agregado al carrito';
        this.toastService.success(msg);
        this.addingToCart.set(false);
      },
      error: (err: HttpErrorResponse) => {
        const errorMessage = err.error?.message || 'No se pudo agregar el producto al carrito.';
        this.toastService.danger(errorMessage);
        this.addingToCart.set(false);
      }
    });
  }

  protected toggleDescription(): void {
    this.descriptionExpanded.update((current) => !current);
  }

  private parseIntegerParam(value: string | null): number | null {
    if (!value) {
      return null;
    }

    const parsed = Number(value);
    return Number.isInteger(parsed) ? parsed : null;
  }

  private bindCarouselResizeObserver(): void {
    const previewElement = this.getCarouselPreviewElement();

    if (!previewElement || previewElement === this.observedCarouselPreview) {
      return;
    }

    this.carouselResizeObserver?.disconnect();
    this.observedCarouselPreview = previewElement;

    if (typeof ResizeObserver === 'undefined') {
      this.updateDescriptionMaxHeight();
      return;
    }

    this.carouselResizeObserver = new ResizeObserver(() => {
      this.scheduleMeasurement();
    });
    this.carouselResizeObserver.observe(previewElement);
    this.updateDescriptionMaxHeight();
  }

  private scheduleMeasurement(): void {
    this.clearMeasurementTimer();
    this.measurementTimer = setTimeout(() => {
      this.measurementTimer = null;
      this.refreshMeasurements();
    }, 0);
  }

  private clearMeasurementTimer(): void {
    if (this.measurementTimer) {
      clearTimeout(this.measurementTimer);
      this.measurementTimer = null;
    }
  }

  private refreshMeasurements(): void {
    this.updateDescriptionMaxHeight();
    this.updateDescriptionOverflow();
  }

  private updateDescriptionMaxHeight(): void {
    const previewElement = this.getCarouselPreviewElement();
    const nextHeight = previewElement?.getBoundingClientRect().height ?? 0;

    if (nextHeight > 0) {
      this.descriptionMaxHeight.set(nextHeight);
    }
  }

  private updateDescriptionOverflow(): void {
    const descriptionElement = this.descriptionBody()?.nativeElement;

    if (!descriptionElement || this.descriptionExpanded()) {
      return;
    }

    this.descriptionHasOverflow.set(
      descriptionElement.scrollHeight - descriptionElement.clientHeight > 1
    );
  }

  private getCarouselPreviewElement(): HTMLElement | null {
    return (
      this.carouselHost()?.nativeElement.querySelector<HTMLElement>('.product-carousel__main') ??
      null
    );
  }
}
