import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { OpencodeRuntimePanel } from '@/pages/Models/OpencodeRuntimePanel';

const { opencodeState } = vi.hoisted(() => ({
  opencodeState: {
    status: { state: 'running', port: 4096, url: 'http://127.0.0.1:4096' },
    runtimeConfigSummary: {
      model: 'openai/gpt-5.4',
      smallModel: null,
      providerIds: ['openai'],
      providerCount: 1,
    },
    loading: false,
    error: null,
    refreshStatus: vi.fn(),
    loadRuntimeConfigSummary: vi.fn(),
    restart: vi.fn(),
    start: vi.fn(),
  },
}));

vi.mock('@/stores/opencode', () => ({
  useOpencodeStore: (selector: (state: typeof opencodeState) => unknown) => selector(opencodeState),
}));

vi.mock('react-i18next', () => ({
  useTranslation: () => ({
    t: (key: string, fallback?: string | Record<string, unknown>) => {
      if (typeof fallback === 'string') return fallback;
      return key;
    },
  }),
}));

describe('OpencodeRuntimePanel', () => {
  beforeEach(() => {
    vi.clearAllMocks();
    opencodeState.status = { state: 'running', port: 4096, url: 'http://127.0.0.1:4096' };
    opencodeState.runtimeConfigSummary = {
      model: 'openai/gpt-5.4',
      smallModel: null,
      providerIds: ['openai'],
      providerCount: 1,
    };
    opencodeState.loading = false;
    opencodeState.error = null;
  });

  it('shows runtime status, port, configured model, and provider count', () => {
    render(<OpencodeRuntimePanel />);

    expect(screen.getByText('Makelore runtime')).toBeInTheDocument();
    expect(document.body.textContent).not.toMatch(/opencode/i);
    expect(screen.getByText('running')).toBeInTheDocument();
    expect(screen.getByText('4096')).toBeInTheDocument();
    expect(screen.getByText('openai/gpt-5.4')).toBeInTheDocument();
    expect(screen.getByText('1')).toBeInTheDocument();
    expect(opencodeState.refreshStatus).toHaveBeenCalledOnce();
    expect(opencodeState.loadRuntimeConfigSummary).toHaveBeenCalledOnce();
  });

  it('restarts the runtime from the panel and refreshes the summary', async () => {
    render(<OpencodeRuntimePanel />);

    fireEvent.click(screen.getByRole('button', { name: /restart runtime/i }));

    await waitFor(() => expect(opencodeState.restart).toHaveBeenCalledOnce());
    expect(opencodeState.loadRuntimeConfigSummary).toHaveBeenCalledTimes(2);
  });

  it('starts the runtime when it is stopped', async () => {
    opencodeState.status = { state: 'stopped', port: 4096 };
    render(<OpencodeRuntimePanel />);

    fireEvent.click(screen.getByRole('button', { name: /start runtime/i }));

    await waitFor(() => expect(opencodeState.start).toHaveBeenCalledOnce());
  });
});
