import { Route, Routes } from 'react-router-dom-v5-compat';
import { render, screen } from 'test/test-utils';
import { byLabelText, byPlaceholderText, byRole, byTestId } from 'testing-library-selector';

import { makeAlertmanagerConfigUpdateFail } from 'app/features/alerting/unified/mocks/server/configure';
import { captureRequests } from 'app/features/alerting/unified/mocks/server/events';
import { AccessControlAction } from 'app/types';

import { setupMswServer } from '../../mockApi';
import { grantUserPermissions } from '../../mocks';
import { testWithFeatureToggles } from '../../test/test-utils';

import NewReceiverView from './NewReceiverView';

setupMswServer();

const Index = () => {
  return <div>redirected</div>;
};

const renderForm = () =>
  render(
    <Routes>
      <Route path="/alerting/notifications" element={<Index />} />
      <Route path="/alerting/notifications/new" element={<NewReceiverView />} />
    </Routes>,
    {
      historyOptions: { initialEntries: ['/alerting/notifications/new'] },
    }
  );

beforeEach(() => {
  grantUserPermissions([AccessControlAction.AlertingNotificationsRead, AccessControlAction.AlertingNotificationsWrite]);
});

describe('alerting API server enabled', () => {
  testWithFeatureToggles(['alertingApiServer']);

  it('can create a receiver', async () => {
    const { user } = renderForm();

    expect(await ui.inputs.name.find()).toBeEnabled();

    await user.type(await ui.inputs.name.find(), 'my new receiver');

    // enter some email
    const email = ui.inputs.email.addresses.get();
    await user.clear(email);
    await user.type(email, 'tester@grafana.com');

    await user.click(ui.saveContactButton.get());

    expect(await screen.findByText(/redirected/i)).toBeInTheDocument();
  });
});

describe('alerting API server disabled', () => {
  it('should be able to test and save a receiver', async () => {
    const capture = captureRequests();

    const { user } = renderForm();

    // wait for loading to be done
    // type in a name for the new receiver
    await user.type(await ui.inputs.name.find(), 'my new receiver');

    // enter some email
    const email = ui.inputs.email.addresses.get();
    await user.clear(email);
    await user.type(email, 'tester@grafana.com');

    // try to test the contact point
    await user.click(await ui.testContactPointButton.find());

    expect(await ui.testContactPointModal.find()).toBeInTheDocument();

    await user.click(ui.customContactPointOption.get());

    // enter custom annotations and labels
    await user.type(screen.getByPlaceholderText('Enter a description...'), 'Test contact point');
    await user.type(ui.contactPointLabelKey(0).get(), 'foo');
    await user.type(ui.contactPointLabelValue(0).get(), 'bar');

    // click test
    await user.click(ui.testContactPoint.get());

    // we shouldn't be testing implementation details but when the request is successful
    // it can't seem to assert on the success toast
    await user.click(ui.saveContactButton.get());

    const requests = await capture;
    const testRequest = requests.find((r) => r.url.endsWith('/config/api/v1/receivers/test'));
    const saveRequest = requests.find(
      (r) => r.url.endsWith('/api/alertmanager/grafana/config/api/v1/alerts') && r.method === 'POST'
    );

    const testBody = await testRequest?.json();
    const fullSaveBody = await saveRequest?.json();

    // Only snapshot and check the receivers, as we don't want other tests to break this
    // just because we added something new to the mock config
    const saveBody = fullSaveBody.alertmanager_config.receivers;

    expect([testBody]).toMatchSnapshot();
    expect([saveBody]).toMatchSnapshot();
  });

  it('does not redirect when creating contact point and API errors', async () => {
    makeAlertmanagerConfigUpdateFail();
    const { user } = renderForm();

    await user.type(await ui.inputs.name.find(), 'receiver that should fail');
    const email = ui.inputs.email.addresses.get();
    await user.clear(email);
    await user.type(email, 'tester@grafana.com');

    await user.click(ui.saveContactButton.get());

    expect(screen.queryByText(/redirected/i)).not.toBeInTheDocument();
  });
});

const ui = {
  saveContactButton: byRole('button', { name: /save contact point/i }),

  testContactPointButton: byRole('button', { name: /Test/ }),
  testContactPointModal: byRole('heading', { name: /test contact point/i }),
  customContactPointOption: byRole('radio', { name: /custom/i }),
  contactPointLabelKey: (idx: number) => byTestId(`label-key-${idx}`),
  contactPointLabelValue: (idx: number) => byTestId(`label-value-${idx}`),
  testContactPoint: byRole('button', { name: /send test notification/i }),
  inputs: {
    name: byPlaceholderText('Name'),
    email: {
      addresses: byLabelText(/Addresses/),
    },
  },
};
