// #region DatasetReviewSessionTests [C:3] [TYPE Module] [SEMANTICS dataset, review, session, store, test, diff]
// @BRIEF Unit tests for dataset review session store: session set/reset, loading, error, dirty flag, and patch operations.
// @RELATION DEPENDS_ON -> [DatasetReviewSessionStore]

// #region DatasetReviewSessionStoreTests:Module [TYPE Function]
// @SEMANTICS: dataset-review, store, session, tests
// @PURPOSE: Unit tests for dataset review session store.
// @LAYER UI
// @RELATION DEPENDS_ON -> [EXT:frontend:datasetReviewSession]
// @UX_STATE: Idle -> Store helpers are exercised without asynchronous UI transitions.

import { describe, it, expect, beforeEach, vi } from 'vitest';

describe('datasetReviewSession store', () => {
  beforeEach(async () => {
    vi.resetModules();
  });

  it('should have correct initial state', async () => {
    const { datasetReviewSessionStore } = await import('../datasetReviewSession.svelte.js');
    
    let state = null;
    const unsubscribe = datasetReviewSessionStore.subscribe(s => { state = s; });
    unsubscribe();
    
    expect(state.session).toBeNull();
    expect(state.isLoading).toBe(false);
    expect(state.isSaving).toBe(false);
    expect(state.error).toBeNull();
    expect(state.isDirty).toBe(false);
  });

  it('should set session data', async () => {
    const { datasetReviewSessionStore, setSession } = await import('../datasetReviewSession.svelte.js');
    const mockSession = { session_id: 's1', user_id: 'u1' };
    
    setSession(mockSession);
    
    let state = null;
    const unsubscribe = datasetReviewSessionStore.subscribe(s => { state = s; });
    unsubscribe();
    
    expect(state.session).toEqual(mockSession);
    expect(state.isLoading).toBe(false);
    expect(state.error).toBeNull();
    expect(state.lastUpdated).toBeInstanceOf(Date);
    expect(state.isDirty).toBe(false);
  });

  it('should update loading state', async () => {
    const { datasetReviewSessionStore, setLoading } = await import('../datasetReviewSession.svelte.js');
    
    setLoading(true);
    
    let state = null;
    const unsubscribe = datasetReviewSessionStore.subscribe(s => { state = s; });
    unsubscribe();
    
    expect(state.isLoading).toBe(true);
  });

  it('should set error state', async () => {
    const { datasetReviewSessionStore, setError } = await import('../datasetReviewSession.svelte.js');
    
    setError('Failed to load');
    
    let state = null;
    const unsubscribe = datasetReviewSessionStore.subscribe(s => { state = s; });
    unsubscribe();
    
    expect(state.error).toBe('Failed to load');
    expect(state.isLoading).toBe(false);
  });

  it('should mark as dirty', async () => {
    const { datasetReviewSessionStore, setDirty } = await import('../datasetReviewSession.svelte.js');
    
    setDirty(true);
    
    let state = null;
    const unsubscribe = datasetReviewSessionStore.subscribe(s => { state = s; });
    unsubscribe();
    
    expect(state.isDirty).toBe(true);
  });

  it('should patch session data and mark as dirty', async () => {
    const { datasetReviewSessionStore, setSession, patchSession } = await import('../datasetReviewSession.svelte.js');
    const mockSession = { session_id: 's1', readiness_state: 'empty' };
    
    setSession(mockSession);
    patchSession({ readiness_state: 'ready' });
    
    let state = null;
    const unsubscribe = datasetReviewSessionStore.subscribe(s => { state = s; });
    unsubscribe();
    
    expect(state.session.readiness_state).toBe('ready');
    expect(state.isDirty).toBe(true);
  });

  it('should reset session', async () => {
    const { datasetReviewSessionStore, setSession, resetSession } = await import('../datasetReviewSession.svelte.js');
    setSession({ id: 's1' });
    
    resetSession();
    
    let state = null;
    const unsubscribe = datasetReviewSessionStore.subscribe(s => { state = s; });
    unsubscribe();
    
    expect(state.session).toBeNull();
  });

  it('should be no-op calling setLoading with same value', async () => {
    const { datasetReviewSessionStore, setLoading } = await import('../datasetReviewSession.svelte.js');
    setLoading(true);
    let state1: any = null;
    const unsub1 = datasetReviewSessionStore.subscribe(s => { state1 = s; });
    unsub1();
    expect(state1.isLoading).toBe(true);

    setLoading(true); // Same value — guard should return early
    let state2: any = null;
    const unsub2 = datasetReviewSessionStore.subscribe(s => { state2 = s; });
    unsub2();
    expect(state2.isLoading).toBe(true);
  });

  it('should be no-op calling setDirty with same value', async () => {
    const { datasetReviewSessionStore, setDirty } = await import('../datasetReviewSession.svelte.js');
    setDirty(true);
    setDirty(true); // Same value — guard returns early
    let state: any = null;
    const unsubscribe = datasetReviewSessionStore.subscribe(s => { state = s; });
    unsubscribe();
    expect(state.isDirty).toBe(true);
  });

  it('should set error and clear loading flags', async () => {
    const { datasetReviewSessionStore, setLoading, setError } = await import('../datasetReviewSession.svelte.js');
    setLoading(true);
    setError('Failed to load session');
    let state: any = null;
    const unsubscribe = datasetReviewSessionStore.subscribe(s => { state = s; });
    unsubscribe();
    expect(state.error).toBe('Failed to load session');
    expect(state.isLoading).toBe(false);
    expect(state.isSaving).toBe(false);
  });

  it('should be no-op calling patchSession when session is null', async () => {
    const { datasetReviewSessionStore, patchSession } = await import('../datasetReviewSession.svelte.js');
    // session is null by default
    patchSession({ readiness_state: 'ready' });
    let state: any = null;
    const unsubscribe = datasetReviewSessionStore.subscribe(s => { state = s; });
    unsubscribe();
    // Session should still be null (patch was no-op)
    expect(state.session).toBeNull();
    expect(state.isDirty).toBe(false);
  });

  it('should support unsubscribe from datasetReviewSessionStore', async () => {
    const { datasetReviewSessionStore } = await import('../datasetReviewSession.svelte.js');
    const received: any[] = [];
    const unsub = datasetReviewSessionStore.subscribe(s => received.push(s));
    const initialCount = received.length;
    unsub();
    // Should not receive further updates after unsubscribe
    expect(received.length).toBe(initialCount);
  });

  it('should be no-op calling setError with same error when not loading/saving', async () => {
    const { datasetReviewSessionStore, setError } = await import('../datasetReviewSession.svelte.js');
    setError('Some error');
    let state1: any = null;
    const unsub1 = datasetReviewSessionStore.subscribe(s => { state1 = s; });
    unsub1();
    expect(state1.error).toBe('Some error');
    expect(state1.isLoading).toBe(false);
    expect(state1.isSaving).toBe(false);

    // Call with same error — guard should return
    setError('Some error');
    let state2: any = null;
    const unsub2 = datasetReviewSessionStore.subscribe(s => { state2 = s; });
    unsub2();
    expect(state2.error).toBe('Some error');
  });

  it('setError with different error should update even when not loading', async () => {
    const { datasetReviewSessionStore, setError } = await import('../datasetReviewSession.svelte.js');
    setError('Error 1');
    setError('Error 2');
    let state: any = null;
    const unsubscribe = datasetReviewSessionStore.subscribe(s => { state = s; });
    unsubscribe();
    expect(state.error).toBe('Error 2');
  });

  it('setLoading false should be a no-op when already false', async () => {
    const { datasetReviewSessionStore, setLoading } = await import('../datasetReviewSession.svelte.js');
    expect(datasetReviewSessionStore.value.isLoading).toBe(false);
    setLoading(false);
    expect(datasetReviewSessionStore.value.isLoading).toBe(false);
  });

  it('setDirty false should be a no-op when already false', async () => {
    const { datasetReviewSessionStore, setDirty } = await import('../datasetReviewSession.svelte.js');
    expect(datasetReviewSessionStore.value.isDirty).toBe(false);
    setDirty(false);
    expect(datasetReviewSessionStore.value.isDirty).toBe(false);
  });

  it('setSession should set lastUpdated to a Date', async () => {
    const { datasetReviewSessionStore, setSession } = await import('../datasetReviewSession.svelte.js');
    setSession({ session_id: 's1' });
    expect(datasetReviewSessionStore.value.lastUpdated).toBeInstanceOf(Date);
    expect(datasetReviewSessionStore.value.isDirty).toBe(false);
  });

  it('store.get value should return current state', async () => {
    const { datasetReviewSessionStore } = await import('../datasetReviewSession.svelte.js');
    expect(datasetReviewSessionStore.value.session).toBeNull();
    expect(datasetReviewSessionStore.value.isLoading).toBe(false);
  });

  it('should set isSaving to false when setError clears it', async () => {
    const { datasetReviewSessionStore, setError } = await import('../datasetReviewSession.svelte.js');
    // Set an error — this also clears isLoading and isSaving
    setError('Critical error');
    expect(datasetReviewSessionStore.value.error).toBe('Critical error');
    expect(datasetReviewSessionStore.value.isLoading).toBe(false);
    expect(datasetReviewSessionStore.value.isSaving).toBe(false);
  });

  it('setError with same error but isLoading=true should proceed to update', async () => {
    const { datasetReviewSessionStore, setError, setLoading } = await import('../datasetReviewSession.svelte.js');
    // Set error to known value
    setError('Err');
    expect(datasetReviewSessionStore.value.error).toBe('Err');
    // Then set loading=true
    setLoading(true);
    // Now call setError with SAME error while loading is true
    // Condition: _state.error === error (true) && !_state.isLoading (false) → short-circuits to false → proceeds to update
    setError('Err');
    // isLoading and isSaving should be cleared by setError
    expect(datasetReviewSessionStore.value.error).toBe('Err');
    expect(datasetReviewSessionStore.value.isLoading).toBe(false);
    expect(datasetReviewSessionStore.value.isSaving).toBe(false);
  });

  it('should update session data on consecutive setSession calls', async () => {
    const { datasetReviewSessionStore, setSession } = await import('../datasetReviewSession.svelte.js');

    setSession({ session_id: 's1', step: 1 });
    expect(datasetReviewSessionStore.value.session?.step).toBe(1);
    expect(datasetReviewSessionStore.value.isDirty).toBe(false);

    setSession({ session_id: 's1', step: 2 });
    expect(datasetReviewSessionStore.value.session?.step).toBe(2);
    expect(datasetReviewSessionStore.value.isDirty).toBe(false);
  });

  it('should set session and clear loading flag', async () => {
    const { datasetReviewSessionStore, setSession, setLoading } = await import('../datasetReviewSession.svelte.js');

    setLoading(true);
    expect(datasetReviewSessionStore.value.isLoading).toBe(true);

    setSession({ session_id: 's1' });
    expect(datasetReviewSessionStore.value.session?.session_id).toBe('s1');
    expect(datasetReviewSessionStore.value.isLoading).toBe(false);
    expect(datasetReviewSessionStore.value.isDirty).toBe(false);
  });

  it('should notify active subscribers when state changes', async () => {
    const { datasetReviewSessionStore, setSession } = await import('../datasetReviewSession.svelte.js');

    const spy = vi.fn();
    const unsubscribe = datasetReviewSessionStore.subscribe(spy);
    spy.mockClear(); // Clear initial notification

    // Now mutate — subscriber should be called
    setSession({ id: 'notify-test' });

    expect(spy).toHaveBeenCalledTimes(1);
    const callArg = spy.mock.calls[0][0];
    expect(callArg.session?.id).toBe('notify-test');
    expect(callArg.isDirty).toBe(false);

    unsubscribe();
  });

  it('should notify subscribers on setError', async () => {
    const { datasetReviewSessionStore, setError } = await import('../datasetReviewSession.svelte.js');

    const spy = vi.fn();
    const unsubscribe = datasetReviewSessionStore.subscribe(spy);
    spy.mockClear();

    setError('test error');

    expect(spy).toHaveBeenCalledTimes(1);
    const callArg = spy.mock.calls[0][0];
    expect(callArg.error).toBe('test error');

    unsubscribe();
  });

  it('should notify subscribers on patchSession', async () => {
    const { datasetReviewSessionStore, setSession, patchSession } = await import('../datasetReviewSession.svelte.js');

    setSession({ id: 'patch-notify' });

    const spy = vi.fn();
    const unsubscribe = datasetReviewSessionStore.subscribe(spy);
    spy.mockClear();

    patchSession({ data: 'updated' });

    expect(spy).toHaveBeenCalledTimes(1);
    expect(spy.mock.calls[0][0].session?.data).toBe('updated');
    expect(spy.mock.calls[0][0].isDirty).toBe(true);

    unsubscribe();
  });

  it('should notify subscribers on resetSession', async () => {
    const { datasetReviewSessionStore, setSession, resetSession } = await import('../datasetReviewSession.svelte.js');

    setSession({ id: 'reset-me' });

    const spy = vi.fn();
    const unsubscribe = datasetReviewSessionStore.subscribe(spy);
    spy.mockClear();

    resetSession();

    expect(spy).toHaveBeenCalledTimes(1);
    expect(spy.mock.calls[0][0].session).toBeNull();

    unsubscribe();
  });
});

