import { FunctionComponent } from 'react';
import { render, screen, within } from '@testing-library/react';
import { ThemeProvider } from '../../../theme';
import AppButton, { AppButtonProps } from './AppButton';
import DefaultIcon from '@mui/icons-material/MoreHoriz';
import { randomText, capitalize } from '@/utils';

/**
 * AppButton wrapped with Theme Provider
 */
const ComponentToTest: FunctionComponent<AppButtonProps> = (props) => (
  <ThemeProvider>
    <AppButton {...props} />
  </ThemeProvider>
);

/**
 * Test specific color for AppButton
 * @param {string} colorName - name of the color, one of ColorName type
 * @param {string} [expectedClassName] - optional value to be found in className (color "true" may use "success" class name)
 * @param {boolean} [ignoreClassName] - optional flag to ignore className (color "inherit" doesn't use any class name)
 */
function testButtonColor(colorName: string, ignoreClassName = false, expectedClassName = colorName) {
  it(`supports "${colorName}" color`, () => {
    const testId = randomText(8);
    let text = `${colorName} button`;
    render(
      <ComponentToTest
        color={colorName}
        data-testid={testId}
        variant="contained" // Required to get correct CSS class name
      >
        {text}
      </ComponentToTest>
    );

    let button = screen.getByTestId(testId);
    expect(button).toBeDefined();
    // console.log('button.className:', button?.className);
    if (!ignoreClassName) {
      // MUI v9: color and variant are separate classes (no more MuiButton-containedPrimary)
      expect(button?.className?.includes('MuiButton-root')).toBeTruthy();
      expect(button?.className?.includes('MuiButton-contained')).toBeTruthy();
      expect(button?.className?.includes(`MuiButton-color${capitalize(expectedClassName)}`)).toBeTruthy();
    }
  });
}

describe('<AppButton/> component', () => {
  //   beforeEach(() => {});

  it('renders itself', () => {
    let text = 'sample button';
    const testId = randomText(8);
    render(<ComponentToTest data-testid={testId}>{text}</ComponentToTest>);
    const button = screen.getByTestId(testId);
    expect(button).toBeDefined();
    // MUI v9: native <button> has implicit role; no explicit role attr on semantic elements
    expect(button).toHaveRole('button');
    expect(button).toHaveAttribute('type', 'button'); // not "submit" or "input" by default
  });

  it('does not force a default margin, and passes a custom sx through untouched', () => {
    const testId = randomText(8);
    render(
      <ComponentToTest data-testid={testId} sx={{ marginInlineStart: 2 }}>
        button with custom sx
      </ComponentToTest>
    );
    const button = screen.getByTestId(testId);
    expect(button).toBeDefined();
    // Regression guard for the removed starter DEFAULT_SX_VALUES={ margin: 1 }:
    // AppButton must not silently drop or merge over a caller-provided sx.
    expect(button).toHaveClass('MuiButton-root');
  });

  it('supports .className property', () => {
    let text = 'button with specific class';
    let className = 'someClassName';
    const testId = randomText(8);
    render(
      <ComponentToTest data-testid={testId} className={className}>
        {text}
      </ComponentToTest>
    );
    const button = screen.getByTestId(testId);
    expect(button).toBeDefined();
    expect(button).toHaveClass(className);
  });

  it('supports .label property', () => {
    let text = 'button with label';
    render(<ComponentToTest label={text} />);
    let span = screen.getByText(text);
    expect(span).toBeDefined();
    let button = span.closest('button'); // parent <button> element
    expect(button).toBeDefined();
  });

  it('supports .text property', () => {
    let text = 'button with text';
    render(<ComponentToTest text={text} />);
    let span = screen.getByText(text);
    expect(span).toBeDefined();
    let button = span.closest('button'); // parent <button> element
    expect(button).toBeDefined();
  });

  it('supports .startIcon property as <svg/>', () => {
    let text = 'button with start icon';
    render(<ComponentToTest text={text} startIcon={<DefaultIcon data-testid="startIcon" />} />);
    let button = screen.getByText(text);
    let icon = within(button).getByTestId('startIcon');
    expect(icon).toBeDefined();
    let span = icon.closest('span');
    expect(span).toHaveClass('MuiButton-startIcon');
  });

  it('supports .endIcon property', () => {
    let text = 'button with end icon as <svg/>';
    render(<ComponentToTest text={text} endIcon={<DefaultIcon data-testid="endIcon" />} />);
    let button = screen.getByText(text);
    let icon = within(button).getByTestId('endIcon');
    expect(icon).toBeDefined();
    let span = icon.closest('span');
    expect(span).toHaveClass('MuiButton-endIcon');
  });

  it('supports .startIcon property as string', () => {
    let text = 'button with start icon';
    render(<ComponentToTest text={text} startIcon="default" />);
    let button = screen.getByText(text);
    let icon = within(button).getByTestId('MoreHorizRoundedIcon'); //Note: this is valid only when "default" icon is <MoreHorizRoundedIcon />
    expect(icon).toBeDefined();
    let span = icon.closest('span');
    expect(span).toHaveClass('MuiButton-startIcon');
  });

  it('supports .endIcon property', () => {
    let text = 'button with end icon as string';
    render(<ComponentToTest text={text} endIcon="default" />);
    let button = screen.getByText(text);
    let icon = within(button).getByTestId('MoreHorizRoundedIcon'); //Note: this is valid only when "default" icon is <MoreHorizRoundedIcon />
    expect(icon).toBeDefined();
    let span = icon.closest('span');
    expect(span).toHaveClass('MuiButton-endIcon');
  });

  // MUI colors
  testButtonColor('inherit');
  testButtonColor('primary');
  testButtonColor('secondary');
  testButtonColor('error');
  testButtonColor('warning');
  testButtonColor('info');
  testButtonColor('success');

  // Non-MUI colors
  testButtonColor('green', true);
  testButtonColor('#FF00FF', true);
  testButtonColor('rgba(255, 0, 0, 0.5)', true);
});
