import {Fragment, useCallback, useEffect, useMemo, useState} from 'react';
import {useTheme} from '@emotion/react';
import styled from '@emotion/styled';
import {FocusScope} from '@react-aria/focus';
import * as Sentry from '@sentry/react';
import {AnimatePresence} from 'framer-motion';

import GuideAnchor from 'sentry/components/assistant/guideAnchor';
import {Button} from 'sentry/components/button';
import {CompactSelect} from 'sentry/components/compactSelect';
import {openConfirmModal} from 'sentry/components/confirm';
import InputControl from 'sentry/components/input';
import {Overlay, PositionWrapper} from 'sentry/components/overlay';
import {Tooltip} from 'sentry/components/tooltip';
import {IconBookmark, IconDashboard, IconDelete, IconStar} from 'sentry/icons';
import {t} from 'sentry/locale';
import {space} from 'sentry/styles/space';
import {trackAnalytics} from 'sentry/utils/analytics';
import useKeyPress from 'sentry/utils/useKeyPress';
import useOrganization from 'sentry/utils/useOrganization';
import useOverlay from 'sentry/utils/useOverlay';
import {useScratchpads} from 'sentry/views/ddm/scratchpadContext';

import {useCreateDashboard} from './useCreateDashboard';

export function ScratchpadSelector() {
  const scratchpads = useScratchpads();
  const organization = useOrganization();
  const createDashboard = useCreateDashboard();

  const isDefault = useCallback(
    scratchpad => scratchpads.default === scratchpad.id,
    [scratchpads.default]
  );

  const scratchpadOptions = useMemo(
    () =>
      Object.values(scratchpads.all).map(scratchpad => ({
        value: scratchpad.id,
        label: scratchpad.name,
        trailingItems: (
          <Fragment>
            <Tooltip
              title={
                isDefault(scratchpad)
                  ? t('Remove as default scratchpad')
                  : t('Set as default scratchpad')
              }
            >
              <Button
                size="zero"
                borderless
                onPointerDown={e => e.stopPropagation()}
                onClick={() => {
                  trackAnalytics('ddm.scratchpad.set-default', {
                    organization,
                  });
                  Sentry.metrics.increment('ddm.scratchpad.set_default');

                  if (isDefault(scratchpad)) {
                    scratchpads.setDefault(null);
                  } else {
                    scratchpads.setDefault(scratchpad.id ?? null);
                  }
                }}
              >
                <StyledDropdownIcon>
                  <IconBookmark isSolid={isDefault(scratchpad)} />
                </StyledDropdownIcon>
              </Button>
            </Tooltip>
            <Tooltip title={t('Remove scratchpad')}>
              <Button
                size="zero"
                borderless
                onPointerDown={e => e.stopPropagation()}
                onClick={() => {
                  openConfirmModal({
                    onConfirm: () => {
                      trackAnalytics('ddm.scratchpad.remove', {
                        organization,
                      });
                      Sentry.metrics.increment('ddm.scratchpad.remove');

                      scratchpads.remove(scratchpad.id);
                    },
                    message: t('Are you sure you want to delete this scratchpad?'),
                    confirmText: t('Delete'),
                  });
                }}
              >
                <StyledDropdownIcon danger>
                  <IconDelete size="sm" />
                </StyledDropdownIcon>
              </Button>
            </Tooltip>
          </Fragment>
        ),
      })),
    [scratchpads, isDefault, organization]
  );

  const selectedScratchpad = scratchpads.selected
    ? scratchpads.all[scratchpads.selected]
    : undefined;

  return (
    <ScratchpadGroup>
      <Button
        icon={<IconDashboard />}
        onClick={() => {
          Sentry.metrics.increment('ddm.scratchpad.dashboard');
          createDashboard(selectedScratchpad);
        }}
      >
        {t('Add to Dashboard')}
      </Button>
      <SaveAsDropdown
        onSave={name => {
          scratchpads.add(name);
        }}
        mode={scratchpads.selected ? 'fork' : 'save'}
      />
      <CompactSelect
        grid
        options={scratchpadOptions}
        value={scratchpads.selected ?? `None`}
        closeOnSelect={false}
        onChange={option => {
          scratchpads.toggleSelected(option.value);
        }}
        triggerProps={{prefix: t('Scratchpad')}}
        emptyMessage="No scratchpads yet."
        disabled={false}
      />
    </ScratchpadGroup>
  );
}

function SaveAsDropdown({
  onSave,
  mode,
}: {
  mode: 'save' | 'fork';
  onSave: (name: string) => void;
}) {
  const {
    isOpen,
    triggerProps,
    overlayProps,
    arrowProps,
    state: {setOpen},
  } = useOverlay({});
  const theme = useTheme();
  const organization = useOrganization();
  const [name, setName] = useState('');

  const save = useCallback(() => {
    trackAnalytics('ddm.scratchpad.save', {
      organization,
    });
    Sentry.metrics.increment('ddm.scratchpad.save');

    onSave(name);
    setOpen(false);
    setName('');
  }, [name, onSave, setOpen, organization]);

  const enterKeyPressed = useKeyPress('Enter');

  useEffect(() => {
    if (isOpen && enterKeyPressed && name) {
      save();
    }
  }, [enterKeyPressed, isOpen, name, save]);

  const isFork = mode === 'fork';

  return (
    <div>
      <Button icon={isFork ? null : <IconStar isSolid={isFork} />} {...triggerProps}>
        {isFork ? `${t('Duplicate as')}\u2026` : `${t('Save as')}\u2026`}
      </Button>
      <AnimatePresence>
        {isOpen && (
          <FocusScope contain restoreFocus autoFocus>
            <PositionWrapper zIndex={theme.zIndex.dropdown} {...overlayProps}>
              <StyledOverlay arrowProps={arrowProps} animated>
                <SaveAsInput
                  type="txt"
                  name="scratchpad-name"
                  placeholder={t('Scratchpad name')}
                  value={name}
                  size="sm"
                  onChange={({target}) => setName(target.value)}
                />
                <GuideAnchor target="create_scratchpad" position="bottom">
                  <SaveAsButton
                    priority="primary"
                    disabled={!name}
                    onClick={() => {
                      save();
                    }}
                  >
                    {mode === 'fork' ? t('Duplicate') : t('Save')}
                  </SaveAsButton>
                </GuideAnchor>
              </StyledOverlay>
            </PositionWrapper>
          </FocusScope>
        )}
      </AnimatePresence>
    </div>
  );
}

const ScratchpadGroup = styled('div')`
  display: flex;
  gap: ${space(1)};
`;

const StyledOverlay = styled(Overlay)`
  padding: ${space(1)};
`;

const SaveAsButton = styled(Button)`
  width: 100%;
`;

const SaveAsInput = styled(InputControl)`
  margin-bottom: ${space(1)};
`;

const StyledDropdownIcon = styled('span')<{danger?: boolean}>`
  padding: ${space(0.5)} ${space(0.5)} 0 ${space(0.5)};
  opacity: 0.5;

  :hover {
    opacity: 0.9;
    color: ${p => (p.danger ? p.theme.red300 : p.theme.gray300)};
  }
`;