describe('getSessionUiPhase', () => {
  it('should return "empty" for null session', async () => {
    const { getSessionUiPhase } = await import('../datasetReviewSession.svelte.js');
    expect(getSessionUiPhase(null)).toBe('empty');
  });

  it('should return "importing" for readiness_state "importing"', async () => {
    const { getSessionUiPhase } = await import('../datasetReviewSession.svelte.js');
    expect(getSessionUiPhase({ readiness_state: 'importing' })).toBe('importing');
  });

  it('should return "partial_preview" for "partially_ready"', async () => {
    const { getSessionUiPhase } = await import('../datasetReviewSession.svelte.js');
    expect(getSessionUiPhase({ readiness_state: 'partially_ready' })).toBe('partial_preview');
  });

  it('should return "partial_preview" for "compiled_preview_ready"', async () => {
    const { getSessionUiPhase } = await import('../datasetReviewSession.svelte.js');
    expect(getSessionUiPhase({ readiness_state: 'compiled_preview_ready' })).toBe('partial_preview');
  });

  it('should return "launch_blocked" for "recovery_required"', async () => {
    const { getSessionUiPhase } = await import('../datasetReviewSession.svelte.js');
    expect(getSessionUiPhase({ readiness_state: 'recovery_required' })).toBe('launch_blocked');
  });

  it('should return "run_ready" for "run_ready"', async () => {
    const { getSessionUiPhase } = await import('../datasetReviewSession.svelte.js');
    expect(getSessionUiPhase({ readiness_state: 'run_ready' })).toBe('run_ready');
  });

  it('should return "run_in_progress" for "run_in_progress"', async () => {
    const { getSessionUiPhase } = await import('../datasetReviewSession.svelte.js');
    expect(getSessionUiPhase({ readiness_state: 'run_in_progress' })).toBe('run_in_progress');
  });

  it('should return "review" for unknown readiness_state', async () => {
    const { getSessionUiPhase } = await import('../datasetReviewSession.svelte.js');
    expect(getSessionUiPhase({ readiness_state: 'unknown_state' })).toBe('review');
  });

  it('should return "review" for session without readiness_state', async () => {
    const { getSessionUiPhase } = await import('../datasetReviewSession.svelte.js');
    expect(getSessionUiPhase({ id: 's1' })).toBe('review');
  });
});

// #endregion DatasetReviewSessionStoreTests:Module
// #endregion DatasetReviewSessionTests
