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

const apiMocks = vi.hoisted(() => ({
  rawMaterials: vi.fn(),
  mixes: vi.fn(),
  mix: vi.fn(),
  mixCalculatorOptions: vi.fn(),
  mixCalculatorSessions: vi.fn(),
  mixCalculatorSession: vi.fn(),
  products: vi.fn(),
  productCosts: vi.fn(),
  scenarios: vi.fn(),
  dataQuality: vi.fn(),
  dashboardSummary: vi.fn(),
  clientAccess: vi.fn(),
  clientAccessExport: vi.fn()
}));

const sessionMocks = vi.hoisted(() => ({
  getStoredClientSession: vi.fn(),
  hasStoredClientSession: vi.fn(),
  hasStoredAdminSession: vi.fn(),
  hasModuleAccess: vi.fn()
}));

vi.mock('$lib/api', () => ({
  api: apiMocks
}));

vi.mock('$lib/session', () => sessionMocks);

import { load as homeLoad } from './+page';
import { load as mixesLoad } from './mixes/+page';
import { load as mixNewLoad } from './mixes/new/+page';
import { load as mixDetailLoad } from './mixes/[id]/+page';
import { load as mixCalculatorLoad } from './mix-calculator/+page';
import { load as mixCalculatorNewLoad } from './mix-calculator/new/+page';
import { load as mixCalculatorDetailLoad } from './mix-calculator/[id]/+page';
import { load as mixCalculatorPrintLoad } from './mix-calculator/[id]/print/+page';
import { load as productsLoad } from './products/+page';
import { load as rawMaterialsLoad } from './raw-materials/+page';
import { load as scenariosLoad } from './scenarios/+page';

describe('route loaders use the SvelteKit fetch argument', () => {
  const fetcher = vi.fn() as typeof fetch;

  beforeEach(() => {
    vi.clearAllMocks();
    sessionMocks.hasStoredClientSession.mockReturnValue(true);
    sessionMocks.hasStoredAdminSession.mockReturnValue(true);
    sessionMocks.getStoredClientSession.mockReturnValue({ role: 'client', module_permissions: {} });
    sessionMocks.hasModuleAccess.mockReturnValue(true);

    apiMocks.rawMaterials.mockResolvedValue([{ id: 1 }]);
    apiMocks.mixes.mockResolvedValue([{ id: 2 }]);
    apiMocks.mix.mockResolvedValue({ id: 42 });
    apiMocks.mixCalculatorOptions.mockResolvedValue({ clients: ['Hunter Premium Produce'], products: [{ product_id: 1 }] });
    apiMocks.mixCalculatorSessions.mockResolvedValue([{ id: 11 }]);
    apiMocks.mixCalculatorSession.mockResolvedValue({ id: 12 });
    apiMocks.products.mockResolvedValue([{ id: 3 }]);
    apiMocks.productCosts.mockResolvedValue([{ id: 4 }]);
    apiMocks.scenarios.mockResolvedValue([{ id: 5 }]);
    apiMocks.dataQuality.mockResolvedValue([{ id: 6 }]);
    apiMocks.dashboardSummary.mockResolvedValue({
      raw_materials: null,
      mixes: null,
      products: null,
      trend_seeds: { raw_material_cost_per_kg: [], mix_cost_per_kg: [], product_finished_delivered: [] },
      operations: null
    });
    apiMocks.clientAccess.mockResolvedValue([{ id: 7 }]);
    apiMocks.clientAccessExport.mockResolvedValue({
      generated_at: '',
      client_rows: [],
      user_rows: [],
      feature_rows: [],
      permission_rows: [],
      audit_rows: [],
      clients: []
    });
  });

  it('passes fetch through the home page loader', async () => {
    const result = homeLoad({ fetch: fetcher } as never);
    await result.summary;

    expect(apiMocks.dashboardSummary).toHaveBeenCalledWith(fetcher);
  });

  it('passes fetch through the raw materials loader', async () => {
    await rawMaterialsLoad({ fetch: fetcher } as never);

    expect(apiMocks.rawMaterials).toHaveBeenCalledWith(fetcher);
    expect(apiMocks.mixes).toHaveBeenCalledWith(fetcher);
    expect(apiMocks.products).toHaveBeenCalledWith(fetcher);
    expect(apiMocks.productCosts).toHaveBeenCalledWith(fetcher);
  });

  it('passes fetch through the mixes loader', async () => {
    await mixesLoad({ fetch: fetcher } as never);

    expect(apiMocks.mixes).toHaveBeenCalledWith(fetcher);
  });

  it('passes fetch through the new mix loader', async () => {
    await mixNewLoad({ fetch: fetcher } as never);

    expect(apiMocks.rawMaterials).toHaveBeenCalledWith(fetcher);
  });

  it('passes fetch through the mix detail loader', async () => {
    await mixDetailLoad({ params: { id: '42' }, fetch: fetcher } as never);

    expect(apiMocks.mix).toHaveBeenCalledWith(42, fetcher);
    expect(apiMocks.rawMaterials).toHaveBeenCalledWith(fetcher);
  });

  it('passes fetch through the products loader', async () => {
    await productsLoad({ fetch: fetcher } as never);

    expect(apiMocks.products).toHaveBeenCalledWith(fetcher);
    expect(apiMocks.productCosts).toHaveBeenCalledWith(fetcher);
  });

  it('passes fetch through the mix calculator loader', async () => {
    await mixCalculatorLoad({ fetch: fetcher } as never);

    expect(apiMocks.mixCalculatorOptions).toHaveBeenCalledWith(fetcher);
  });

  it('passes fetch through the new mix calculator loader', async () => {
    await mixCalculatorNewLoad({ fetch: fetcher } as never);

    expect(apiMocks.mixCalculatorOptions).toHaveBeenCalledWith(fetcher);
  });

  it('passes fetch through the mix calculator detail loader', async () => {
    await mixCalculatorDetailLoad({ params: { id: '12' }, fetch: fetcher } as never);

    expect(apiMocks.mixCalculatorSession).toHaveBeenCalledWith(12, fetcher);
    expect(apiMocks.mixCalculatorOptions).toHaveBeenCalledWith(fetcher);
  });

  it('passes fetch through the mix calculator print loader', async () => {
    await mixCalculatorPrintLoad({ params: { id: '12' }, fetch: fetcher } as never);

    expect(apiMocks.mixCalculatorSession).toHaveBeenCalledWith(12, fetcher);
  });

  it('passes fetch through the scenarios loader', async () => {
    await scenariosLoad({ fetch: fetcher } as never);

    expect(apiMocks.scenarios).toHaveBeenCalledWith(fetcher);
  });
});
