import { useMemo, useState } from 'react';
import { Button, Group, Paper, Stack, Text, Title } from '@mantine/core';
import { IconLogout } from '@tabler/icons-react';
import { useTranslation } from 'react-i18next';
import { AdvancedTable, ConfirmModal, notify, useErrorHandler, useServerTable } from '@ema-platform/ui';
import { useDateDisplayer } from '@ema-platform/shared';
import { useSessions, type MySession } from '../../hooks/useSessions';
import { useAuthToken } from '../../hooks/useAuthToken';
import { currentSessionId } from '../../utils/jwt';
import { sessionColumns } from './columns';

/** What the one confirm dialog is currently asking about. */
type Pending =
  | { kind: 'one'; ids: string[]; device: string }
  | { kind: 'selected'; ids: string[] }
  | { kind: 'others' };

/**
 * Where the signed-in user is logged in, and how to end those sessions.
 *
 * Renders as its own card so it can sit OUTSIDE the change-password <form> on
 * the Security tab — a bare <button> inside that form would submit it.
 */
export function ActiveSessions() {
  const { t } = useTranslation();
  const { handleError } = useErrorHandler();
  const showDate = useDateDisplayer();
  const token = useAuthToken();
  const currentId = useMemo(() => currentSessionId(token), [token]);

  const { pageIndex, setPageIndex, pageSize, setPageSize, skip, take } = useServerTable({
    pageSize: 5,
  });
  const { sessions, total, isFetching, refetch, revoke, isRevoking, allSessionIds } = useSessions({
    skip,
    take,
  });

  const [selected, setSelected] = useState<string[]>([]);
  const [pending, setPending] = useState<Pending | null>(null);

  const columns = useMemo(
    () =>
      sessionColumns({
        t,
        sessions,
        selected,
        setSelected,
        currentId,
        showDate,
        onRevoke: (s: MySession) => setPending({ kind: 'one', ids: [s.id], device: s.device }),
      }),
    [t, sessions, selected, currentId, showDate],
  );

  const confirmMessage = () => {
    if (!pending) return '';
    const base =
      pending.kind === 'one'
        ? t('profile.sessions.confirm.one', { device: pending.device })
        : pending.kind === 'selected'
          ? t('profile.sessions.confirm.selected', { count: pending.ids.length })
          : t('profile.sessions.confirm.others');
    // Without a session claim on the token there is no way to spare this
    // device, so say so rather than implying the current login survives.
    return currentId ? base : `${base} ${t('profile.sessions.confirm.unknownDevice')}`;
  };

  const onConfirm = async () => {
    if (!pending) return;
    try {
      const ids =
        pending.kind === 'others'
          ? (await allSessionIds()).filter((id) => id !== currentId)
          : pending.ids;
      await revoke(ids);
      notify.success(t('profile.sessions.revoked', { count: ids.length }));
      setSelected([]);
      setPending(null);
    } catch (e) {
      handleError(e);
    }
  };

  // "Sign out everywhere else" is only meaningful once a second session exists.
  const hasOthers = total > (currentId ? 1 : 0);

  return (
    <Paper p="xl" shadow="sm" radius="lg" withBorder>
      <Stack gap="md">
        <Group justify="space-between" align="flex-start" wrap="nowrap">
          <div>
            <Title order={5}>{t('profile.sessions.title')}</Title>
            <Text size="sm" c="dimmed">
              {t('profile.sessions.hint')}
            </Text>
          </div>
          <Group gap="xs" wrap="nowrap">
            {selected.length > 0 && (
              <Button
                type="button"
                variant="light"
                color="red"
                size="sm"
                onClick={() => setPending({ kind: 'selected', ids: selected })}
              >
                {t('profile.sessions.revokeSelected', { count: selected.length })}
              </Button>
            )}
            {hasOthers && (
              <Button
                type="button"
                variant="light"
                color="red"
                size="sm"
                leftSection={<IconLogout size={16} />}
                onClick={() => setPending({ kind: 'others' })}
              >
                {t('profile.sessions.signOutOthers')}
              </Button>
            )}
          </Group>
        </Group>

        <AdvancedTable<MySession>
          tableName="active-sessions"
          columns={columns}
          data={sessions}
          itemCount={total}
          pageIndex={pageIndex}
          onPageChange={setPageIndex}
          pageSize={pageSize}
          onPageSizeChange={setPageSize}
          pageSizeOptions={[5, 10, 20]}
          refresh={refetch}
          isLoading={isFetching}
          emptyText={t('profile.sessions.empty')}
        />
      </Stack>

      <ConfirmModal
        opened={pending !== null}
        onClose={() => setPending(null)}
        onConfirm={onConfirm}
        loading={isRevoking}
        title={t('profile.sessions.confirm.title')}
        message={confirmMessage()}
        confirmLabel={t('profile.sessions.revoke')}
        cancelLabel={t('common.cancel', 'Cancel')}
      />
    </Paper>
  );
}
