import { css } from '@emotion/css';
import React, { useEffect, useState } from 'react';
import { v4 as uuidv4 } from 'uuid';

import { GrafanaTheme2 } from '@grafana/data';
import { config } from '@grafana/runtime';
import {
  Button,
  ClipboardButton,
  DatePickerWithInput,
  Field,
  Input,
  Modal,
  RadioButtonGroup,
  useStyles2,
} from '@grafana/ui';

const EXPIRATION_OPTIONS = [
  { label: 'No expiration', value: false },
  { label: 'Set expiration date', value: true },
];

export type ServiceAccountToken = {
  name: string;
  secondsToLive?: number;
};

interface Props {
  isOpen: boolean;
  token: string;
  serviceAccountLogin: string;
  onCreateToken: (token: ServiceAccountToken) => void;
  onClose: () => void;
}

export const CreateTokenModal = ({ isOpen, token, serviceAccountLogin, onCreateToken, onClose }: Props) => {
  const tomorrow = new Date();
  tomorrow.setDate(tomorrow.getDate() + 1);

  const maxExpirationDate = new Date();
  if (config.tokenExpirationDayLimit !== undefined && config.tokenExpirationDayLimit > -1) {
    maxExpirationDate.setDate(maxExpirationDate.getDate() + config.tokenExpirationDayLimit + 1);
  } else {
    maxExpirationDate.setDate(8640000000000000);
  }
  const defaultExpirationDate = config.tokenExpirationDayLimit !== undefined && config.tokenExpirationDayLimit > 0;

  const [defaultTokenName, setDefaultTokenName] = useState('');
  const [newTokenName, setNewTokenName] = useState('');
  const [isWithExpirationDate, setIsWithExpirationDate] = useState(defaultExpirationDate);
  const [newTokenExpirationDate, setNewTokenExpirationDate] = useState<Date | string>(tomorrow);
  const [isExpirationDateValid, setIsExpirationDateValid] = useState(newTokenExpirationDate !== '');
  const styles = useStyles2(getStyles);

  useEffect(() => {
    // Generate new token name every time we open modal
    if (isOpen) {
      setDefaultTokenName(`${serviceAccountLogin}-${uuidv4()}`);
    }
  }, [serviceAccountLogin, isOpen]);

  const onExpirationDateChange = (value: Date | string) => {
    const isValid = value !== '';
    setIsExpirationDateValid(isValid);
    setNewTokenExpirationDate(value);
  };

  const onGenerateToken = () => {
    onCreateToken({
      name: newTokenName || defaultTokenName,
      secondsToLive: isWithExpirationDate ? getSecondsToLive(newTokenExpirationDate) : undefined,
    });
  };

  const onCloseInternal = () => {
    setNewTokenName('');
    setDefaultTokenName('');
    setIsWithExpirationDate(defaultExpirationDate);
    setNewTokenExpirationDate(tomorrow);
    setIsExpirationDateValid(newTokenExpirationDate !== '');
    onClose();
  };

  const modalTitle = !token ? 'Add service account token' : 'Service account token created';

  return (
    <Modal
      isOpen={isOpen}
      title={modalTitle}
      onDismiss={onCloseInternal}
      className={styles.modal}
      contentClassName={styles.modalContent}
    >
      {!token ? (
        <div>
          <Field
            label="Display name"
            description="Name to easily identify the token"
            // for now this is required
            // need to make this optional in backend as well
            required={true}
          >
            <Input
              name="tokenName"
              value={newTokenName}
              placeholder={defaultTokenName}
              onChange={(e) => {
                setNewTokenName(e.currentTarget.value);
              }}
            />
          </Field>
          {!isWithExpirationDate && (
            <Field label="Expiration">
              <RadioButtonGroup
                options={EXPIRATION_OPTIONS}
                value={isWithExpirationDate}
                onChange={setIsWithExpirationDate}
                size="md"
              />
            </Field>
          )}
          {isWithExpirationDate && (
            <Field label="Expiration date">
              <DatePickerWithInput
                onChange={onExpirationDateChange}
                value={newTokenExpirationDate}
                placeholder=""
                minDate={tomorrow}
                maxDate={maxExpirationDate}
              />
            </Field>
          )}
          <Modal.ButtonRow>
            <Button onClick={onGenerateToken} disabled={isWithExpirationDate && !isExpirationDateValid}>
              Generate token
            </Button>
          </Modal.ButtonRow>
        </div>
      ) : (
        <>
          <Field
            label="Token"
            description="Copy the token now as you will not be able to see it again. Losing a token requires creating a new one."
          >
            <div className={styles.modalTokenRow}>
              <Input name="tokenValue" value={token} readOnly />
              <ClipboardButton
                className={styles.modalCopyToClipboardButton}
                variant="primary"
                size="md"
                icon="copy"
                getText={() => token}
              >
                Copy clipboard
              </ClipboardButton>
            </div>
          </Field>
          <Modal.ButtonRow>
            <ClipboardButton variant="primary" getText={() => token} onClipboardCopy={onCloseInternal}>
              Copy to clipboard and close
            </ClipboardButton>
            <Button variant="secondary" onClick={onCloseInternal}>
              Close
            </Button>
          </Modal.ButtonRow>
        </>
      )}
    </Modal>
  );
};

const getSecondsToLive = (date: Date | string) => {
  const dateAsDate = new Date(date);
  const now = new Date();

  return Math.ceil((dateAsDate.getTime() - now.getTime()) / 1000);
};

const getStyles = (theme: GrafanaTheme2) => {
  return {
    modal: css`
      width: 550px;
    `,
    modalContent: css`
      overflow: visible;
    `,
    modalTokenRow: css`
      display: flex;
    `,
    modalCopyToClipboardButton: css`
      margin-left: ${theme.spacing(0.5)};
    `,
  };
};
