import React, { type FC, useMemo, useState } from 'react';

import { Trans, t } from '@grafana/i18n';
import { isFetchError } from '@grafana/runtime';
import { Button, ConfirmModal, Modal, type ModalProps, Space, Spinner, Stack, Text } from '@grafana/ui';

import { type RouteWithID } from '../../../../../../plugins/datasource/alertmanager/types';
import { type FormAmRoute } from '../../../types/amroutes';
import { defaultGroupBy } from '../../../utils/amroutes';
import { GRAFANA_RULES_SOURCE_NAME } from '../../../utils/datasource';
import { ROOT_ROUTE_NAME } from '../../../utils/k8s/constants';
import { stringifyErrorLike } from '../../../utils/misc';
import { AmRootRouteForm } from '../EditDefaultPolicyForm';
import { NotificationPoliciesErrorAlert } from '../PolicyUpdateErrorAlert';
import {
  trackNotificationPolicyCreateError,
  trackNotificationPolicyCreated,
  trackNotificationPolicyDeleteError,
  trackNotificationPolicyDeleted,
  trackNotificationPolicyReset,
  trackNotificationPolicyResetError,
} from '../notificationPolicyAnalytics';

export interface DeleteModalProps {
  isOpen: boolean;
  onConfirm: () => Promise<unknown>;
  onDismiss: () => void;
  routeName: string;
}

export const DeleteModal = React.memo(({ onConfirm, onDismiss, isOpen, routeName }: DeleteModalProps) => {
  const [isDeleting, setIsDeleting] = useState(false);
  const [error, setError] = useState<unknown | undefined>();

  const onDeleteDismiss = () => {
    onDismiss();
    setError(undefined);
  };

  const onDeleteConfirm = async () => {
    setIsDeleting(true);
    onConfirm()
      .then(() => {
        trackNotificationPolicyDeleted();
        onDeleteDismiss();
      })
      .catch((err) => {
        trackNotificationPolicyDeleteError({ error: stringifyErrorLike(err) });
        setError(err);
      })
      .finally(() => {
        setIsDeleting(false);
      });
  };
  if (error) {
    return <ErrorModal isOpen={isOpen} onDismiss={onDeleteDismiss} error={error} />;
  }

  return (
    <ConfirmModal
      body={
        <>
          <Text element="p">
            <Trans
              i18nKey="alerting.policies.delete-modal.permanently-remove"
              values={{ routeName: routeName === ROOT_ROUTE_NAME || !routeName ? 'Default Policy' : routeName }}
            >
              This action will permanently remove the <code>{'{{routeName}}'}</code> notification policy.
            </Trans>
          </Text>
          <Space v={2} />
        </>
      }
      confirmationText={t('alerting.common.delete', 'Delete')}
      confirmText={isDeleting ? t('alerting.common.deleting', 'Deleting...') : t('alerting.common.delete', 'Delete')}
      onDismiss={onDeleteDismiss}
      onConfirm={onDeleteConfirm}
      title={t('alerting.policies.delete-modal.title-delete-notification-policy', 'Delete notification policy')}
      isOpen={isOpen}
    />
  );
});
DeleteModal.displayName = 'DeleteModal';

function getConfirmText(isResetting: boolean, isActualDefaultPolicy: boolean): string {
  if (isResetting) {
    return isActualDefaultPolicy
      ? t('alerting.policies.reset-modal.resetting', 'Resetting...')
      : t('alerting.policies.reset-modal.deleting', 'Deleting...');
  }
  return isActualDefaultPolicy
    ? t('alerting.policies.reset-modal.reset', 'Reset')
    : t('alerting.policies.reset-modal.delete', 'Delete');
}

export interface ResetModalProps {
  isOpen: boolean;
  onConfirm: () => Promise<unknown>;
  onDismiss: () => void;
  routeName: string;
  /** When true (default), shows "Reset" language. When false, shows "Delete" language for non-default policy trees. */
  isActualDefaultPolicy?: boolean;
}

export const ResetModal = React.memo(
  ({ onConfirm, onDismiss, isOpen, routeName, isActualDefaultPolicy = true }: ResetModalProps) => {
    const [isResetting, setIsResetting] = useState(false);
    const [error, setError] = useState<unknown | undefined>();

    const onResetDismiss = () => {
      onDismiss();
      setError(undefined);
    };

    const onResetConfirm = async () => {
      setIsResetting(true);
      onConfirm()
        .then(() => {
          trackNotificationPolicyReset();
          onResetDismiss();
        })
        .catch((err) => {
          trackNotificationPolicyResetError({ error: stringifyErrorLike(err) });
          setError(err);
        })
        .finally(() => {
          setIsResetting(false);
        });
    };
    if (error) {
      return <ErrorModal isOpen={isOpen} onDismiss={onResetDismiss} error={error} />;
    }

    const displayName = routeName === ROOT_ROUTE_NAME || !routeName ? 'Default Policy' : routeName;

    return (
      <ConfirmModal
        body={
          <>
            <Text element="p">
              {isActualDefaultPolicy ? (
                <Trans i18nKey="alerting.policies.reset-modal.permanently-reset" values={{ routeName: displayName }}>
                  This action will permanently reset the <code>{'{{routeName}}'}</code> notification policy to an empty
                  state.
                </Trans>
              ) : (
                <Trans i18nKey="alerting.policies.reset-modal.permanently-delete" values={{ routeName: displayName }}>
                  This action will permanently delete the <code>{'{{routeName}}'}</code> notification policy.
                </Trans>
              )}
            </Text>
            <Space v={2} />
          </>
        }
        confirmationText={
          isActualDefaultPolicy
            ? t('alerting.policies.reset-modal.reset', 'Reset')
            : t('alerting.policies.reset-modal.delete', 'Delete')
        }
        confirmText={getConfirmText(isResetting, isActualDefaultPolicy)}
        onDismiss={onResetDismiss}
        onConfirm={onResetConfirm}
        title={
          isActualDefaultPolicy
            ? t('alerting.policies.reset-modal.title-reset-notification-policy', 'Reset notification policy')
            : t('alerting.policies.reset-modal.title-delete-notification-policy', 'Delete notification policy')
        }
        isOpen={isOpen}
      />
    );
  }
);
ResetModal.displayName = 'ResetModal';

