import { describe, it, expect, beforeEach, vi } from 'vitest';
import { signal } from '@angular/core';
import { HttpErrorResponse } from '@angular/common/http';
import { TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import {
  ActivatedRoute,
  convertToParamMap,
  ParamMap,
  provideRouter,
  Router,
  UrlSerializer,
} from '@angular/router';

import { BehaviorSubject, of } from 'rxjs';

import { Tenant } from '../../services/tenant.interface';
import { TenantService } from '../../services/tenant.service';
import { CartService } from '../../services/cart/cart.service';
import { Cart } from '../../services/cart/cart.interface';
import { ToastService } from '../../services/toast.service';
import { AuthService } from '../../services/auth/auth.service';
import { AuthUser } from '../../services/auth/auth.interfaces';
import { StoreLayoutComponent } from './store-layout.component';
import { StoreHeaderComponent } from './store-header/store-header.component';
import { CheckoutService } from '../../services/checkout.service';
import { CheckoutCountdownService } from '../../services/checkout-countdown.service';
import { TenantUrlSerializer } from '../../services/tenant-url.serializer';

const tenant: Tenant = {
  id: 1,
  codigo: 'test',
  nombre: 'Test Tenant',
  dominio: 'localhost',
  address: 'Calle Test 123, Rosario',
  phone: '+54 341 555 1234',
  primary_color: '#6376F3',
  secondary_color: '#A0A0A0',
  danger_color: '#FF8888',
  success_color: '#198754',
  header_bg_color: '#313131',
  footer_bg_color: '#313131',
  header_logo: 'https://example.com/header.png',
  footer_logo: 'https://example.com/footer.png',
  header_bg_image: 'https://example.com/header-background.png',
  footer_bg_image: 'https://example.com/footer-background.png',
  cart_editing_policy: {
    code: 'full',
    allow_modify: true,
    allow_delete: true,
    allow_update_quantity: true,
    allow_update_variant: true,
  },
  categories: [],
  menues: [
    {
      id: 4,
      code: 'account',
      label: 'Mi cuenta',
      parent_menu_code: null,
      content_type: 'dynamic',
      route: '/mi-cuenta',
      submenues: [
        {
          id: 5,
          code: 'account.profile',
          label: 'Datos personales',
          parent_menu_code: 'account',
          content_type: 'dynamic',
          route: '/mi-cuenta/datos-personales',
          submenues: [],
        },
        {
          id: 6,
          code: 'account.purchases',
          label: 'Mis compras',
          parent_menu_code: 'account',
          content_type: 'dynamic',
          route: '/mi-cuenta/compras',
          submenues: [],
        },
        {
          id: 7,
          code: 'account.tickets',
          label: 'Mis tickets',
          parent_menu_code: 'account',
          content_type: 'dynamic',
          route: '/mi-cuenta/tickets',
          submenues: [],
        },
      ],
    },
    {
      id: 1,
      code: 'help',
      label: 'Ayuda',
      parent_menu_code: null,
      content_type: 'dynamic',
      route: '/ayuda',
      submenues: [
        {
          id: 2,
          code: 'help.contact',
          label: 'Contacto',
          parent_menu_code: 'help',
          content_type: 'static',
          route: '/ayuda/contacto',
          submenues: [],
        },
        {
          id: 3,
          code: 'help.faq',
          label: 'Preguntas frecuentes',
          parent_menu_code: 'help',
          content_type: 'static',
          route: '/ayuda/preguntas-frecuentes',
          submenues: [],
        },
      ],
    },
  ],
  social_media: [
    {
      code: 'instagram',
      icon: 'instagram',
      name: 'Instagram',
      url: 'https://instagram.com/test',
    },
    {
      code: 'whatsapp',
      icon: 'whatsapp',
      name: 'WhatsApp',
      url: 'https://wa.me/5493410000000',
    },
    {
      code: 'facebook',
      icon: 'facebook',
      name: 'Facebook',
      url: 'https://facebook.com/test',
    },
    {
      code: 'linkedin',
      icon: 'fa-brands fa-linkedin-in',
      name: 'LinkedIn',
      url: 'https://linkedin.com/company/test',
    },
  ],
};

describe('StoreLayoutComponent', () => {
  let tenantState = signal<Tenant | null>(tenant);
  let cartState = signal<Cart | null>(null);
  let authUserState = signal<AuthUser | null>(null);
  let checkoutRemainingSecondsState = signal<number | null>(null);
  let checkoutServiceStub: { startCheckout: ReturnType<typeof vi.fn> };
  let queryParamMapState: BehaviorSubject<ParamMap>;

  beforeEach(async () => {
    tenantState = signal<Tenant | null>(tenant);
    cartState = signal<Cart | null>(null);
    authUserState = signal<AuthUser | null>(null);
    checkoutRemainingSecondsState = signal<number | null>(null);
    queryParamMapState = new BehaviorSubject(convertToParamMap({}));
    const isAuthenticatedState = signal(false);
    checkoutServiceStub = {
      startCheckout: vi.fn().mockResolvedValue({ id: 55 }),
    };

    await TestBed.configureTestingModule({
      imports: [StoreLayoutComponent],
      providers: [
        provideRouter([]),
        { provide: UrlSerializer, useClass: TenantUrlSerializer },
        {
          provide: ActivatedRoute,
          useValue: { queryParamMap: queryParamMapState.asObservable() },
        },
        {
          provide: TenantService,
          useValue: {
            tenant: tenantState.asReadonly(),
            status: signal<'ready'>('ready').asReadonly(),
            getTenant: () => tenantState(),
            bootstrap: vi.fn().mockResolvedValue(undefined),
          },
        },
        {
          provide: CartService,
          useValue: {
            cart: cartState.asReadonly(),
            loadCart: () => of({ id: 1, items: [], subtotal: '0' }),
            updateItemQuantity: vi
              .fn()
              .mockReturnValue(of({ data: { id: 1, items: [], subtotal: '0' } })),
            removeItem: vi.fn().mockReturnValue(of({ data: { id: 1, items: [], subtotal: '0' } })),
            clearCart: vi.fn(() => cartState.set(null)),
          },
        },
        {
          provide: ToastService,
          useValue: {
            show: vi.fn(),
            info: vi.fn(),
            danger: vi.fn(),
            success: vi.fn(),
            dismiss: vi.fn(),
          },
        },
        {
          provide: AuthService,
          useValue: {
            user: authUserState,
            isAuthenticated: isAuthenticatedState,
            logout: vi.fn().mockReturnValue(of(void 0)),
          },
        },
        {
          provide: CheckoutService,
          useValue: checkoutServiceStub,
        },
        {
          provide: CheckoutCountdownService,
          useValue: {
            remainingSeconds: checkoutRemainingSecondsState.asReadonly(),
          },
        },
      ],
    }).compileComponents();
  });

  it('renders the main layout sections', () => {
    const fixture = TestBed.createComponent(StoreLayoutComponent);
    fixture.detectChanges();

    const compiled = fixture.nativeElement as HTMLElement;

    expect(compiled.querySelector('app-store-header .store-layout__header')).not.toBeNull();
    expect(compiled.querySelector('.store-layout__category-trigger')).not.toBeNull();
    expect(compiled.querySelector('router-outlet')).not.toBeNull();
    expect(compiled.querySelector('app-store-footer .store-layout__footer')).not.toBeNull();
  });

  it('opens the cart when requested through the openCart query parameter', () => {
    const fixture = TestBed.createComponent(StoreLayoutComponent);
    fixture.detectChanges();

    expect((fixture.componentInstance as any).isCartOpen()).toBe(false);

    queryParamMapState.next(convertToParamMap({ openCart: 'true' }));
    fixture.detectChanges();

    expect((fixture.componentInstance as any).isCartOpen()).toBe(true);
    expect((fixture.nativeElement as HTMLElement).querySelector('app-cart')).not.toBeNull();
  });

  it('disables the cart icon and prevents opening the popup during checkout with a tenant base path', () => {
    tenantState.set({ ...tenant, base_path: 'fiesta' });
    const router = TestBed.inject(Router);
    vi.spyOn(router, 'url', 'get').mockReturnValue('/fiesta/checkout/25');

    const fixture = TestBed.createComponent(StoreLayoutComponent);
    fixture.detectChanges();

    const element = fixture.nativeElement as HTMLElement;
    const cartButton = element.querySelector<HTMLButtonElement>('app-cart-icon button');
    const header = fixture.debugElement.query(By.directive(StoreHeaderComponent));

    expect(cartButton?.disabled).toBe(true);
    expect(cartButton?.getAttribute('aria-label')).toBe(
      'Carrito no disponible durante el checkout',
    );
    expect(element.querySelector('[data-testid="cart-badge"]')).toBeNull();

    header.componentInstance.cartClick.emit();
    queryParamMapState.next(convertToParamMap({ openCart: 'true' }));
    fixture.detectChanges();

    expect((fixture.componentInstance as any).isCartOpen()).toBe(false);
    expect(element.querySelector('app-cart')).toBeNull();
    expect(element.querySelector('.store-layout__cart-overlay')).toBeNull();
  });

  it('shows the synchronized countdown in the header whenever one is active', () => {
    checkoutRemainingSecondsState.set(587);

    const fixture = TestBed.createComponent(StoreLayoutComponent);
    fixture.detectChanges();

    const element = fixture.nativeElement as HTMLElement;

    expect(element.querySelector('.store-layout__checkout-timer-label')?.textContent).toContain(
      'Tiempo restante de compra:',
    );
    expect(element.querySelector('.store-layout__checkout-timer-value')?.textContent?.trim()).toBe(
      '09:47',
    );
  });

  it('hides the configured header elements when the tenant disables them', () => {
    tenantState.set({
      ...tenant,
      categories: [{ id: 1, nombre: 'Remeras', subcategories: [] }],
      display_categories: false,
      display_seach_bar: false,
      display_cart: false,
    });

    const fixture = TestBed.createComponent(StoreLayoutComponent);
    fixture.detectChanges();

    const compiled = fixture.nativeElement as HTMLElement;

    expect(compiled.querySelector('#store-search-input')).toBeNull();
    expect(compiled.querySelector('.store-layout__category-trigger')).toBeNull();
    expect(compiled.querySelector('app-cart-icon')).toBeNull();

    (fixture.componentInstance as any).isCartOpen.set(true);
    fixture.detectChanges();

    expect(compiled.querySelector('app-cart')).toBeNull();
    expect(compiled.querySelector('.store-layout__cart-overlay')).toBeNull();

    const header = fixture.debugElement.query(By.directive(StoreHeaderComponent));
    (header.componentInstance as any).toggleMobileMenu();
    fixture.detectChanges();

    expect(compiled.querySelectorAll('.store-layout__mobile-dropdown-item')).toHaveLength(1);
  });

  it('renders the tenant branding and action icons', () => {
    const fixture = TestBed.createComponent(StoreLayoutComponent);
    fixture.detectChanges();

    const compiled = fixture.nativeElement as HTMLElement;

    expect(compiled.querySelector('[data-testid="store-header-brand-slot"]')).not.toBeNull();
    expect(compiled.querySelector('[data-testid="store-footer-brand-slot"]')).not.toBeNull();
    expect(
      compiled.querySelector(
        `app-store-header img.store-layout__brand-logo[src="${tenant.header_logo}"]`,
      ),
    ).not.toBeNull();
    expect(
      compiled.querySelector(
        `app-store-footer img.store-layout__brand-logo[src="${tenant.footer_logo}"]`,
      ),
    ).not.toBeNull();
    expect(
      (compiled.querySelector('.store-layout__header') as HTMLElement).style.backgroundImage,
    ).toContain(tenant.header_bg_image!);
    expect(
      (compiled.querySelector('.store-layout__footer') as HTMLElement).style.backgroundImage,
    ).toContain(tenant.footer_bg_image!);
    expect(compiled.querySelector('.fa-cart-shopping')).not.toBeNull();
    expect(compiled.querySelector('.fa-circle-user')).not.toBeNull();
    expect(compiled.querySelector('.fa-instagram')).not.toBeNull();
    expect(compiled.querySelector('.fa-whatsapp')).not.toBeNull();
    expect(compiled.querySelector('.fa-facebook')).not.toBeNull();
    expect(compiled.querySelector('.fa-linkedin-in')).not.toBeNull();
    expect(compiled.querySelector('.store-layout__contact-details')?.textContent).toContain(
      tenant.address,
    );
    expect(compiled.querySelector('.store-layout__contact-details')?.textContent).toContain(
      tenant.phone,
    );
  });

  it('navigates to search results when the search button is clicked', () => {
    const router = TestBed.inject(Router);
    vi.spyOn(router, 'navigate');
    const fixture = TestBed.createComponent(StoreLayoutComponent);
    fixture.detectChanges();

    const header = fixture.debugElement.query(By.directive(StoreHeaderComponent));
    const searchButton = header.query(By.css('.store-layout__search-button'));

    (header.componentInstance as any).searchControl.setValue('  zapatillas  ');
    searchButton.triggerEventHandler('click');
    fixture.detectChanges();

    expect(router.navigate).toHaveBeenCalledWith(['/buscar'], {
      queryParams: { q: 'zapatillas', page: 1 },
    });
  });

  it('prevents the native submit and searches when Enter is pressed', () => {
    const router = TestBed.inject(Router);
    vi.spyOn(router, 'navigate');
    const fixture = TestBed.createComponent(StoreLayoutComponent);
    fixture.detectChanges();

    const header = fixture.debugElement.query(By.directive(StoreHeaderComponent));
    const input = header.query(By.css('#store-search-input'));
    const keyboardEvent = {
      preventDefault: vi.fn(),
    };

    (header.componentInstance as any).searchControl.setValue('remera');
    input.triggerEventHandler('keydown.enter', keyboardEvent);

    expect(keyboardEvent.preventDefault).toHaveBeenCalled();
    expect(router.navigate).toHaveBeenCalledWith(['/buscar'], {
      queryParams: { q: 'remera', page: 1 },
    });
  });

  it('requires at least three characters to search', () => {
    const router = TestBed.inject(Router);
    vi.spyOn(router, 'navigate');
    const fixture = TestBed.createComponent(StoreLayoutComponent);
    fixture.detectChanges();

    const header = fixture.debugElement.query(By.directive(StoreHeaderComponent));
    const input = header.query(By.css('#store-search-input'));
    const searchButton = header.query(By.css('.store-layout__search-button'));

    expect(input.nativeElement.getAttribute('minlength')).toBe('3');

    (header.componentInstance as any).searchControl.setValue('ab');
    searchButton.triggerEventHandler('click');
    fixture.detectChanges();

    expect(router.navigate).not.toHaveBeenCalled();
    expect((fixture.nativeElement as HTMLElement).textContent).toContain(
      'Ingresá al menos 3 caracteres para buscar.',
    );
    expect(input.nativeElement.getAttribute('aria-invalid')).toBe('true');
  });

  it('renders the primary tickets action when the tenant has the tickets menu', () => {
    const router = TestBed.inject(Router);
    vi.spyOn(router, 'navigate');
    const configuredTicketsLabel = 'Entradas digitales';
    tenantState.set({
      ...tenant,
      menues: tenant.menues?.map((menu) =>
        menu.code === 'account'
          ? {
              ...menu,
              submenues: menu.submenues.map((submenu) =>
                submenu.code === 'account.tickets'
                  ? { ...submenu, label: configuredTicketsLabel }
                  : submenu,
              ),
            }
          : menu,
      ),
    });

    const fixture = TestBed.createComponent(StoreLayoutComponent);
    fixture.detectChanges();

    const ticketsAction = (fixture.nativeElement as HTMLElement).querySelector<HTMLElement>(
      'app-button[data-testid="store-header-tickets"]',
    );
    const ticketsButton = ticketsAction?.querySelector('button');

    expect(ticketsAction).not.toBeNull();
    expect(ticketsButton).not.toBeNull();
    expect(ticketsButton?.textContent?.trim()).toBe(configuredTicketsLabel);
    expect(ticketsButton?.classList).toContain('btn-primary');

    ticketsButton?.click();

    expect(router.navigate).toHaveBeenCalledWith(['/mi-cuenta/tickets']);
  });

  it('does not render the tickets action when the tenant lacks the tickets menu', () => {
    tenantState.set({
      ...tenant,
      menues: tenant.menues?.map((menu) =>
        menu.code === 'account'
          ? {
              ...menu,
              submenues: menu.submenues.filter((submenu) => submenu.code !== 'account.tickets'),
            }
          : menu,
      ),
    });

    const fixture = TestBed.createComponent(StoreLayoutComponent);
    fixture.detectChanges();

    expect(
      (fixture.nativeElement as HTMLElement).querySelector('[data-testid="store-header-tickets"]'),
    ).toBeNull();
  });

  it('redirects to /login when user icon is clicked and user is not logged in', () => {
    const authService = TestBed.inject(AuthService);
    const router = TestBed.inject(Router);
    vi.spyOn(router, 'navigate');

    (authService.isAuthenticated as any).set(false);

    const fixture = TestBed.createComponent(StoreLayoutComponent);
    fixture.detectChanges();

    const compiled = fixture.nativeElement as HTMLElement;
    const userButton = compiled.querySelector(
      'app-icon-button[variant="user"] button',
    ) as HTMLButtonElement;
    expect(userButton).not.toBeNull();
    userButton.click();
    fixture.detectChanges();

    expect(compiled.querySelector('app-user-dropdown')).toBeNull();
    expect(router.navigate).toHaveBeenCalledWith(['/login']);
  });

  it('opens authenticated user dropdown without redirecting on icon click', () => {
    const authService = TestBed.inject(AuthService);
    const router = TestBed.inject(Router);
    vi.spyOn(router, 'navigate');

    (authService.isAuthenticated as any).set(true);
    (authService.user as any).set({
      id: 1,
      nombre_apellido: 'Ada Lovelace',
      email: 'ada@example.com',
    });

    const fixture = TestBed.createComponent(StoreLayoutComponent);
    fixture.detectChanges();

    const compiled = fixture.nativeElement as HTMLElement;
    const userButton = compiled.querySelector(
      'app-icon-button[variant="user"] button',
    ) as HTMLButtonElement;
    expect(userButton).not.toBeNull();
    userButton.click();
    fixture.detectChanges();

    expect(compiled.querySelector('app-user-dropdown')).not.toBeNull();
    expect(compiled.textContent).toContain('Ada Lovelace');
    expect(compiled.querySelector('[data-testid="user-dropdown-account"]')).not.toBeNull();
    expect(
      compiled.querySelector('[data-testid="user-dropdown-account.purchases"]'),
    ).not.toBeNull();
    expect(compiled.querySelector('[data-testid="user-dropdown-account.tickets"]')).toBeNull();
    expect(router.navigate).not.toHaveBeenCalled();
  });

  it('logs out from the authenticated user dropdown, clears the cart and returns home', () => {
    const authService = TestBed.inject(AuthService);
    const cartService = TestBed.inject(CartService);
    const router = TestBed.inject(Router);
    vi.spyOn(router, 'navigate');

    (authService.isAuthenticated as any).set(true);
    (authService.user as any).set({
      id: 1,
      nombre_apellido: 'Ada Lovelace',
      email: 'ada@example.com',
    });

    const fixture = TestBed.createComponent(StoreLayoutComponent);
    fixture.detectChanges();

    const compiled = fixture.nativeElement as HTMLElement;
    const userButton = compiled.querySelector(
      'app-icon-button[variant="user"] button',
    ) as HTMLButtonElement;
    userButton.click();
    fixture.detectChanges();

    const logoutButton = compiled.querySelector(
      '[data-testid="user-dropdown-logout"]',
    ) as HTMLButtonElement;
    expect(logoutButton).not.toBeNull();
    logoutButton.click();
    fixture.detectChanges();

    expect(authService.logout).toHaveBeenCalled();
    expect(cartService.clearCart).toHaveBeenCalled();
    expect(router.navigate).toHaveBeenCalledWith(['/']);
  });

  it('provides account actions from the footer', () => {
    const authService = TestBed.inject(AuthService);
    const cartService = TestBed.inject(CartService);
    const router = TestBed.inject(Router);
    vi.spyOn(router, 'navigate');

    const fixture = TestBed.createComponent(StoreLayoutComponent);
    fixture.detectChanges();

    const compiled = fixture.nativeElement as HTMLElement;
    const footerLinks = Array.from(
      compiled.querySelectorAll<HTMLAnchorElement>('app-store-footer a.store-layout__footer-link'),
    );
    const profileLink = footerLinks.find((link) => link.textContent?.trim() === 'Mi cuenta');
    const purchasesLink = footerLinks.find((link) => link.textContent?.trim() === 'Mis compras');
    const ticketsLink = footerLinks.find((link) => link.textContent?.trim() === 'Mis tickets');
    const logoutButton = Array.from(
      compiled.querySelectorAll<HTMLButtonElement>('app-store-footer button'),
    ).find((button) => button.textContent?.trim() === 'Cerrar sesion');

    expect(profileLink?.getAttribute('href')).toBe('/mi-cuenta/datos-personales');
    expect(purchasesLink?.getAttribute('href')).toBe('/mi-cuenta/compras');
    expect(ticketsLink).toBeUndefined();
    expect(logoutButton).toBeDefined();

    logoutButton!.click();
    fixture.detectChanges();

    expect(authService.logout).toHaveBeenCalled();
    expect(cartService.clearCart).toHaveBeenCalled();
    expect(router.navigate).toHaveBeenCalledWith(['/']);
  });

  it('leaves checkout before logging out so the pending purchase can be cancelled', async () => {
    const authService = TestBed.inject(AuthService);
    const cartService = TestBed.inject(CartService);
    const router = TestBed.inject(Router);
    vi.spyOn(router, 'url', 'get').mockReturnValue('/checkout/25');
    const navigateSpy = vi.spyOn(router, 'navigate').mockResolvedValue(true);

    const fixture = TestBed.createComponent(StoreLayoutComponent);
    fixture.detectChanges();

    await (fixture.componentInstance as any).onLogoutClick();

    expect(navigateSpy).toHaveBeenCalledWith(['/']);
    expect(authService.logout).toHaveBeenCalled();
    expect(navigateSpy.mock.invocationCallOrder[0]).toBeLessThan(
      (authService.logout as any).mock.invocationCallOrder[0],
    );
    expect(cartService.clearCart).toHaveBeenCalled();
  });

  it('renders only the help submenus assigned to the tenant in the footer', () => {
    const fixture = TestBed.createComponent(StoreLayoutComponent);
    fixture.detectChanges();

    const compiled = fixture.nativeElement as HTMLElement;
    const footerLinks = Array.from(
      compiled.querySelectorAll<HTMLAnchorElement>('app-store-footer a.store-layout__footer-link'),
    );
    const helpLinks = footerLinks.filter((link) =>
      link.getAttribute('href')?.startsWith('/ayuda/'),
    );

    expect(helpLinks.map((link) => link.textContent?.trim())).toEqual([
      'Contacto',
      'Preguntas frecuentes',
    ]);
    expect(helpLinks.map((link) => link.getAttribute('href'))).toEqual([
      '/ayuda/contacto',
      '/ayuda/preguntas-frecuentes',
    ]);
    expect(compiled.textContent).not.toContain('Medios de pago');
  });

  it('creates a purchase and redirects to checkout when cart buy is clicked', async () => {
    const router = TestBed.inject(Router);
    vi.spyOn(router, 'navigate');
    cartState.set({
      id: 1,
      tenant_codigo: tenant.codigo,
      status: 'active',
      subtotal: '100.00',
      items: [
        {
          id: 1,
          cantidad: 1,
          precio_unitario: '100.00',
          catalog_item_id: 1,
          variant_id: null,
          nombre: 'Producto',
          imagen: null,
          variant: null,
        },
      ],
    });
    authUserState.set({
      id: 7,
      nombre_apellido: 'Juan Perez',
      email: 'juan@example.com',
      dni: '12345678',
      telefono: '3415555555',
    });

    const fixture = TestBed.createComponent(StoreLayoutComponent);
    fixture.detectChanges();

    (fixture.componentInstance as any).isCartOpen.set(true);
    fixture.detectChanges();

    const compiled = fixture.nativeElement as HTMLElement;
    const buyButton = Array.from(compiled.querySelectorAll('app-button button')).find(
      (button) => button.textContent?.trim() === 'Comprar',
    ) as HTMLButtonElement | undefined;

    expect(buyButton).toBeDefined();
    buyButton!.click();
    await Promise.resolve();
    fixture.detectChanges();

    expect(checkoutServiceStub.startCheckout).toHaveBeenCalledWith('test', {
      cart_id: 1,
    });
    expect(router.navigate).toHaveBeenCalledWith(['/checkout', 55]);
    expect((fixture.componentInstance as any).isCartOpen()).toBe(false);
  });

  it('shows the backend message and refreshes the cart when its reservation expired', async () => {
    const message = 'La reserva de stock venció. Usá el carrito activo para continuar.';
    checkoutServiceStub.startCheckout.mockRejectedValue(
      new HttpErrorResponse({
        status: 422,
        error: { code: 'stock_reservation.expired', message },
      }),
    );
    cartState.set({
      id: 1,
      tenant_codigo: tenant.codigo,
      status: 'active',
      subtotal: '100.00',
      items: [],
    });
    authUserState.set({
      id: 7,
      nombre_apellido: 'Juan Perez',
      email: 'juan@example.com',
      dni: '12345678',
      telefono: '3415555555',
    });

    const fixture = TestBed.createComponent(StoreLayoutComponent);
    const loadCart = vi.spyOn(TestBed.inject(CartService), 'loadCart');
    fixture.detectChanges();
    loadCart.mockClear();

    await (fixture.componentInstance as any).onCheckoutClick();

    expect(TestBed.inject(ToastService).danger).toHaveBeenCalledWith(message);
    expect(loadCart).toHaveBeenCalledOnce();
  });

  it('allows modifying quantities directly in the regular cart without a toggle', () => {
    cartState.set({
      id: 1,
      tenant_codigo: tenant.codigo,
      status: 'active',
      subtotal: '100.00',
      items: [
        {
          id: 1,
          cantidad: 1,
          precio_unitario: '100.00',
          catalog_item_id: 1,
          variant_id: null,
          nombre: 'Producto',
          imagen: null,
          variant: null,
        },
      ],
    });

    const fixture = TestBed.createComponent(StoreLayoutComponent);
    fixture.detectChanges();
    (fixture.componentInstance as any).isCartOpen.set(true);
    fixture.detectChanges();

    const element = fixture.nativeElement as HTMLElement;
    const cartItem = fixture.debugElement.query(By.css('app-cart-item'));
    const buyButton = Array.from(
      element.querySelectorAll<HTMLButtonElement>('app-button button'),
    ).find((button) => button.textContent?.trim() === 'Comprar');

    expect(element.querySelector('.cart-edit-btn')).toBeNull();
    expect(cartItem.componentInstance.quantityDisabled()).toBe(false);
    expect(buyButton).toBeDefined();
  });

  it('hides quantity selectors when the tenant disables cart editing', () => {
    tenantState.set({
      ...tenant,
      cart_editing_policy: {
        code: 'disabled',
        allow_modify: false,
        allow_delete: false,
        allow_update_quantity: false,
        allow_update_variant: false,
      },
    });
    cartState.set({
      id: 1,
      tenant_codigo: tenant.codigo,
      status: 'active',
      subtotal: '100.00',
      items: [
        {
          id: 1,
          cantidad: 1,
          precio_unitario: '100.00',
          catalog_item_id: 1,
          variant_id: null,
          nombre: 'Producto',
          imagen: null,
          variant: null,
        },
      ],
    });

    const fixture = TestBed.createComponent(StoreLayoutComponent);
    fixture.detectChanges();
    (fixture.componentInstance as any).isCartOpen.set(true);
    fixture.detectChanges();

    const cartItem = fixture.debugElement.query(By.css('app-cart-item'));
    expect(cartItem.componentInstance.readonly()).toBe(true);
    expect(cartItem.nativeElement.querySelector('app-quantity-selector')).toBeNull();
  });

  it('shows variant selectors only for the full cart editing policy', () => {
    const variantCart: Cart = {
      id: 1,
      tenant_codigo: tenant.codigo,
      status: 'active',
      subtotal: '100.00',
      items: [
        {
          id: 1,
          cantidad: 1,
          precio_unitario: '100.00',
          catalog_item_id: 1,
          variant_id: 10,
          nombre: 'Producto',
          imagen: null,
          variant: { id: 10, precio: '100.00', stock_tecnico: 5, values: { talle: 'M' } },
          variants: [
            { id: 10, precio: '100.00', stock_tecnico: 5, values: { talle: 'M' } },
            { id: 11, precio: '100.00', stock_tecnico: 5, values: { talle: 'L' } },
          ],
        },
      ],
    };
    tenantState.set({
      ...tenant,
      cart_editing_policy: {
        code: 'quantity_and_remove',
        allow_modify: true,
        allow_delete: true,
        allow_update_quantity: true,
        allow_update_variant: false,
      },
    });
    cartState.set(variantCart);

    const fixture = TestBed.createComponent(StoreLayoutComponent);
    fixture.detectChanges();
    (fixture.componentInstance as any).isCartOpen.set(true);
    fixture.detectChanges();

    expect(fixture.nativeElement.querySelector('app-variant-selector')).toBeNull();
    expect(fixture.nativeElement.querySelector('app-quantity-selector')).not.toBeNull();

    tenantState.set({
      ...tenant,
      cart_editing_policy: {
        code: 'full',
        allow_modify: true,
        allow_delete: true,
        allow_update_quantity: true,
        allow_update_variant: true,
      },
    });
    fixture.detectChanges();

    expect(fixture.nativeElement.querySelector('app-variant-selector')).not.toBeNull();
  });
});
