import { render, screen, fireEvent } from '@testing-library/react';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import App from './App';
import { useEngine } from './hooks/useEngine';

vi.mock('./hooks/useEngine', () => ({
  useEngine: vi.fn(),
}));

describe('App Component Integration', () => {
  const mockStart = vi.fn();
  const mockStop = vi.fn();
  const mockLoadProgram = vi.fn();
  const mockNewProgram = vi.fn();
  const mockListPrograms = vi.fn().mockResolvedValue([]);
  const mockSaveCurrentProgram = vi.fn();
  const mockLoadProgramById = vi.fn();
  const mockDeleteProgramById = vi.fn();
  const mockRenameCurrentProgram = vi.fn();

  const mockState = {
    running: false,
    cycle: 0,
    inputs: new Map(),
    outputs: new Map(),
    memory: new Map(),
    timers: new Map(),
    counters: new Map(),
  };

  const mockProgram = {
    name: 'Test Program',
    rungs: [],
    cycleTime: 100,
  };

  beforeEach(() => {
    vi.clearAllMocks();
    (useEngine as any).mockReturnValue({
      state: mockState,
      engine: {},
      program: mockProgram,
      loadProgram: mockLoadProgram,
      start: mockStart,
      stop: mockStop,
      newProgram: mockNewProgram,
      listPrograms: mockListPrograms,
      saveCurrentProgram: mockSaveCurrentProgram,
      loadProgramById: mockLoadProgramById,
      deleteProgramById: mockDeleteProgramById,
      renameCurrentProgram: mockRenameCurrentProgram,
      currentProgramId: null,
    });
  });

  it('renders the app with no program loaded', () => {
    (useEngine as any).mockReturnValue({
      state: mockState,
      engine: {},
      program: null,
      loadProgram: mockLoadProgram,
      start: mockStart,
      stop: mockStop,
      newProgram: mockNewProgram,
      listPrograms: mockListPrograms,
      saveCurrentProgram: mockSaveCurrentProgram,
      loadProgramById: mockLoadProgramById,
      deleteProgramById: mockDeleteProgramById,
      renameCurrentProgram: mockRenameCurrentProgram,
      currentProgramId: null,
    });

    render(<App />);
    expect(screen.getByText(/No program loaded/)).toBeInTheDocument();
  });

  it('renders the ladder when a program is loaded', () => {
    render(<App />);
    expect(screen.getByText('Lego Ladder')).toBeInTheDocument();
  });

  it('calls start when the start button is clicked', () => {
    render(<App />);
    const startButton = screen.getByRole('button', { name: /Start/i });
    fireEvent.click(startButton);
    expect(mockStart).toHaveBeenCalled();
  });

  it('calls stop when the stop button is clicked', () => {
    (useEngine as any).mockReturnValue({
      state: { ...mockState, running: true },
      engine: {},
      program: mockProgram,
      loadProgram: mockLoadProgram,
      start: mockStart,
      stop: mockStop,
      newProgram: mockNewProgram,
      listPrograms: mockListPrograms,
      saveCurrentProgram: mockSaveCurrentProgram,
      loadProgramById: mockLoadProgramById,
      deleteProgramById: mockDeleteProgramById,
      renameCurrentProgram: mockRenameCurrentProgram,
      currentProgramId: null,
    });

    render(<App />);
    const stopButton = screen.getByRole('button', { name: /Stop/i });
    fireEvent.click(stopButton);
    expect(mockStop).toHaveBeenCalled();
  });
});