import {
  ChangeDetectionStrategy,
  Component,
  computed,
  effect,
  input,
  model,
  output,
  signal,
  untracked,
} from '@angular/core';
import { FormsModule } from '@angular/forms';

import { ButtonComponent } from '../button/button.component';
import { QuantitySelectorComponent } from '../quantity-selector/quantity-selector.component';

export interface VerticalCartVariant {
  id: number;
  values: Record<string, string>;
}

interface VariantSelector {
  key: string;
  label: string;
  options: string[];
}

@Component({
  selector: 'app-product-vertical-with-cart-card',
  imports: [ButtonComponent, FormsModule, QuantitySelectorComponent],
  templateUrl: './product-vertical-with-cart-card.component.html',
  styleUrl: './product-vertical-with-cart-card.component.scss',
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ProductVerticalWithCartCardComponent {
  readonly title = input<string>('');
  readonly description = input<string>('');
  readonly price = input<number>(0);
  readonly variants = input<VerticalCartVariant[]>([]);

  readonly quantity = model<number>(1);
  readonly selectedVariant = model<number | null>(null);

  readonly buy = output<{ quantity: number; variant: number | null }>();
  readonly addToCart = output<{ quantity: number; variant: number | null }>();

  protected readonly selectedValues = signal<Record<string, string>>({});

  protected readonly formattedPrice = computed(() => this.formatCurrency(this.price()));
  protected readonly variantSelectors = computed<VariantSelector[]>(() => {
    const variants = this.variants();
    const keys = Array.from(new Set(variants.flatMap((variant) => Object.keys(variant.values))));

    return keys.map((key) => ({
      key,
      label: this.formatVariantLabel(key),
      options: Array.from(
        new Set(
          variants
            .map((variant) => variant.values[key])
            .filter((value): value is string => Boolean(value)),
        ),
      ),
    }));
  });

  protected readonly hasVariants = computed(() => this.variantSelectors().length > 0);
  protected readonly hasMultipleVariantSelectors = computed(
    () => this.variantSelectors().length > 1,
  );

  constructor() {
    effect(() => {
      const variants = this.variants();

      untracked(() => {
        if (variants.length === 0) {
          this.selectedValues.set({});
          this.selectedVariant.set(null);
          return;
        }

        const selected =
          variants.find((variant) => variant.id === this.selectedVariant()) ?? variants[0];
        this.selectedValues.set({ ...selected.values });
        this.selectedVariant.set(selected.id);
      });
    });
  }

  protected onVariantValueChange(key: string, value: string): void {
    const values = { ...this.selectedValues(), [key]: value };
    const selectors = this.variantSelectors();
    const matchingVariant = this.variants().find((variant) =>
      selectors.every((selector) => variant.values[selector.key] === values[selector.key]),
    );

    this.selectedValues.set(values);
    this.selectedVariant.set(matchingVariant?.id ?? null);
  }

  protected onAddToCart(): void {
    this.addToCart.emit({ quantity: this.quantity(), variant: this.selectedVariant() });
  }

  protected onBuy(): void {
    this.buy.emit({ quantity: this.quantity(), variant: this.selectedVariant() });
  }

  private formatVariantLabel(key: string): string {
    const label = key.replace(/[_-]+/g, ' ');
    return label.charAt(0).toUpperCase() + label.slice(1);
  }

  private formatCurrency(value: number): string {
    const rounded = Math.round(value);
    const parts = rounded.toString().split('.');
    parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, '.');

    return `$ ${parts.join(',')}`;
  }
}
