import { describe, it, expect, vi } from 'vitest';
import { render, screen, fireEvent } from '@testing-library/react';
import { ThemeProvider } from '@cameleer/design-system';
import type { ReactNode } from 'react';
import { CheckpointsTable } from './CheckpointsTable';
import type { Deployment, AppVersion } from '../../../api/queries/admin/apps';

function wrap(ui: ReactNode) {
  return render(<ThemeProvider>{ui}</ThemeProvider>);
}

const v6: AppVersion = {
  id: 'v6id', appId: 'a', version: 6, jarPath: '/j', jarChecksum: 'c',
  jarFilename: 'my-app-1.2.3.jar', jarSizeBytes: 1, detectedRuntimeType: null,
  detectedMainClass: null, uploadedAt: '2026-04-23T10:00:00Z',
};

const stoppedDep: Deployment = {
  id: 'd1', appId: 'a', appVersionId: 'v6id', environmentId: 'e',
  status: 'STOPPED', targetState: 'STOPPED', deploymentStrategy: 'BLUE_GREEN',
  replicaStates: [{ index: 0, containerId: 'c', containerName: 'n', status: 'STOPPED' }],
  deployStage: null, containerId: null, containerName: null, errorMessage: null,
  deployedAt: '2026-04-23T10:35:00Z', stoppedAt: '2026-04-23T10:52:00Z',
  createdAt: '2026-04-23T10:35:00Z', createdBy: 'alice',
  deployedConfigSnapshot: { jarVersionId: 'v6id', agentConfig: null, containerConfig: {}, sensitiveKeys: null },
};

function expand() {
  fireEvent.click(screen.getByRole('button', { name: /expand|collapse/i }));
}

describe('CheckpointsTable', () => {
  it('defaults to collapsed — label + trigger visible, rows hidden', () => {
    wrap(<CheckpointsTable deployments={[stoppedDep]} versions={[v6]}
      currentDeploymentId={null} jarRetentionCount={5} onSelect={() => {}} />);
    expect(screen.getByText('Checkpoints')).toBeInTheDocument();
    expect(screen.getByRole('button', { name: /expand \(1\)/i })).toBeInTheDocument();
    expect(screen.queryByText('v6')).toBeNull();
    expect(screen.queryByText('my-app-1.2.3.jar')).toBeNull();
  });

  it('clicking trigger expands to show rows; label flips to Collapse', () => {
    wrap(<CheckpointsTable deployments={[stoppedDep]} versions={[v6]}
      currentDeploymentId={null} jarRetentionCount={5} onSelect={() => {}} />);
    expand();
    expect(screen.getByText('v6')).toBeInTheDocument();
    expect(screen.getByText('my-app-1.2.3.jar')).toBeInTheDocument();
    expect(screen.getByText('alice')).toBeInTheDocument();
    expect(screen.getByRole('button', { name: /collapse \(1\)/i })).toBeInTheDocument();
  });

  it('row click invokes onSelect with deploymentId', () => {
    const onSelect = vi.fn();
    wrap(<CheckpointsTable deployments={[stoppedDep]} versions={[v6]}
      currentDeploymentId={null} jarRetentionCount={5} onSelect={onSelect} />);
    expand();
    fireEvent.click(screen.getByText('v6').closest('tr')!);
    expect(onSelect).toHaveBeenCalledWith('d1');
  });

  it('renders em-dash for null createdBy', () => {
    const noActor = { ...stoppedDep, createdBy: null };
    wrap(<CheckpointsTable deployments={[noActor]} versions={[v6]}
      currentDeploymentId={null} jarRetentionCount={5} onSelect={() => {}} />);
    expand();
    expect(screen.getByText('—')).toBeInTheDocument();
  });

  it('marks pruned-JAR rows as archived', () => {
    const pruned = { ...stoppedDep, appVersionId: 'unknown' };
    wrap(<CheckpointsTable deployments={[pruned]} versions={[]}
      currentDeploymentId={null} jarRetentionCount={5} onSelect={() => {}} />);
    expand();
    expect(screen.getByText(/archived/i)).toBeInTheDocument();
  });

  it('renders nothing when there are no checkpoints', () => {
    const { container } = wrap(<CheckpointsTable deployments={[stoppedDep]} versions={[v6]}
      currentDeploymentId="d1" jarRetentionCount={5} onSelect={() => {}} />);
    expect(container).toBeEmptyDOMElement();
  });

  it('caps visible rows at jarRetentionCount and shows expander', () => {
    const many: Deployment[] = Array.from({ length: 10 }, (_, i) => ({
      ...stoppedDep, id: `d${i}`, deployedAt: `2026-04-23T10:${String(10 + i).padStart(2, '0')}:00Z`,
    }));
    wrap(<CheckpointsTable deployments={many} versions={[v6]}
      currentDeploymentId={null} jarRetentionCount={3} onSelect={() => {}} />);
    expand();
    expect(screen.getAllByRole('row').length).toBeLessThanOrEqual(4);
    expect(screen.getByText(/show older \(7\)/i)).toBeInTheDocument();
  });

  it('shows all rows when jarRetentionCount >= total', () => {
    wrap(<CheckpointsTable deployments={[stoppedDep]} versions={[v6]}
      currentDeploymentId={null} jarRetentionCount={10} onSelect={() => {}} />);
    expand();
    expect(screen.queryByText(/show older/i)).toBeNull();
  });

  it('falls back to default cap of 10 when jarRetentionCount is 0 or null', () => {
    const fifteen: Deployment[] = Array.from({ length: 15 }, (_, i) => ({
      ...stoppedDep, id: `d${i}`, deployedAt: `2026-04-23T10:${String(10 + i).padStart(2, '0')}:00Z`,
    }));
    wrap(<CheckpointsTable deployments={fifteen} versions={[v6]}
      currentDeploymentId={null} jarRetentionCount={null} onSelect={() => {}} />);
    expand();
    expect(screen.getByText(/show older \(5\)/i)).toBeInTheDocument();
  });

  it('Deployed sub-line is locale-formatted (not the raw ISO)', () => {
    wrap(<CheckpointsTable deployments={[stoppedDep]} versions={[v6]}
      currentDeploymentId={null} jarRetentionCount={5} onSelect={() => {}} />);
    expand();
    // Raw ISO would contain 'T' and end in 'Z' — localized form must not.
    const raw = '2026-04-23T10:35:00Z';
    expect(screen.queryByText(raw)).toBeNull();
    // Use the createdBy cell as an anchor and walk to the sibling Deployed cell.
    const row = screen.getByText('alice').closest('tr')!;
    const cells = row.querySelectorAll('td');
    // Column order: Version, JAR, Deployed by, Deployed, Strategy, Outcome, chevron
    const deployedCell = cells[3];
    expect(deployedCell).toBeDefined();
    const text = deployedCell.textContent ?? '';
    expect(text).not.toContain('T10:35');
    expect(text).not.toContain('Z');
    expect(text.length).toBeGreaterThan(0);
  });
});
