import { act, renderHook, waitFor } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { describe, expect, it, vi } from 'vitest';
import { api } from '@/lib/api';
import { requireSelectedStore } from '@/lib/stores/store-context';
vi.mock('@/lib/stores/store-context', () => ({ requireSelectedStore: vi.fn((id: string) => id), captureCommandGeneration: vi.fn(() => 7) }));
import { SCHEDULE_KEYS, useScheduleWeek, useScheduleMutation, useCopyWeek } from '../use-scheduling';
vi.mock('@/lib/api', () => ({ api: { scheduling: { week: vi.fn(), myWeek: vi.fn(), deleteShift: vi.fn(), copyWeek: vi.fn() } } }));
function setup() {
  const qc = new QueryClient({ defaultOptions: { queries: { retry: false }, mutations: { retry: false } } });
  return { qc, wrapper: ({ children }: {children: React.ReactNode}) => <QueryClientProvider client={qc}>{children}</QueryClientProvider> };
}
describe('schedule query isolation', () => {
  it('checks the exact capability at dispatch and refuses stale-store completion', async () => {
    const { wrapper } = setup();
    let finish!: () => void;
    vi.mocked(api.scheduling.deleteShift).mockImplementation(() => new Promise<{ data: { deleted: true } }>(resolve => { finish = () => resolve({ data: { deleted: true } }); }));
    const { result } = renderHook(() => useScheduleMutation('s1'), { wrapper });
    const pending = result.current.mutateAsync({ action: 'delete', id: 'shift', revision: 'r' });
    await waitFor(() => expect(api.scheduling.deleteShift).toHaveBeenCalled());
    expect(requireSelectedStore).toHaveBeenCalledWith('s1', 'schedule.manage', 7);
    vi.mocked(requireSelectedStore).mockImplementation(() => { throw new Error('Store access changed'); });
    finish();
    await expect(pending).rejects.toThrow('Store access changed');
    vi.mocked(requireSelectedStore).mockImplementation(id => id!);
  });
  it('does not fetch without membership; separates own/team and store caches', async () => {
    vi.mocked(api.scheduling.week).mockResolvedValue({ data: { shifts: [] } } as never);
    vi.mocked(api.scheduling.myWeek).mockResolvedValue({ data: { shifts: [] } } as never);
    const { wrapper } = setup();
    const { result, rerender } = renderHook(({ id, own }: { id: string | null; own: boolean }) => useScheduleWeek(id, '2026-09-07', own), { wrapper, initialProps: { id: null as string | null, own: false } });
    expect(api.scheduling.week).not.toHaveBeenCalled();
    rerender({ id: 's1', own: false });
    await waitFor(() => expect(result.current.isSuccess).toBe(true));
    rerender({ id: 's2', own: true });
    await waitFor(() => expect(api.scheduling.myWeek).toHaveBeenCalledWith('s2', '2026-09-07'));
    expect(SCHEDULE_KEYS.week('s1', '2026-09-07', false)).not.toEqual(SCHEDULE_KEYS.week('s1', '2026-09-07', true));
  });
  it('invalidates only the changed store including staff data, never after copy preview', async () => {
    vi.mocked(api.scheduling.deleteShift).mockResolvedValue({ data: { deleted: true } });
    vi.mocked(api.scheduling.copyWeek).mockResolvedValue({ data: { shifts: [], shift_count: 0, copied: 0, conflict_count: 0, conflicts: [], source_week_start: '2026-09-07', target_week_start: '2026-09-14', preview: true } });
    const { qc, wrapper } = setup();
    qc.setQueryData(SCHEDULE_KEYS.week('s1', '2026-09-07', true), { data: {} });
    qc.setQueryData(SCHEDULE_KEYS.week('s2', '2026-09-07', true), { data: {} });
    const { result } = renderHook(() => ({ change: useScheduleMutation('s1'), copy: useCopyWeek('s1') }), { wrapper });
    await act(async () => { await result.current.copy.mutateAsync({ source_week_start: '2026-09-07', target_week_start: '2026-09-14', preview: true }); });
    expect(qc.getQueryState(SCHEDULE_KEYS.week('s1', '2026-09-07', true))?.isInvalidated).toBe(false);
    await act(async () => { await result.current.change.mutateAsync({ action: 'delete', id: 'shift', revision: 'exact.123456' }); });
    expect(api.scheduling.deleteShift).toHaveBeenCalledWith('s1', 'shift', 'exact.123456');
    expect(qc.getQueryState(SCHEDULE_KEYS.week('s1', '2026-09-07', true))?.isInvalidated).toBe(true);
    expect(qc.getQueryState(SCHEDULE_KEYS.week('s2', '2026-09-07', true))?.isInvalidated).toBe(false);
  });
});
