/**
 * useCohortSelection — unit tests (R6UX-001 / R6UXS-002)
 *
 * Mirrors the test structure of useContentInventorySelection.test.ts
 * to validate identical selection semantics in the shared primitive.
 */
import { act, renderHook } from '@testing-library/react';
import { describe, expect, it } from 'vitest';

import { useCohortSelection } from './useCohortSelection';

const PAGE_IDS = ['id-1', 'id-2', 'id-3'];
const TOTAL_COUNT = 10; // 10 total in cohort, 3 on this page

function setup(overrides?: { pageIds?: string[]; totalCount?: number }) {
  return renderHook(() =>
    useCohortSelection({
      pageIds: overrides?.pageIds ?? PAGE_IDS,
      totalCount: overrides?.totalCount ?? TOTAL_COUNT,
    }),
  );
}

describe('useCohortSelection', () => {
  // ── initial state ─────────────────────────────────────────────────────
  it('starts with nothing selected', () => {
    const { result } = setup();
    expect(result.current.selectedIds.size).toBe(0);
    expect(result.current.allMatchingSelected).toBe(false);
    expect(result.current.effectiveCount).toBe(0);
  });

  it('allPageSelected is false when page is empty', () => {
    const { result } = setup({ pageIds: [] });
    expect(result.current.allPageSelected).toBe(false);
  });

  // ── toggleRow ─────────────────────────────────────────────────────────
  it('toggleRow selects a single item', () => {
    const { result } = setup();
    act(() => result.current.toggleRow('id-1'));
    expect(result.current.selectedIds.has('id-1')).toBe(true);
    expect(result.current.effectiveCount).toBe(1);
  });

  it('toggleRow deselects an already-selected item', () => {
    const { result } = setup();
    act(() => result.current.toggleRow('id-1'));
    act(() => result.current.toggleRow('id-1'));
    expect(result.current.selectedIds.has('id-1')).toBe(false);
    expect(result.current.effectiveCount).toBe(0);
  });

  it('deselecting a row clears allMatchingSelected', () => {
    const { result } = setup();
    act(() => result.current.selectAllMatching());
    expect(result.current.allMatchingSelected).toBe(true);
    act(() => result.current.toggleRow('id-1'));
    expect(result.current.allMatchingSelected).toBe(false);
  });

  // FND-001: multi-page scenario — toggleRow on an id NOT in selectedIds while
  // allMatchingSelected=true should DESELECT (exit cohort mode), not ADD the id.
  it('toggleRow on a non-page id while allMatchingSelected exits cohort mode', () => {
    const { result } = setup({ pageIds: ['id-1', 'id-2'], totalCount: 10 });
    act(() => result.current.selectAllMatching());
    expect(result.current.allMatchingSelected).toBe(true);
    // 'other-page-id' is not in the current pageIds — simulates a different page's row
    act(() => result.current.toggleRow('other-page-id'));
    expect(result.current.allMatchingSelected).toBe(false);
    // The clicked id should be deselected (removed), not added
    expect(result.current.selectedIds.has('other-page-id')).toBe(false);
  });

  // ── togglePageAll ──────────────────────────────────────────────────────
  it('togglePageAll selects all page items when none selected', () => {
    const { result } = setup();
    act(() => result.current.togglePageAll());
    expect(result.current.allPageSelected).toBe(true);
    PAGE_IDS.forEach((id) => expect(result.current.selectedIds.has(id)).toBe(true));
  });

  it('togglePageAll deselects all page items when all are selected', () => {
    const { result } = setup();
    act(() => result.current.togglePageAll()); // select
    act(() => result.current.togglePageAll()); // deselect
    expect(result.current.allPageSelected).toBe(false);
    PAGE_IDS.forEach((id) => expect(result.current.selectedIds.has(id)).toBe(false));
  });

  it('togglePageAll deselects clears allMatchingSelected', () => {
    const { result } = setup();
    act(() => result.current.selectAllMatching());
    expect(result.current.allMatchingSelected).toBe(true);
    act(() => result.current.togglePageAll()); // all page already checked → deselect
    expect(result.current.allMatchingSelected).toBe(false);
  });

  // FND-001: multi-page scenario — togglePageAll on a different page (whose ids were
  // never added to selectedIds) while allMatchingSelected=true should DESELECT, not ADD.
  it('togglePageAll on a different page while allMatchingSelected exits cohort mode', () => {
    // Use renderHook directly so we can rerender with different props.
    const { result, rerender } = renderHook(
      ({ pageIds, totalCount }: { pageIds: string[]; totalCount: number }) =>
        useCohortSelection({ pageIds, totalCount }),
      { initialProps: { pageIds: ['id-1', 'id-2'], totalCount: 10 } },
    );
    act(() => result.current.selectAllMatching());
    expect(result.current.allMatchingSelected).toBe(true);
    // Simulate navigating to a different page — rerender with different pageIds.
    rerender({ pageIds: ['page2-id-1', 'page2-id-2'], totalCount: 10 });
    // The page-2 ids were never in selectedIds, so allPageSelected=false,
    // but allMatchingSelected=true. Clicking the checkbox should DESELECT (exit cohort).
    act(() => result.current.togglePageAll());
    expect(result.current.allMatchingSelected).toBe(false);
  });

  it('togglePageAll does not set allMatchingSelected when selecting page', () => {
    const { result } = setup();
    act(() => result.current.togglePageAll());
    expect(result.current.allPageSelected).toBe(true);
    expect(result.current.allMatchingSelected).toBe(false);
  });

  // ── selectAllMatching ─────────────────────────────────────────────────
  it('selectAllMatching sets allMatchingSelected and checks all page rows', () => {
    const { result } = setup();
    act(() => result.current.selectAllMatching());
    expect(result.current.allMatchingSelected).toBe(true);
    expect(result.current.allPageSelected).toBe(true);
    expect(result.current.effectiveCount).toBe(TOTAL_COUNT);
  });

  // ── clearSelection ────────────────────────────────────────────────────
  it('clearSelection resets all state', () => {
    const { result } = setup();
    act(() => result.current.selectAllMatching());
    act(() => result.current.clearSelection());
    expect(result.current.selectedIds.size).toBe(0);
    expect(result.current.allMatchingSelected).toBe(false);
    expect(result.current.effectiveCount).toBe(0);
  });

  // ── selectSingle ──────────────────────────────────────────────────────
  it('selectSingle pre-selects exactly one item and clears cohort mode', () => {
    const { result } = setup();
    act(() => result.current.selectAllMatching());
    act(() => result.current.selectSingle('id-2'));
    expect(result.current.selectedIds.size).toBe(1);
    expect(result.current.selectedIds.has('id-2')).toBe(true);
    expect(result.current.allMatchingSelected).toBe(false);
  });

  // ── onDispatched ──────────────────────────────────────────────────────
  it('onDispatched clears selection after successful dispatch', () => {
    const { result } = setup();
    act(() => result.current.selectAllMatching());
    expect(result.current.effectiveCount).toBe(TOTAL_COUNT);
    act(() => result.current.onDispatched());
    expect(result.current.selectedIds.size).toBe(0);
    expect(result.current.allMatchingSelected).toBe(false);
    expect(result.current.effectiveCount).toBe(0);
  });

  // ── somePageSelected ─────────────────────────────────────────────────
  it('somePageSelected is true when some but not all page items selected', () => {
    const { result } = setup();
    act(() => result.current.toggleRow('id-1'));
    expect(result.current.somePageSelected).toBe(true);
    expect(result.current.allPageSelected).toBe(false);
  });

  it('somePageSelected is false when all page items selected', () => {
    const { result } = setup();
    act(() => result.current.togglePageAll());
    expect(result.current.somePageSelected).toBe(false);
    expect(result.current.allPageSelected).toBe(true);
  });

  // ── effectiveCount ────────────────────────────────────────────────────
  it('effectiveCount reflects selectedIds.size in ids mode', () => {
    const { result } = setup();
    act(() => result.current.toggleRow('id-1'));
    act(() => result.current.toggleRow('id-2'));
    expect(result.current.effectiveCount).toBe(2);
  });

  it('effectiveCount reflects totalCount in cohort mode', () => {
    const { result } = setup({ totalCount: 42 });
    act(() => result.current.selectAllMatching());
    expect(result.current.effectiveCount).toBe(42);
  });
});
