import React, { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { Text, Switch, Button, color, Spinner } from 'folds';
import { SettingTile } from '../../../components/setting-tile';
import { SettingsSection } from '../SettingsSection';
import { useSetting } from '../../../state/hooks/settings';
import { settingsAtom } from '../../../state/settings';
import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback';
import {
  useRegisterPushNotifications,
  useDisablePushNotifications,
  usePushNotificationStatus,
  usePushEnabled,
} from '../../../hooks/usePushNotifications';

const noop = (): void => undefined;

function PushNotification() {
  const { t } = useTranslation();
  const status = usePushNotificationStatus();
  const register = useRegisterPushNotifications();
  const disable = useDisablePushNotifications();

  // Source of truth: setPushEnabled() in utils/push.ts fans out a custom event
  // that this hook listens for, so the toggle reflects changes made elsewhere
  // (e.g. the global PushPermissionPrompt on first login).
  const enabled = usePushEnabled();

  const [enableState, enable] = useAsyncCallback(
    useCallback(async () => {
      await register();
    }, [register])
  );

  const [disableState, doDisable] = useAsyncCallback(
    useCallback(async () => {
      await disable();
    }, [disable])
  );

  if (status === 'unavailable') return null;

  const busy =
    enableState.status === AsyncStatus.Loading || disableState.status === AsyncStatus.Loading;

  let description: React.ReactNode = <span>{t('Settings.push_description')}</span>;
  // A permission denial surfaces as both status='denied' AND enableState.error, but
  // the status change is async on native (checkPermissions round-trip) while the
  // error lands synchronously. Check the error reason first to avoid a flash of
  // the generic push_error before the permission-specific message.
  const permissionDenied =
    status === 'denied' ||
    (enableState.status === AsyncStatus.Error &&
      (enableState.error as Error | undefined)?.message === 'permission_denied');
  if (permissionDenied) {
    description = (
      <Text as="span" style={{ color: color.Critical.Main }} size="T200">
        {t('Settings.push_permission_blocked')}
      </Text>
    );
  } else if (enableState.status === AsyncStatus.Error) {
    description = (
      <Text as="span" style={{ color: color.Critical.Main }} size="T200">
        {t('Settings.push_error')}
      </Text>
    );
  }

  // useAsyncCallback re-throws after recording the error state, so every call
  // site needs .catch — otherwise expected flows like permission_denied turn
  // into unhandled promise rejections.
  let after: React.ReactNode = (
    <Switch
      disabled={status === 'denied'}
      value={enabled}
      onChange={(val) => (val ? enable().catch(noop) : doDisable().catch(noop))}
    />
  );
  if (busy) {
    after = <Spinner variant="Secondary" />;
  } else if (status === 'prompt' && !enabled) {
    after = (
      <Button size="300" radii="300" onClick={() => enable().catch(noop)}>
        <Text size="B300">{t('Settings.enable')}</Text>
      </Button>
    );
  }

  return (
    <SettingTile title={t('Settings.push_notifications')} description={description} after={after} />
  );
}

export function SystemNotification() {
  const { t } = useTranslation();
  const [isNotificationSounds, setIsNotificationSounds] = useSetting(
    settingsAtom,
    'isNotificationSounds'
  );
  const [inviteSpamFilter, setInviteSpamFilter] = useSetting(settingsAtom, 'inviteSpamFilter');
  // Gate the push row at the call site: PushNotification renders null when push
  // is unavailable, and SettingsSection's `filter(Boolean)` can only drop
  // JSX-level falsy children — a returned-null component would otherwise leave
  // an empty bordered first row in the grouped panel.
  const pushStatus = usePushNotificationStatus();

  return (
    <SettingsSection label={t('Settings.system')}>
      {pushStatus !== 'unavailable' && <PushNotification />}
      <SettingTile
        title={t('Settings.notification_sound')}
        description={t('Settings.notification_sound_desc')}
        after={<Switch value={isNotificationSounds} onChange={setIsNotificationSounds} />}
      />
      <SettingTile
        title={t('Settings.invite_spam_filter')}
        description={t('Settings.invite_spam_filter_desc')}
        after={<Switch value={inviteSpamFilter} onChange={setInviteSpamFilter} />}
      />
    </SettingsSection>
  );
}
