// @vitest-environment jsdom
import { afterEach, describe, expect, it, vi } from 'vitest';
import { cleanup, fireEvent, render, screen, within } from '@testing-library/react';

import ScannerHistoryStrip, {
  TAB_DUPLICATES,
  TAB_QUEUE,
  TAB_RECENT,
  getDuplicateCards,
} from '../../components/scanner/ScannerHistoryStrip.js';

const CARD_A = {
  id: 'card-a',
  name: 'Lightning Bolt',
  set: 'Alpha',
  databaseId: 101,
  quantity: 1,
  processed: false,
};

const CARD_B = {
  id: 'card-b',
  name: 'Lightning Bolt',
  set: 'Alpha',
  databaseId: 102,
  quantity: 1,
  processed: false,
};

const CARD_C = {
  id: 'card-c',
  name: 'Counterspell',
  set: 'Beta',
  databaseId: 201,
  quantity: 2,
  processed: true,
};

function renderStrip(overrides = {}) {
  const props = {
    scannedCards: [],
    ownershipMap: {},
    focusedCardId: null,
    onFocusCard: vi.fn(),
    activeTab: TAB_RECENT,
    onTabChange: vi.fn(),
    batchProgress: null,
    onClearAll: vi.fn(),
    onCommitSelectedToOwned: vi.fn(),
    onOpenListPicker: vi.fn(),
    isProcessing: false,
    ...overrides,
  };

  return {
    ...render(<ScannerHistoryStrip {...props} />),
    props,
  };
}

describe('getDuplicateCards', () => {
  it('flags session name/set repeats', () => {
    const result = getDuplicateCards([CARD_A, CARD_B], {});
    expect(result.map((card) => card.id)).toEqual(['card-b']);
  });

  it('flags quantity greater than one', () => {
    const solo = { ...CARD_C, quantity: 2 };
    const result = getDuplicateCards([solo], {});
    expect(result).toHaveLength(1);
    expect(result[0].id).toBe('card-c');
  });

  it('flags cards already in ownershipMap by databaseId', () => {
    const owned = { ...CARD_A, databaseId: 999 };
    const result = getDuplicateCards([owned], { 999: { quantity: 1 } });
    expect(result).toHaveLength(1);
    expect(result[0].id).toBe('card-a');
  });
});

describe('ScannerHistoryStrip', () => {
  afterEach(() => cleanup());

  it('renders three tabs with badge counts in aria-label', () => {
    renderStrip({
      scannedCards: [CARD_A, CARD_B, CARD_C],
      activeTab: TAB_RECENT,
    });

    expect(screen.getByRole('tab', { name: 'Recent Scans' })).toBeTruthy();
    expect(screen.getByRole('tab', { name: 'Scan Queue, 2 unprocessed cards' })).toBeTruthy();
    expect(screen.getByRole('tab', { name: 'Duplicates, 2 duplicate cards' })).toBeTruthy();
    expect(screen.getByRole('tab', { name: 'Scan Queue, 2 unprocessed cards' }).innerHTML).not.toContain('#ffffff');
  });

  it('calls onTabChange when a tab is clicked', () => {
    const { props } = renderStrip({ scannedCards: [CARD_A] });

    fireEvent.click(screen.getByRole('tab', { name: /scan queue/i }));
    expect(props.onTabChange).toHaveBeenCalledWith(TAB_QUEUE);
  });

  it('shows empty states for each tab', () => {
    const { rerender, props } = renderStrip({ activeTab: TAB_RECENT });
    expect(screen.getByText('No scans yet this session.')).toBeTruthy();

    rerender(<ScannerHistoryStrip {...props} activeTab={TAB_QUEUE} />);
    expect(
      screen.getByText('Scan queue is empty — matches appear here before you add them.')
    ).toBeTruthy();

    rerender(<ScannerHistoryStrip {...props} activeTab={TAB_DUPLICATES} />);
    expect(screen.getByText('No duplicates detected.')).toBeTruthy();
  });

  it('row click invokes onFocusCard without commit handlers', () => {
    const onFocusCard = vi.fn();
    const onCommitSelectedToOwned = vi.fn();
    const onOpenListPicker = vi.fn();

    renderStrip({
      scannedCards: [CARD_A],
      activeTab: TAB_RECENT,
      onFocusCard,
      onCommitSelectedToOwned,
      onOpenListPicker,
    });

    fireEvent.click(screen.getByRole('button', { name: /lightning bolt/i }));
    expect(onFocusCard).toHaveBeenCalledWith('card-a');
    expect(onCommitSelectedToOwned).not.toHaveBeenCalled();
    expect(onOpenListPicker).not.toHaveBeenCalled();
  });

  it('applies focused styling when focusedCardId matches a chip', () => {
    renderStrip({
      scannedCards: [CARD_A],
      activeTab: TAB_RECENT,
      focusedCardId: 'card-a',
    });

    const chip = screen.getByRole('button', { name: /lightning bolt/i });
    expect(chip.getAttribute('aria-current')).toBe('true');
  });

  it('shows batch progress banner with cancel in Scan Queue tab', () => {
    const onCancel = vi.fn();
    renderStrip({
      scannedCards: [CARD_A],
      activeTab: TAB_QUEUE,
      batchProgress: { active: true, current: 2, total: 5, onCancel },
    });

    expect(screen.getByText('Scanning 2 of 5…')).toBeTruthy();
    fireEvent.click(screen.getByRole('button', { name: /^cancel$/i }));
    expect(onCancel).toHaveBeenCalledTimes(1);
  });

  it('disables Clear All while batch progress is active', () => {
    renderStrip({
      scannedCards: [CARD_A],
      batchProgress: { active: true, current: 1, total: 3, onCancel: vi.fn() },
    });

    expect(screen.getByRole('button', { name: /clear all/i }).disabled).toBe(true);
  });

  it('shows identify failed label on failed queue rows', () => {
    const failedCard = {
      ...CARD_A,
      identifyFailed: true,
      identifyFailureReason: 'No match found',
    };

    renderStrip({
      scannedCards: [failedCard],
      activeTab: TAB_QUEUE,
    });

    expect(screen.getByText('Identify failed')).toBeTruthy();
    expect(screen.getByText('No match found')).toBeTruthy();
  });

  it('lists recent scans newest first', () => {
    const older = { ...CARD_A, id: 'older', name: 'Older Card' };
    const newer = { ...CARD_B, id: 'newer', name: 'Newer Card', set: 'New Set' };

    renderStrip({
      scannedCards: [older, newer],
      activeTab: TAB_RECENT,
    });

    const panel = screen.getByRole('tabpanel', { name: /recent scans/i });
    const buttons = within(panel).getAllByRole('button');
    expect(buttons[0].textContent).toContain('Newer Card');
    expect(buttons[1].textContent).toContain('Older Card');
  });

  it('exposes tablist semantics', () => {
    renderStrip({ scannedCards: [CARD_A] });
    expect(screen.getByRole('tablist', { name: 'Scan history' })).toBeTruthy();
    expect(screen.getAllByRole('tab')).toHaveLength(3);
    expect(screen.getAllByRole('tabpanel', { hidden: true })).toHaveLength(3);
  });
});
