/**
 * L1 — the DI provider resolves real vs mock gateways from `VITE_USE_MOCK`,
 * and `useGateways` exposes the injected set (and guards against misuse).
 */
import { describe, it, expect, afterEach, vi } from "vitest";
import { render, screen, renderHook } from "@testing-library/react";

import { MockSystemGateway } from "@/adapters/mock";
import { DIProvider, useGateways, resolveGateways, shouldUseMock } from "./di";

afterEach(() => {
  vi.unstubAllEnvs();
});

describe("shouldUseMock / resolveGateways", () => {
  it("returns mock gateways when VITE_USE_MOCK=1", () => {
    vi.stubEnv("VITE_USE_MOCK", "1");
    expect(shouldUseMock()).toBe(true);
    expect(resolveGateways().system).toBeInstanceOf(MockSystemGateway);
  });

  it("returns mock gateways when VITE_USE_MOCK=true", () => {
    vi.stubEnv("VITE_USE_MOCK", "true");
    expect(shouldUseMock()).toBe(true);
  });

  it("returns real (non-mock) gateways otherwise", () => {
    vi.stubEnv("VITE_USE_MOCK", "");
    expect(shouldUseMock()).toBe(false);
    // Real adapter is not the mock implementation.
    expect(resolveGateways().system).not.toBeInstanceOf(MockSystemGateway);
  });
});

describe("DIProvider / useGateways", () => {
  it("provides explicit gateways to consumers", () => {
    const gateways = resolveGatewaysMock();
    const { result } = renderHook(() => useGateways(), {
      wrapper: ({ children }) => (
        <DIProvider gateways={gateways}>{children}</DIProvider>
      ),
    });
    expect(result.current).toBe(gateways);
  });

  it("renders children inside the provider", () => {
    render(
      <DIProvider gateways={resolveGatewaysMock()}>
        <span>ok</span>
      </DIProvider>,
    );
    expect(screen.getByText("ok")).toBeTruthy();
  });

  it("throws when useGateways is used outside a provider", () => {
    expect(() => renderHook(() => useGateways())).toThrow(
      /must be used within a <DIProvider>/,
    );
  });
});

function resolveGatewaysMock() {
  vi.stubEnv("VITE_USE_MOCK", "1");
  const g = resolveGateways();
  vi.unstubAllEnvs();
  return g;
}
