import { StrictMode } from 'react';
import { act, renderHook } from '@testing-library/react';
import { describe, expect, it } from 'vitest';

import { useServerDraft } from '@/hooks/useServerDraft';

describe('useServerDraft', () => {
  it('keeps an edited draft when the server refetches', () => {
    const { result, rerender } = renderHook(
      ({ server }) =>
        useServerDraft(
          server,
          (value) => ({ ...value }),
          (left, right) => left.value === right.value,
        ),
      { initialProps: { server: { value: 'one' } } },
    );

    act(() => result.current.setDraft({ value: 'edited' }));
    rerender({ server: { value: 'two' } });

    expect(result.current.draft).toEqual({ value: 'edited' });
    expect(result.current.isDirty).toBe(true);
  });

  it('accepts a refetch that matches the saved draft', () => {
    const { result, rerender } = renderHook(
      ({ server }) =>
        useServerDraft(
          server,
          (value) => ({ ...value }),
          (left, right) => left.value === right.value,
        ),
      { initialProps: { server: { value: 'one' } } },
    );

    act(() => result.current.setDraft({ value: 'saved' }));
    rerender({ server: { value: 'saved' } });

    expect(result.current.draft).toEqual({ value: 'saved' });
    expect(result.current.isDirty).toBe(false);
  });

  it('compares a preserved draft with the latest server value', () => {
    const { result, rerender } = renderHook(
      ({ server }) =>
        useServerDraft(
          server,
          (value) => ({ ...value }),
          (left, right) => left.value === right.value,
        ),
      { initialProps: { server: { value: 'one' } } },
    );

    act(() => result.current.setDraft({ value: 'later' }));
    rerender({ server: { value: 'saved' } });
    act(() => result.current.setDraft({ value: 'one' }));

    expect(result.current.isDirty).toBe(true);
  });

  it('hydrates clean drafts under StrictMode', () => {
    const { result, rerender } = renderHook(
      ({ server }) =>
        useServerDraft(
          server,
          (value) => ({ ...value }),
          (left, right) => left.value === right.value,
        ),
      {
        initialProps: { server: { value: 'one' } },
        wrapper: StrictMode,
      },
    );

    rerender({ server: { value: 'two' } });

    expect(result.current.draft).toEqual({ value: 'two' });
    expect(result.current.isDirty).toBe(false);
  });

  it('preserves an edit made before the first server response', () => {
    const { result, rerender } = renderHook(
      ({ server }) =>
        useServerDraft(
          server,
          (value) => ({ ...value }),
          (left, right) => left.value === right.value,
        ),
      { initialProps: { server: undefined as { value: string } | undefined } },
    );

    act(() => result.current.setDraft({ value: 'edited' }));
    rerender({ server: { value: 'one' } });

    expect(result.current.draft).toEqual({ value: 'edited' });
    expect(result.current.isDirty).toBe(true);
  });

  it('marks a sent draft clean before its refetch arrives', () => {
    const { result } = renderHook(
      ({ server }) =>
        useServerDraft(
          server,
          (value) => ({ ...value }),
          (left, right) => left.value === right.value,
        ),
      { initialProps: { server: { value: 'one' } } },
    );

    act(() => result.current.setDraft({ value: 'saved' }));
    act(() => result.current.markSaved({ value: 'saved' }));

    expect(result.current.isDirty).toBe(false);
  });
});
