import React, {
  ChangeEventHandler,
  KeyboardEventHandler,
  MouseEventHandler,
  useMemo,
  useState,
} from 'react';
import {
  Box,
  Button,
  config,
  Icon,
  Icons,
  Input,
  Menu,
  MenuItem,
  PopOut,
  RectCords,
  Switch,
  Text,
  toRem,
} from 'folds';
import FocusTrap from 'focus-trap-react';
import { isKeyHotkey } from 'is-hotkey';
import { useTranslation } from 'react-i18next';
import { useSetting } from '../../../state/hooks/settings';
import { settingsAtom } from '../../../state/settings';
import { SettingTile } from '../../../components/setting-tile';
import { KeySymbol } from '../../../utils/key-symbol';
import { isMacOS } from '../../../utils/user-agent';
import { stopPropagation } from '../../../utils/keyboard';
import { DarkTheme, LightTheme } from '../../../hooks/useTheme';
import { SettingsPage } from '../SettingsPage';
import { SettingsSection } from '../SettingsSection';

type ThemeChoice = 'system' | typeof LightTheme.id | typeof DarkTheme.id;

function ThemeSelect() {
  const { t } = useTranslation();
  const [useSystemTheme, setUseSystemTheme] = useSetting(settingsAtom, 'useSystemTheme');
  const [themeId, setThemeId] = useSetting(settingsAtom, 'themeId');

  let choice: ThemeChoice;
  if (useSystemTheme) {
    choice = 'system';
  } else if (themeId === DarkTheme.id) {
    choice = DarkTheme.id;
  } else {
    choice = LightTheme.id;
  }

  const choices = useMemo<ThemeChoice[]>(() => ['system', LightTheme.id, DarkTheme.id], []);

  const choiceLabel = useMemo<Record<ThemeChoice, string>>(
    () => ({
      system: t('Settings.system_theme'),
      'light-theme': t('Settings.theme_light'),
      'dark-theme': t('Settings.theme_dark'),
    }),
    [t]
  );

  const [menuCords, setMenuCords] = useState<RectCords>();

  const handleMenu: MouseEventHandler<HTMLButtonElement> = (evt) => {
    setMenuCords(evt.currentTarget.getBoundingClientRect());
  };

  const handleSelect = (next: ThemeChoice) => {
    setMenuCords(undefined);
    if (next === 'system') {
      setUseSystemTheme(true);
      return;
    }
    setUseSystemTheme(false);
    setThemeId(next);
  };

  return (
    <>
      <Button
        size="300"
        variant="Secondary"
        outlined
        fill="Soft"
        radii="300"
        after={<Icon size="300" src={Icons.ChevronBottom} />}
        onClick={handleMenu}
      >
        <Text size="T300">{choiceLabel[choice]}</Text>
      </Button>
      <PopOut
        anchor={menuCords}
        offset={5}
        position="Bottom"
        align="End"
        content={
          <FocusTrap
            focusTrapOptions={{
              initialFocus: false,
              onDeactivate: () => setMenuCords(undefined),
              clickOutsideDeactivates: true,
              isKeyForward: (evt: KeyboardEvent) =>
                evt.key === 'ArrowDown' || evt.key === 'ArrowRight',
              isKeyBackward: (evt: KeyboardEvent) =>
                evt.key === 'ArrowUp' || evt.key === 'ArrowLeft',
              escapeDeactivates: stopPropagation,
            }}
          >
            <Menu>
              <Box direction="Column" gap="100" style={{ padding: config.space.S100 }}>
                {choices.map((c) => (
                  <MenuItem
                    key={c}
                    size="300"
                    variant="Surface"
                    aria-selected={c === choice}
                    radii="300"
                    onClick={() => handleSelect(c)}
                  >
                    <Box grow="Yes">
                      <Text size="T300">{choiceLabel[c]}</Text>
                    </Box>
                  </MenuItem>
                ))}
              </Box>
            </Menu>
          </FocusTrap>
        }
      />
    </>
  );
}

function PageZoomInput() {
  const [pageZoom, setPageZoom] = useSetting(settingsAtom, 'pageZoom');
  const [currentZoom, setCurrentZoom] = useState(`${pageZoom}`);

  const handleZoomChange: ChangeEventHandler<HTMLInputElement> = (evt) => {
    setCurrentZoom(evt.target.value);
  };

  const handleZoomEnter: KeyboardEventHandler<HTMLInputElement> = (evt) => {
    if (isKeyHotkey('escape', evt)) {
      evt.stopPropagation();
      setCurrentZoom(pageZoom.toString());
    }
    if (
      isKeyHotkey('enter', evt) &&
      'value' in evt.target &&
      typeof evt.target.value === 'string'
    ) {
      const newZoom = parseInt(evt.target.value, 10);
      if (Number.isNaN(newZoom)) return;
      const safeZoom = Math.max(Math.min(newZoom, 150), 75);
      setPageZoom(safeZoom);
      setCurrentZoom(safeZoom.toString());
    }
  };

  return (
    <Input
      style={{ width: toRem(100) }}
      variant={pageZoom === parseInt(currentZoom, 10) ? 'Secondary' : 'Success'}
      size="300"
      radii="300"
      type="number"
      min="75"
      max="150"
      value={currentZoom}
      onChange={handleZoomChange}
      onKeyDown={handleZoomEnter}
      after={<Text size="T300">%</Text>}
      outlined
    />
  );
}

