import { render } from '@testing-library/vue';
import userEvent from '@testing-library/user-event';
import { describe, expect, test } from 'vitest';
import UiFileItem from '../UiFileItem.vue';

describe('UiFileItem', () => {
  test('renders the basename (without extension) and the type | size meta', () => {
    const { container, getByText, getByLabelText } = render(UiFileItem, {
      props: {
        filename: 'doc.pdf',
        typeLabel: 'PDF',
        sizeLabel: '1 MB',
      },
    });
    expect(getByText('doc')).toBeInTheDocument();
    expect(getByLabelText('doc.pdf')).toBeInTheDocument();
    expect(getByText('PDF')).toBeInTheDocument();
    expect(getByText('|')).toBeInTheDocument();
    expect(getByText('1 MB')).toBeInTheDocument();
    // Container uses the muted-subtle surface from the design tokens.
    expect(container.querySelector('[data-slot="file-item"]')).toHaveClass(
      'bg-background-surface-muted-subtle',
    );
  });

  test('leaves dotfile names without extension segment unchanged', () => {
    const { getByText } = render(UiFileItem, {
      props: { filename: '.gitignore' },
    });
    expect(getByText('.gitignore')).toBeInTheDocument();
  });

  test('emits remove when remove control is activated', async () => {
    const user = userEvent.setup();
    const { getByRole, emitted } = render(UiFileItem, {
      props: {
        filename: 'x.txt',
        removeLabel: 'Remove file',
      },
    });
    await user.click(getByRole('button', { name: 'Remove file' }));
    expect(emitted('remove')).toHaveLength(1);
  });

  test('does not render the remove control when removable is false', () => {
    const { queryByRole } = render(UiFileItem, {
      props: {
        filename: 'x.txt',
        removeLabel: 'Remove file',
        removable: false,
      },
    });
    expect(queryByRole('button', { name: 'Remove file' })).toBeNull();
  });

  test('shows error text in the destructive band when error is set', () => {
    const { getByText, getByRole } = render(UiFileItem, {
      props: {
        filename: 'bad.exe',
        error: 'Unsupported file type',
      },
    });
    expect(getByText('Unsupported file type')).toBeInTheDocument();
    expect(getByRole('alert')).toHaveTextContent('Unsupported file type');
  });

  test('hides type/size meta in the error state even when both are set', () => {
    const { queryByText, getByText } = render(UiFileItem, {
      props: {
        filename: 'bad.exe',
        typeLabel: 'EXE',
        sizeLabel: '2 MB',
        error: 'Unsupported',
      },
    });
    // Error state replaces the meta line.
    expect(queryByText('EXE')).toBeNull();
    expect(queryByText('2 MB')).toBeNull();
    expect(getByText('Unsupported')).toBeInTheDocument();
  });

  test('renders a progress bar when progress is between 0 and 100', () => {
    const { container } = render(UiFileItem, {
      props: {
        filename: 'upload.zip',
        progress: 35,
      },
    });
    expect(
      container.querySelector('[data-slot="progress"]'),
    ).toBeInTheDocument();
  });

  test('hides type/size meta while progress is in flight', () => {
    const { queryByText } = render(UiFileItem, {
      props: {
        filename: 'upload.zip',
        typeLabel: 'ZIP',
        sizeLabel: '12 MB',
        progress: 35,
      },
    });
    // Meta is replaced by the progress bar; only the title and bar remain.
    expect(queryByText('ZIP')).toBeNull();
    expect(queryByText('12 MB')).toBeNull();
  });

  test('does not emit remove when disabled', async () => {
    const user = userEvent.setup();
    const { getByRole, emitted } = render(UiFileItem, {
      props: {
        filename: 'x.txt',
        removeLabel: 'Remove file',
        disabled: true,
      },
    });
    const btn = getByRole('button', { name: 'Remove file' });
    expect(btn).toBeDisabled();
    await user.click(btn);
    expect(emitted('remove')).toBeFalsy();
  });

  test('renders a UiFileType badge whose tone matches the filename extension', () => {
    const { container } = render(UiFileItem, {
      props: { filename: 'data.csv' },
    });
    const badge = container.querySelector('[data-slot="file-type"]');
    expect(badge?.getAttribute('data-tone')).toBe('accent-yellow');
  });
});
