import { describe, it, expect, vi, beforeEach } from 'vitest';
import { render, screen, fireEvent, act } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { ThemeProvider } from '@cameleer/design-system';
import type { ReactNode } from 'react';
import { StartupLogPanel } from './StartupLogPanel';
import type { Deployment } from '../api/queries/admin/apps';
import * as logsModule from '../api/queries/logs';

function wrap(ui: ReactNode) {
  const qc = new QueryClient({ defaultOptions: { queries: { retry: false } } });
  return render(
    <ThemeProvider>
      <QueryClientProvider client={qc}>{ui}</QueryClientProvider>
    </ThemeProvider>,
  );
}

const baseDep: Deployment = {
  id: 'dep1', appId: 'a', appVersionId: 'v', environmentId: 'e',
  status: 'STARTING', targetState: 'RUNNING', deploymentStrategy: 'BLUE_GREEN',
  replicaStates: [], deployStage: 'START_REPLICAS',
  containerId: null, containerName: null, errorMessage: null,
  deployedAt: null, stoppedAt: null,
  createdAt: '2026-04-23T10:00:00Z', createdBy: null,
};

const entries = [
  { timestamp: '2026-04-23T10:00:01Z', level: 'INFO' as const, message: 'hello',
    loggerName: null, threadName: null, stackTrace: null, exchangeId: null,
    instanceId: null, application: null, mdc: null, source: 'container' as const },
];

describe('StartupLogPanel', () => {
  beforeEach(() => { vi.restoreAllMocks(); });

  it('passes default sort=desc to useStartupLogs', () => {
    const spy = vi.spyOn(logsModule, 'useStartupLogs').mockReturnValue({
      data: { data: entries, nextCursor: null, hasMore: false, levelCounts: {} },
    } as ReturnType<typeof logsModule.useStartupLogs>);
    wrap(<StartupLogPanel deployment={baseDep} appSlug="app" envSlug="dev" />);
    expect(spy).toHaveBeenCalledWith('app', 'dev', '2026-04-23T10:00:00Z', true, 'desc');
  });

  it('toggle flips sort to asc', () => {
    const spy = vi.spyOn(logsModule, 'useStartupLogs').mockReturnValue({
      data: { data: entries, nextCursor: null, hasMore: false, levelCounts: {} },
    } as ReturnType<typeof logsModule.useStartupLogs>);
    wrap(<StartupLogPanel deployment={baseDep} appSlug="app" envSlug="dev" />);
    fireEvent.click(screen.getByRole('button', { name: /oldest first|newest first/i }));
    expect(spy).toHaveBeenLastCalledWith('app', 'dev', '2026-04-23T10:00:00Z', true, 'asc');
  });

  it('refresh button calls refetch', () => {
    const refetch = vi.fn();
    vi.spyOn(logsModule, 'useStartupLogs').mockReturnValue({
      data: { data: entries, nextCursor: null, hasMore: false, levelCounts: {} },
      refetch,
    } as unknown as ReturnType<typeof logsModule.useStartupLogs>);
    wrap(<StartupLogPanel deployment={baseDep} appSlug="app" envSlug="dev" />);
    fireEvent.click(screen.getByRole('button', { name: /refresh/i }));
    expect(refetch).toHaveBeenCalled();
  });

  it('scrolls to top after refresh when sort=desc', async () => {
    const refetch = vi.fn().mockResolvedValue({});
    vi.spyOn(logsModule, 'useStartupLogs').mockReturnValue({
      data: { data: entries, nextCursor: null, hasMore: false, levelCounts: {} },
      refetch,
    } as unknown as ReturnType<typeof logsModule.useStartupLogs>);
    const scrollTo = vi.fn();
    const origScrollTo = Element.prototype.scrollTo;
    Element.prototype.scrollTo = scrollTo as unknown as typeof Element.prototype.scrollTo;
    try {
      wrap(<StartupLogPanel deployment={baseDep} appSlug="app" envSlug="dev" />);
      await act(async () => {
        fireEvent.click(screen.getByRole('button', { name: /refresh/i }));
        await Promise.resolve();
      });
      // default sort is desc → scroll to top (top === 0)
      expect(scrollTo).toHaveBeenCalledWith(expect.objectContaining({ top: 0 }));
    } finally {
      Element.prototype.scrollTo = origScrollTo;
    }
  });
});
