// Tests for getBackend/setBackend/setBackendForTesting lifecycle

import { describe, it, expect, beforeEach } from 'vitest';
import {
  getBackend,
  setBackend,
  setBackendForTesting,
  resetBackendForTesting,
} from '../backend';
import type { BackendAdapter } from '@agor/types';

beforeEach(() => {
  resetBackendForTesting();
});

describe('backend singleton', () => {
  describe('getBackend', () => {
    it('throws before setBackend is called', () => {
      expect(() => getBackend()).toThrow(
        '[backend] Adapter not initialized. Call setBackend() before accessing the backend.'
      );
    });

    it('returns adapter after setBackend', () => {
      const mockAdapter = { capabilities: {} } as unknown as BackendAdapter;
      setBackend(mockAdapter);
      expect(getBackend()).toBe(mockAdapter);
    });
  });

  describe('setBackend', () => {
    it('sets the adapter on first call', () => {
      const mockAdapter = { capabilities: {} } as unknown as BackendAdapter;
      setBackend(mockAdapter);
      expect(getBackend()).toBe(mockAdapter);
    });

    it('throws on second call', () => {
      const adapter1 = { capabilities: {} } as unknown as BackendAdapter;
      const adapter2 = { capabilities: {} } as unknown as BackendAdapter;
      setBackend(adapter1);
      expect(() => setBackend(adapter2)).toThrow(
        '[backend] Adapter already set. setBackend() must be called exactly once.'
      );
    });
  });

  describe('setBackendForTesting', () => {
    it('works before setBackend', () => {
      const partial = { getSetting: async () => 'test' };
      setBackendForTesting(partial);
      expect(getBackend().getSetting).toBeDefined();
    });

    it('allows overwrite (no single-set enforcement)', () => {
      const partial1 = { getSetting: async () => 'v1' };
      const partial2 = { getSetting: async () => 'v2' };
      setBackendForTesting(partial1);
      setBackendForTesting(partial2);
      // Should use second one
      expect(getBackend()).toBe(partial2 as unknown as BackendAdapter);
    });

    it('allows overwrite even after setBackend', () => {
      const adapter = { capabilities: {} } as unknown as BackendAdapter;
      setBackend(adapter);
      const partial = { getSetting: async () => 'test' };
      // setBackendForTesting bypasses single-set check
      setBackendForTesting(partial);
      expect(getBackend()).toBe(partial as unknown as BackendAdapter);
    });
  });

  describe('resetBackendForTesting', () => {
    it('resets to uninitialized state', () => {
      const adapter = { capabilities: {} } as unknown as BackendAdapter;
      setBackend(adapter);
      resetBackendForTesting();
      expect(() => getBackend()).toThrow();
    });

    it('allows setBackend after reset', () => {
      const adapter1 = { capabilities: {} } as unknown as BackendAdapter;
      const adapter2 = { capabilities: { supportsPtyMultiplexing: true } } as unknown as BackendAdapter;
      setBackend(adapter1);
      resetBackendForTesting();
      setBackend(adapter2);
      expect(getBackend()).toBe(adapter2);
    });
  });
});