function Appearance() {
  const { t } = useTranslation();
  const [twitterEmoji, setTwitterEmoji] = useSetting(settingsAtom, 'twitterEmoji');

  return (
    <SettingsSection label={t('Settings.appearance')}>
      <SettingTile title={t('Settings.theme')} after={<ThemeSelect />} />
      <SettingTile
        title={t('Settings.twitter_emoji')}
        after={<Switch variant="Primary" value={twitterEmoji} onChange={setTwitterEmoji} />}
      />
      <SettingTile title={t('Settings.page_zoom')} after={<PageZoomInput />} />
    </SettingsSection>
  );
}

function Editor() {
  const { t } = useTranslation();
  const [enterForNewline, setEnterForNewline] = useSetting(settingsAtom, 'enterForNewline');
  const [isMarkdown, setIsMarkdown] = useSetting(settingsAtom, 'isMarkdown');
  const [hideActivity, setHideActivity] = useSetting(settingsAtom, 'hideActivity');

  return (
    <SettingsSection label={t('Settings.editor')}>
      <SettingTile
        title={t('Settings.enter_newline')}
        description={t('Settings.enter_newline_desc', {
          key: isMacOS() ? KeySymbol.Command : 'Ctrl',
        })}
        after={<Switch variant="Primary" value={enterForNewline} onChange={setEnterForNewline} />}
      />
      <SettingTile
        title={t('Settings.markdown')}
        after={<Switch variant="Primary" value={isMarkdown} onChange={setIsMarkdown} />}
      />
      <SettingTile
        title={t('Settings.hide_activity')}
        description={t('Settings.hide_activity_desc')}
        after={<Switch variant="Primary" value={hideActivity} onChange={setHideActivity} />}
      />
    </SettingsSection>
  );
}

function Messages() {
  const { t } = useTranslation();
  const [hideMembershipEvents, setHideMembershipEvents] = useSetting(
    settingsAtom,
    'hideMembershipEvents'
  );
  const [hideNickAvatarEvents, setHideNickAvatarEvents] = useSetting(
    settingsAtom,
    'hideNickAvatarEvents'
  );
  const [mediaAutoLoad, setMediaAutoLoad] = useSetting(settingsAtom, 'mediaAutoLoad');
  const [urlPreview, setUrlPreview] = useSetting(settingsAtom, 'urlPreview');

  // Merged control for the two service-event toggles (joins/leaves +
  // name/avatar changes). Reads on only when *both* classes are hidden, and
  // writes both atoms together. AND (not OR) keeps the switch honest against
  // the default state: out of the box hideMembershipEvents is false (joins/
  // leaves shown) and hideNickAvatarEvents is true, so the switch reads OFF
  // and the visible join/leave events agree with it. The timeline still reads
  // each atom directly, so existing persisted preferences are untouched until
  // the user flips this switch (which then sets both to the same value).
  const hideServiceEvents = hideMembershipEvents && hideNickAvatarEvents;
  const setHideServiceEvents = (value: boolean) => {
    setHideMembershipEvents(value);
    setHideNickAvatarEvents(value);
  };

  return (
    <SettingsSection label={t('Settings.messages')}>
      <SettingTile
        title={t('Settings.hide_service_events')}
        description={t('Settings.hide_service_events_desc')}
        after={
          <Switch variant="Primary" value={hideServiceEvents} onChange={setHideServiceEvents} />
        }
      />
      <SettingTile
        title={t('Settings.disable_media_auto_load')}
        after={
          <Switch variant="Primary" value={!mediaAutoLoad} onChange={(v) => setMediaAutoLoad(!v)} />
        }
      />
      <SettingTile
        title={t('Settings.url_preview')}
        after={<Switch variant="Primary" value={urlPreview} onChange={setUrlPreview} />}
      />
    </SettingsSection>
  );
}

function Advanced() {
  const { t } = useTranslation();
  const [developerTools, setDeveloperTools] = useSetting(settingsAtom, 'developerTools');

  return (
    <SettingsSection label={t('Settings.advanced')}>
      <SettingTile
        title={t('Settings.developer_mode')}
        description={t('Settings.developer_mode_desc')}
        after={<Switch variant="Primary" value={developerTools} onChange={setDeveloperTools} />}
      />
    </SettingsSection>
  );
}

type GeneralProps = {
  requestClose: () => void;
};
export function General({ requestClose }: GeneralProps) {
  const { t } = useTranslation();
  return (
    <SettingsPage title={t('Settings.general_title')} requestClose={requestClose}>
      <Appearance />
      <Editor />
      <Messages />
      <Advanced />
    </SettingsPage>
  );
}
