import {AutofixCodebaseChangeData} from 'sentry-fixture/autofixCodebaseChangeData';
import {AutofixStepFixture} from 'sentry-fixture/autofixStep';

import {
  render,
  renderGlobalModal,
  screen,
  userEvent,
  waitFor,
  within,
} from 'sentry-test/reactTestingLibrary';

import {addErrorMessage, addSuccessMessage} from 'sentry/actionCreators/indicator';
import AutofixMessageBox from 'sentry/components/events/autofix/autofixMessageBox';
import {AutofixStatus, AutofixStepType} from 'sentry/components/events/autofix/types';

jest.mock('sentry/actionCreators/indicator');

describe('AutofixMessageBox', () => {
  const defaultProps = {
    displayText: 'Test display text',
    groupId: '123',
    runId: '456',
    actionText: 'Send',
    allowEmptyMessage: false,
    responseRequired: false,
    step: null,
    onSend: null,
  };

  const changesStepProps = {
    ...defaultProps,
    isChangesStep: true,
    step: AutofixStepFixture({
      type: AutofixStepType.CHANGES,
      changes: [AutofixCodebaseChangeData()],
    }),
  };

  const prCreatedProps = {
    ...changesStepProps,
    step: AutofixStepFixture({
      type: AutofixStepType.CHANGES,
      status: AutofixStatus.COMPLETED,
      changes: [AutofixCodebaseChangeData()],
    }),
  };

  const multiplePRsProps = {
    ...changesStepProps,
    step: AutofixStepFixture({
      type: AutofixStepType.CHANGES,
      status: AutofixStatus.COMPLETED,
      changes: [
        AutofixCodebaseChangeData({
          repo_name: 'example/repo1',
          pull_request: {
            pr_url: 'https://github.com/example/repo1/pull/1',
            pr_number: 1,
          },
        }),
        AutofixCodebaseChangeData({
          repo_name: 'example/repo1',
          pull_request: {
            pr_url: 'https://github.com/example/repo2/pull/2',
            pr_number: 2,
          },
        }),
      ],
    }),
  };

  beforeEach(() => {
    (addSuccessMessage as jest.Mock).mockClear();
    (addErrorMessage as jest.Mock).mockClear();
    MockApiClient.clearMockResponses();

    MockApiClient.addMockResponse({
      url: '/issues/123/autofix/setup/?check_write_access=true',
      method: 'GET',
      body: {
        genAIConsent: {ok: true},
        integration: {ok: true},
      },
    });
  });

  it('renders correctly with default props', () => {
    render(<AutofixMessageBox {...defaultProps} />);

    expect(screen.getByText('Test display text')).toBeInTheDocument();
    expect(
      screen.getByPlaceholderText('Share helpful context or directions...')
    ).toBeInTheDocument();
    expect(screen.getByRole('button', {name: 'Send'})).toBeInTheDocument();
  });

  it('calls onSend when provided and button is clicked', async () => {
    const onSendMock = jest.fn();
    render(<AutofixMessageBox {...defaultProps} onSend={onSendMock} />);

    const input = screen.getByPlaceholderText('Share helpful context or directions...');
    await userEvent.type(input, 'Test message');
    await userEvent.click(screen.getByRole('button', {name: 'Send'}));

    expect(onSendMock).toHaveBeenCalledWith('Test message');
  });

  it('sends interjection message when onSend is not provided', async () => {
    MockApiClient.addMockResponse({
      method: 'POST',
      url: '/issues/123/autofix/update/',
      body: {},
    });

    render(<AutofixMessageBox {...defaultProps} />);

    const input = screen.getByPlaceholderText('Share helpful context or directions...');
    await userEvent.type(input, 'Test message');
    await userEvent.click(screen.getByRole('button', {name: 'Send'}));

    await waitFor(() => {
      expect(addSuccessMessage).toHaveBeenCalledWith('Thanks for the input.');
    });
  });

  it('displays error message when API request fails', async () => {
    MockApiClient.addMockResponse({
      url: '/issues/123/autofix/update/',
      method: 'POST',
      body: {
        detail: 'Internal Error',
      },
      statusCode: 500,
    });

    render(<AutofixMessageBox {...defaultProps} />);

    const input = screen.getByPlaceholderText('Share helpful context or directions...');
    await userEvent.type(input, 'Test message');
    await userEvent.click(screen.getByRole('button', {name: 'Send'}));

    await waitFor(() => {
      expect(addErrorMessage).toHaveBeenCalledWith(
        'Something went wrong when sending Autofix your message.'
      );
    });
  });

  it('renders step icon and title when step is provided', () => {
    const stepProps = {
      ...defaultProps,
      step: AutofixStepFixture(),
    };

    render(<AutofixMessageBox {...stepProps} />);

    expect(screen.getByText(AutofixStepFixture().title)).toBeInTheDocument();
  });

  it('renders required input style when responseRequired is true', () => {
    render(<AutofixMessageBox {...defaultProps} responseRequired />);

    expect(
      screen.getByPlaceholderText('Please answer to continue...')
    ).toBeInTheDocument();
  });

  it('handles suggested root cause selection correctly', async () => {
    const onSendMock = jest.fn();
    render(
      <AutofixMessageBox {...defaultProps} onSend={onSendMock} isRootCauseSelectionStep />
    );

    // Test suggested root cause
    await userEvent.click(screen.getByRole('button', {name: 'Use suggested root cause'}));
    const input = screen.getByPlaceholderText(
      '(Optional) Provide any instructions for the fix...'
    );
    await userEvent.type(input, 'Use this suggestion');
    await userEvent.click(screen.getByRole('button', {name: 'Send'}));

    expect(onSendMock).toHaveBeenCalledWith('Use this suggestion', false);
  });

  it('handles custom root cause selection correctly', async () => {
    const onSendMock = jest.fn();
    render(
      <AutofixMessageBox {...defaultProps} onSend={onSendMock} isRootCauseSelectionStep />
    );

    // Test custom root cause
    await userEvent.click(
      screen.getByRole('button', {name: 'Propose your own root cause'})
    );
    const customInput = screen.getByPlaceholderText('Propose your own root cause...');
    await userEvent.type(customInput, 'Custom root cause');
    await userEvent.click(screen.getByRole('button', {name: 'Send'}));

    expect(onSendMock).toHaveBeenCalledWith('Custom root cause', true);
  });

  it('renders segmented control for changes step', () => {
    render(<AutofixMessageBox {...changesStepProps} />);

    expect(screen.getByRole('button', {name: 'Iterate'})).toBeInTheDocument();
    expect(screen.getByRole('button', {name: 'Use this code'})).toBeInTheDocument();
    expect(screen.getByRole('button', {name: 'Add tests'})).toBeInTheDocument();
  });

  it('shows feedback input when "Iterate" is selected', async () => {
    render(<AutofixMessageBox {...changesStepProps} />);

    await userEvent.click(screen.getByRole('button', {name: 'Iterate'}));

    expect(
      screen.getByPlaceholderText('Share helpful context or directions...')
    ).toBeInTheDocument();
    expect(screen.getByRole('button', {name: 'Send'})).toBeInTheDocument();
  });

  it('shows "Draft PR" button when "Approve" is selected', async () => {
    MockApiClient.addMockResponse({
      url: '/issues/123/autofix/setup/?check_write_access=true',
      method: 'GET',
      body: {
        genAIConsent: {ok: true},
        integration: {ok: true},
        githubWriteIntegration: {
          repos: [{ok: true, owner: 'owner', name: 'hello-world', id: 100}],
        },
      },
    });

    render(<AutofixMessageBox {...changesStepProps} />);

    await userEvent.click(screen.getByRole('button', {name: 'Use this code'}));

    expect(screen.getByText('Push the above changes to a branch?')).toBeInTheDocument();
    expect(screen.getByRole('button', {name: 'Draft PR'})).toBeInTheDocument();
  });

  it('shows "Draft PRs" button with correct text for multiple changes', async () => {
    MockApiClient.addMockResponse({
      url: '/issues/123/autofix/setup/?check_write_access=true',
      method: 'GET',
      body: {
        genAIConsent: {ok: true},
        integration: {ok: true},
        githubWriteIntegration: {
          repos: [{ok: true, owner: 'owner', name: 'hello-world', id: 100}],
        },
      },
    });

    const multipleChangesProps = {
      ...changesStepProps,
      step: {
        ...changesStepProps.step,
        changes: [AutofixCodebaseChangeData(), AutofixCodebaseChangeData()],
      },
    };

    render(<AutofixMessageBox {...multipleChangesProps} />);

    await userEvent.click(screen.getByRole('button', {name: 'Use this code'}));

    expect(screen.getByText('Push the above changes to 2 branches?')).toBeInTheDocument();
    expect(screen.getByRole('button', {name: 'Draft PRs'})).toBeInTheDocument();
  });

  it('shows "View PR" buttons when PRs are created', () => {
    render(<AutofixMessageBox {...prCreatedProps} />);

    expect(screen.getByRole('button', {name: /View PR in/})).toBeInTheDocument();
    expect(screen.getByRole('button', {name: /View PR in/})).toHaveAttribute(
      'href',
      'https://github.com/owner/hello-world/pull/200'
    );
  });

  it('shows multiple "View PR" buttons for multiple PRs', () => {
    render(<AutofixMessageBox {...multiplePRsProps} />);

    const viewPRButtons = screen.getAllByRole('button', {name: /View PR in/});
    expect(viewPRButtons).toHaveLength(2);
    expect(viewPRButtons[0]).toHaveAttribute(
      'href',
      'https://github.com/example/repo1/pull/1'
    );
    expect(viewPRButtons[1]).toHaveAttribute(
      'href',
      'https://github.com/example/repo2/pull/2'
    );
  });

  it('shows "Draft PRs" button that opens setup modal when setup is incomplete', async () => {
    MockApiClient.addMockResponse({
      url: '/issues/123/autofix/setup/?check_write_access=true',
      method: 'GET',
      body: {
        genAIConsent: {ok: true},
        integration: {ok: true},
        githubWriteIntegration: {
          repos: [
            {ok: false, provider: 'github', owner: 'owner', name: 'hello-world', id: 100},
          ],
        },
      },
    });
    MockApiClient.addMockResponse({
      url: '/issues/123/autofix/setup/',
      method: 'GET',
      body: {
        genAIConsent: {ok: true},
        integration: {ok: true},
      },
    });

    render(<AutofixMessageBox {...changesStepProps} />);

    await userEvent.click(screen.getByRole('button', {name: 'Use this code'}));

    expect(screen.getByText('Push the above changes to a branch?')).toBeInTheDocument();

    const createPRsButton = screen.getByRole('button', {name: 'Draft PR'});
    expect(createPRsButton).toBeInTheDocument();

    renderGlobalModal();
    await userEvent.click(createPRsButton);

    expect(await screen.findByRole('dialog')).toBeInTheDocument();
    expect(
      within(screen.getByRole('dialog')).getByText('Allow Autofix to Make Pull Requests')
    ).toBeInTheDocument();
  });

  it('shows option buttons for changes step', () => {
    render(<AutofixMessageBox {...changesStepProps} />);

    expect(screen.getByRole('button', {name: 'Use this code'})).toBeInTheDocument();
    expect(screen.getByRole('button', {name: 'Iterate'})).toBeInTheDocument();
    expect(screen.getByRole('button', {name: 'Add tests'})).toBeInTheDocument();
  });

  it('shows "Test" button and static message when "Test" is selected', async () => {
    render(<AutofixMessageBox {...changesStepProps} />);

    await userEvent.click(screen.getByRole('button', {name: 'Add tests'}));

    expect(
      screen.getByText('Write unit tests to make sure the issue is fixed?')
    ).toBeInTheDocument();
    expect(screen.getByRole('button', {name: 'Add Tests'})).toBeInTheDocument();
  });

  it('sends correct message when "Test" is clicked without onSend prop', async () => {
    MockApiClient.addMockResponse({
      method: 'POST',
      url: '/issues/123/autofix/update/',
      body: {},
    });

    render(<AutofixMessageBox {...changesStepProps} />);

    await userEvent.click(screen.getByRole('button', {name: 'Add tests'}));
    await userEvent.click(screen.getByRole('button', {name: 'Add Tests'}));

    await waitFor(() => {
      expect(addSuccessMessage).toHaveBeenCalledWith('Thanks for the input.');
    });
  });
});
