import React, { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import {
  Box,
  Button,
  color,
  config,
  Icon,
  IconButton,
  Icons,
  IconSrc,
  MenuItem,
  Overlay,
  OverlayBackdrop,
  OverlayCenter,
  Text,
} from 'folds';
import FocusTrap from 'focus-trap-react';
import { General } from './general';
import { PageNav, PageNavContent, PageNavHeader, PageRoot } from '../../components/page';
import { ScreenSize, useScreenSizeContext } from '../../hooks/useScreenSize';
import { Account } from './account';
import { Notifications } from './notifications';
import { Devices } from './devices';
import { EmojisStickers } from './emojis-stickers';
import { About } from './about';
import { Network } from './network';
import { UseStateProvider } from '../../components/UseStateProvider';
import { stopPropagation } from '../../utils/keyboard';
import { LogoutDialog } from '../../components/LogoutDialog';

export enum SettingsPages {
  GeneralPage,
  AccountPage,
  NotificationPage,
  NetworkPage,
  DevicesPage,
  EmojisStickersPage,
  AboutPage,
}

// Stable string keys for URL deep-links: `/settings?page=devices`.
// Append-only — the enum is local but the param values are part of
// the URL contract (push notifications, bookmarks, external links).
// `as const satisfies` so the value type is a literal union (not
// widened to `Record<string, SettingsPages>`): the lookup
// `SETTINGS_PAGE_PARAM[k]` with `k: keyof typeof SETTINGS_PAGE_PARAM`
// returns a narrow `SettingsPages`, but a lookup with an arbitrary
// `string` is a TS error rather than silently typing as
// `SettingsPages` — closing the type-lie R1 flagged but the index-
// signature version didn't actually fix (tsconfig has no
// `noUncheckedIndexedAccess`).
export const SETTINGS_PAGE_PARAM = {
  general: SettingsPages.GeneralPage,
  account: SettingsPages.AccountPage,
  notifications: SettingsPages.NotificationPage,
  network: SettingsPages.NetworkPage,
  devices: SettingsPages.DevicesPage,
  emojis: SettingsPages.EmojisStickersPage,
  about: SettingsPages.AboutPage,
} as const satisfies Record<string, SettingsPages>;
export const SETTINGS_PARAM_DEVICES = 'devices';

// DOM id of the visible "Settings" title in PageNavHeader — referenced
// from `aria-labelledby` on the mobile sheet's `role="dialog"` so
// screen readers announce the same string sighted users see (WAI-ARIA
// APG dialog pattern prefers `aria-labelledby` over `aria-label`).
export const SETTINGS_TITLE_ID = 'vojo-settings-title';

type SettingsMenuItem = {
  page: SettingsPages;
  nameKey: string;
  icon: IconSrc;
};

const SETTINGS_MENU_ITEMS: SettingsMenuItem[] = [
  { page: SettingsPages.GeneralPage, nameKey: 'Settings.menu_general', icon: Icons.Setting },
  { page: SettingsPages.AccountPage, nameKey: 'Settings.menu_account', icon: Icons.User },
  {
    page: SettingsPages.NotificationPage,
    nameKey: 'Settings.menu_notifications',
    icon: Icons.Bell,
  },
  { page: SettingsPages.NetworkPage, nameKey: 'Settings.network.menu', icon: Icons.Server },
  { page: SettingsPages.DevicesPage, nameKey: 'Settings.menu_devices', icon: Icons.Monitor },
  {
    page: SettingsPages.EmojisStickersPage,
    nameKey: 'Settings.menu_emojis_stickers',
    icon: Icons.Smile,
  },
  { page: SettingsPages.AboutPage, nameKey: 'Settings.menu_about', icon: Icons.Info },
];

type SettingsProps = {
  initialPage?: SettingsPages;
  requestClose: () => void;
};
export function Settings({ initialPage, requestClose }: SettingsProps) {
  const { t } = useTranslation();
  const screenSize = useScreenSizeContext();
  // `initialPage !== undefined` (not truthy-check) — `GeneralPage`
  // happens to be enum value `0`, which the old `if (initialPage)`
  // form silently dropped, breaking `/settings?page=general`.
  const [activePage, setActivePage] = useState<SettingsPages | undefined>(() => {
    if (initialPage !== undefined) return initialPage;
    return screenSize === ScreenSize.Mobile ? undefined : SettingsPages.GeneralPage;
  });
  // Re-sync when the parent passes a new `initialPage` (e.g. the
  // UnverifiedTab shield-icon shortcut navigating from `/settings` to
  // `/settings?page=devices` while Settings stays mounted — without
  // this effect the activePage would stay at its previous value and
  // the deep-link would be silently ignored). Treats `initialPage`
  // as the canonical deep-link entry, not the live state, so any
  // user-driven menu click (`setActivePage(...)`) remains untouched
  // until a NEW initialPage arrives from props.
  useEffect(() => {
    if (initialPage !== undefined) setActivePage(initialPage);
  }, [initialPage]);
  const menuItems = SETTINGS_MENU_ITEMS;

  const handlePageRequestClose = () => {
    if (screenSize === ScreenSize.Mobile) {
      setActivePage(undefined);
      return;
    }
    requestClose();
  };

  // Two-level back on mobile: first Escape (or Android hardware back,
  // which `useAndroidBackButton` translates into an Escape dispatch)
  // pops the active sub-page back to the menu; the next Escape lets the
  // wrapper close the sheet entirely. We listen in capture mode so this
  // handler runs BEFORE the wrapper's window-level keydown bubble
  // listener — when a sub-page is active we `stopImmediatePropagation()`
  // so the wrapper's close-sheet handler doesn't also fire.
  //
  // On desktop the two-level fallback isn't useful (Settings is the
  // route — Esc just navigates back), so the handler is mobile-only.
  useEffect(() => {
    if (screenSize !== ScreenSize.Mobile) return undefined;
    if (activePage === undefined) return undefined;
    const onKeyDown = (e: KeyboardEvent) => {
      if (e.key !== 'Escape') return;
      const target = e.target as HTMLElement | null;
      if (
        target &&
        (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable)
      ) {
        return;
      }
      setActivePage(undefined);
      e.stopImmediatePropagation();
    };
    window.addEventListener('keydown', onKeyDown, { capture: true });
    return () => window.removeEventListener('keydown', onKeyDown, { capture: true });
  }, [screenSize, activePage]);

  return (
    <PageRoot
      nav={
        screenSize === ScreenSize.Mobile && activePage !== undefined ? undefined : (
          <PageNav size="350" surface="surfaceVariant">
            <PageNavHeader outlined={false}>
              <Box grow="Yes" gap="200" alignItems="Center">
                <Text id={SETTINGS_TITLE_ID} size="H4" truncate>
                  {t('Settings.title')}
                </Text>
              </Box>
              <Box shrink="No">
                {screenSize === ScreenSize.Mobile && (
                  <IconButton
                    onClick={requestClose}
                    variant="SurfaceVariant"
                    aria-label={t('Settings.close')}
                  >
                    {/* Explicit `color: OnContainer` because the
                        surrounding PageNavHeader carries
                        `variant="Background"` (recipe-level) — without
                        an override the Icon would inherit the
                        Background tone and read as a near-invisible
                        dark patch against the SurfaceVariant panel
                        bg. The neutral OnContainer is the same light
                        text colour used everywhere else on the panel. */}
                    <Icon src={Icons.Cross} style={{ color: color.SurfaceVariant.OnContainer }} />
                  </IconButton>
                )}
              </Box>
            </PageNavHeader>
            <Box grow="Yes" direction="Column">
              <PageNavContent>
                <div style={{ flexGrow: 1 }}>
                  {menuItems.map((item) => {
                    const isActive = activePage === item.page;
                    // The whole PageNav sits on SurfaceVariant.Container
                    // (the chat-pane tone). Active items step up to
                    // SurfaceVariant.ContainerActive (the raised
                    // hover/active tone) to read as a subtle raised
                    // row, and the active icon picks up
                    // `Primary.Main` (Fleet-violet) for a single
                    // splash of accent — the same accent the
                    // DM/Channels/Bots tab underline uses. Text stays
                    // neutral OnContainer; the weight bump conveys
                    // the active state to the eye.
                    return (
                      <MenuItem
                        key={item.nameKey}
                        variant="SurfaceVariant"
                        radii="400"
                        aria-pressed={isActive}
                        before={
                          <Icon
                            src={item.icon}
                            size="100"
                            filled={isActive}
                            style={{
                              color: isActive
                                ? color.Primary.Main
                                : color.SurfaceVariant.OnContainer,
                              opacity: isActive ? 1 : 0.7,
                            }}
                          />
                        }
                        onClick={() => setActivePage(item.page)}
                        style={{
                          backgroundColor: isActive
                            ? color.SurfaceVariant.ContainerActive
                            : 'transparent',
                        }}
                      >
                        <Text
                          style={{
                            fontWeight: isActive ? config.fontWeight.W600 : undefined,
                            opacity: isActive ? 1 : 0.82,
                          }}
                          size="T300"
                          truncate
                        >
                          {t(item.nameKey)}
                        </Text>
                      </MenuItem>
                    );
                  })}
                </div>
              </PageNavContent>
              <Box style={{ padding: config.space.S200 }} shrink="No" direction="Column">
                <UseStateProvider initial={false}>
                  {(logout, setLogout) => (
                    <>
                      <Button
                        size="300"
                        variant="Critical"
                        fill="None"
                        radii="Pill"
                        before={<Icon src={Icons.Power} size="100" />}
                        onClick={() => setLogout(true)}
                      >
                        <Text size="B400">{t('Settings.logout')}</Text>
                      </Button>
                      {logout && (
                        <Overlay open backdrop={<OverlayBackdrop />}>
                          <OverlayCenter>
                            <FocusTrap
                              focusTrapOptions={{
                                onDeactivate: () => setLogout(false),
                                clickOutsideDeactivates: true,
                                escapeDeactivates: stopPropagation,
                              }}
                            >
                              <LogoutDialog handleClose={() => setLogout(false)} />
                            </FocusTrap>
                          </OverlayCenter>
                        </Overlay>
                      )}
                    </>
                  )}
                </UseStateProvider>
              </Box>
            </Box>
          </PageNav>
        )
      }
    >
      {activePage === SettingsPages.GeneralPage && (
        <General requestClose={handlePageRequestClose} />
      )}
      {activePage === SettingsPages.AccountPage && (
        <Account requestClose={handlePageRequestClose} />
      )}
      {activePage === SettingsPages.NotificationPage && (
        <Notifications requestClose={handlePageRequestClose} />
      )}
      {activePage === SettingsPages.NetworkPage && (
        <Network requestClose={handlePageRequestClose} />
      )}
      {activePage === SettingsPages.DevicesPage && (
        <Devices requestClose={handlePageRequestClose} />
      )}
      {activePage === SettingsPages.EmojisStickersPage && (
        <EmojisStickers requestClose={handlePageRequestClose} />
      )}
      {activePage === SettingsPages.AboutPage && <About requestClose={handlePageRequestClose} />}
    </PageRoot>
  );
}