const emptyRouteWithID = {
  id: '',
  name: '',
  group_by: defaultGroupBy,
};

export interface CreateModalProps {
  isOpen: boolean;
  onConfirm: (route: Partial<FormAmRoute>) => Promise<unknown>;
  onDismiss: () => void;
  existingPolicyNames?: string[];
}

export const CreateModal = React.memo(({ existingPolicyNames, onConfirm, onDismiss, isOpen }: CreateModalProps) => {
  const [isCreating, setIsCreating] = useState(false);
  const [error, setError] = useState<unknown | undefined>();
  const [route, setRoute] = useState<RouteWithID>(emptyRouteWithID);
  const nameError = useMemo(() => {
    return isFetchError(error) && error.status === 409 ? stringifyErrorLike(error) : undefined;
  }, [error]);

  const onCreateDismiss = () => {
    onDismiss();
    setError(undefined);
    setRoute(emptyRouteWithID);
  };

  const onCreateConfirm = async (newRoute: Partial<FormAmRoute>) => {
    if (newRoute) {
      setIsCreating(true);
      setError(undefined);
      onConfirm(newRoute)
        .then(() => {
          trackNotificationPolicyCreated({
            hasCustomTimings: newRoute.overrideTimings ?? false,
            hasCustomGrouping: newRoute.overrideGrouping ?? false,
          });
          onCreateDismiss();
        })
        .catch((err) => {
          trackNotificationPolicyCreateError({ error: stringifyErrorLike(err) });
          setError(err);
        })
        .finally(() => {
          setIsCreating(false);
        });
    }
  };

  if (isCreating) {
    return <CreatingModal isOpen={isOpen} onDismiss={onCreateDismiss} />;
  }

  return (
    <Modal
      isOpen={isOpen}
      onDismiss={onCreateDismiss}
      closeOnBackdropClick={true}
      closeOnEscape={true}
      title={t('alerting.policies.create-modal.title-new-notification-policy', 'New notification policy')}
    >
      {!nameError && error ? <NotificationPoliciesErrorAlert error={error} /> : null}
      <AmRootRouteForm
        existingPolicyNames={existingPolicyNames}
        nameError={nameError}
        route={route}
        showNameField={true}
        onSubmit={onCreateConfirm}
        alertManagerSourceName={GRAFANA_RULES_SOURCE_NAME}
        actionButtons={
          <Modal.ButtonRow>
            <Button type="button" variant="secondary" onClick={onCreateDismiss}>
              <Trans i18nKey="alerting.common.cancel">Cancel</Trans>
            </Button>
            <Button type="submit">
              <Trans i18nKey="alerting.common.create">Create</Trans>
            </Button>
          </Modal.ButtonRow>
        }
      />
    </Modal>
  );
});
CreateModal.displayName = 'CreateModal';

interface ErrorModalProps extends Pick<ModalProps, 'isOpen' | 'onDismiss'> {
  error: unknown;
}
const ErrorModal = ({ isOpen, onDismiss, error }: ErrorModalProps) => {
  return (
    <Modal
      isOpen={isOpen}
      onDismiss={onDismiss}
      closeOnBackdropClick={true}
      closeOnEscape={true}
      title={t('alerting.policies.error-modal.title-something-went-wrong', 'Something went wrong')}
    >
      <p>
        <Trans i18nKey="alerting.policies.error-modal.failed-to-update-your-configuration">
          Failed to update your configuration:
        </Trans>
      </p>
      <pre>
        <code>{stringifyErrorLike(error)}</code>
      </pre>
    </Modal>
  );
};

const CreatingModal: FC<Pick<ModalProps, 'isOpen' | 'onDismiss'>> = ({ isOpen, onDismiss = () => {} }) => (
  <Modal
    isOpen={isOpen}
    onDismiss={onDismiss}
    closeOnBackdropClick={false}
    closeOnEscape={false}
    ariaLabel={t('alerting.policies.create-modal.creating', 'Creating...')}
    title={
      <Stack direction="row" alignItems="center" gap={0.5}>
        <Trans i18nKey="alerting.policies.create-modal.creating">Creating...</Trans> <Spinner inline />
      </Stack>
    }
  >
    <Trans i18nKey="alerting.policies.create-modal.please-wait">
      Please wait while we create your notification policy.
    </Trans>
  </Modal>
);
