'use client';
import { useMemo, useState } from 'react';
import { useLocale, useTranslations } from 'next-intl';
import { useSnackbar } from 'notistack';
import {
  Box,
  Dialog,
  DialogActions,
  DialogContent,
  DialogContentText,
  DialogTitle,
  Drawer,
  FormControlLabel,
  Skeleton,
  Stack,
  Switch,
  TextField,
  Typography,
} from '@mui/material';
import { AppButton, AppIcon } from '@/components';
import { AdminEmptyState, AdminErrorState, AdminPageHeader, ConfigRow } from '@/components/admin';
import { formatShamsiDateTime } from '@/utils';
import { useAdminCapabilities } from '@/hooks';
import { CONFIG_GROUPS, RATE_CONFIG_KEYS } from '@/services/admin/constants';
import type { PlatformConfig } from '@/services/admin/types';
import { usePlatformConfigs, useUpdatePlatformConfig, useConfigChangeHistory } from '@/services/admin';

const GROUP_ORDER = ['fees', 'deadlines', 'evv', 'bnpl', 'cancellation', 'other'] as const;
type GroupKey = (typeof GROUP_ORDER)[number];

/** Validate a candidate value against a config's `data_type` (+ the 0–1 rate rule). Returns an i18n key or null. */
function validate(config: PlatformConfig, value: string): string | null {
  const trimmed = value.trim();
  if (trimmed.length === 0) return 'cfg_empty_error';
  if (config.dataType === 'int') {
    if (!/^-?\d+$/.test(trimmed)) return 'cfg_int_error';
  }
  if (config.dataType === 'int' || config.dataType === 'decimal') {
    const n = Number(trimmed);
    if (Number.isNaN(n)) return 'cfg_int_error';
    if (RATE_CONFIG_KEYS.includes(config.key) && (n < 0 || n > 1)) return 'cfg_range_error';
  }
  if (config.dataType === 'json') {
    try {
      JSON.parse(trimmed);
    } catch {
      return 'cfg_json_error';
    }
  }
  return null;
}

/**
 * Platform config editor (f15) — every `platform_configs` row grouped by concern, each with a typed input
 * by `data_type` and boundary validation (a rate is 0–1). Saving is audited server-side and takes effect
 * immediately without re-pricing already-computed rows — the save dialog says so. The change-history drawer
 * proves the value in effect at any past moment. The client never re-parses config beyond rendering by
 * `data_type` (phase §5).
 */
export default function AdminConfigPage() {
  const t = useTranslations('admin');
  const caps = useAdminCapabilities();
  const configs = usePlatformConfigs(1);
  const [editing, setEditing] = useState<PlatformConfig | null>(null);
  const [historyKey, setHistoryKey] = useState<string | null>(null);

  const grouped = useMemo(() => {
    const items = configs.data?.items ?? [];
    const byKey = new Map(Object.entries(CONFIG_GROUPS).flatMap(([g, keys]) => keys.map((k) => [k, g as GroupKey])));
    const result: Record<GroupKey, PlatformConfig[]> = { fees: [], deadlines: [], evv: [], bnpl: [], cancellation: [], other: [] };
    for (const c of items) result[byKey.get(c.key) ?? 'other'].push(c);
    return result;
  }, [configs.data]);

  return (
    <Box sx={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
      <AdminPageHeader title={t('cfg_title')} subtitle={t('cfg_subtitle')} />

      {configs.isLoading ? (
        <Stack sx={{ gap: 2 }}>{[0, 1, 2].map((k) => <Skeleton key={k} variant="rounded" height={96} />)}</Stack>
      ) : configs.isError ? (
        <AdminErrorState message={t('error_generic')} retryLabel={t('retry')} onRetry={() => configs.refetch()} />
      ) : (configs.data?.items.length ?? 0) === 0 ? (
        <AdminEmptyState icon="config" title={t('cfg_title')} />
      ) : (
        GROUP_ORDER.filter((g) => grouped[g].length > 0).map((g) => (
          <Stack key={g} sx={{ gap: 1.5 }}>
            <Typography variant="overline" sx={{ color: 'text.secondary', fontWeight: 700 }}>
              {t(`cfg_group_${g}`)}
            </Typography>
            {grouped[g].map((config) => (
              <ConfigRow
                key={config.key}
                config={config}
                canEdit={caps.canConfig}
                onEdit={setEditing}
                onHistory={(c) => setHistoryKey(c.key)}
              />
            ))}
          </Stack>
        ))
      )}

      {editing ? <ConfigEditDialog config={editing} onClose={() => setEditing(null)} /> : null}
      <ConfigHistoryDrawer configKey={historyKey} onClose={() => setHistoryKey(null)} />
    </Box>
  );
}

/** The typed, validated, audited edit dialog for one config row. */
function ConfigEditDialog({ config, onClose }: { config: PlatformConfig; onClose: () => void }) {
  const t = useTranslations('admin');
  const { enqueueSnackbar } = useSnackbar();
  const update = useUpdatePlatformConfig();
  const [value, setValue] = useState(config.value);

  const errorKey = validate(config, value);
  const isBool = config.dataType === 'bool';

  const onSave = () => {
    if (errorKey) return;
    update.mutate(
      { key: config.key, value: isBool ? value : value.trim() },
      {
        onSuccess: () => {
          enqueueSnackbar(t('cfg_saved'), { variant: 'success' });
          onClose();
        },
      },
    );
  };

  return (
    <Dialog open onClose={update.isPending ? undefined : onClose} fullWidth maxWidth="sm">
      <DialogTitle sx={{ fontWeight: 800, fontFamily: 'monospace' }}>{config.key}</DialogTitle>
      <DialogContent>
        {config.description ? (
          <DialogContentText sx={{ mb: 2 }}>{config.description}</DialogContentText>
        ) : null}

        {isBool ? (
          <FormControlLabel
            control={<Switch checked={value === 'true'} onChange={(e) => setValue(e.target.checked ? 'true' : 'false')} />}
            label={t(`dtype_bool`)}
          />
        ) : (
          <TextField
            fullWidth
            autoFocus
            multiline={config.dataType === 'json'}
            minRows={config.dataType === 'json' ? 4 : 1}
            type={config.dataType === 'int' || config.dataType === 'decimal' ? 'text' : 'text'}
            value={value}
            onChange={(e) => setValue(e.target.value)}
            label={t('cfg_col_value')}
            error={!!errorKey}
            helperText={errorKey ? t(errorKey) : undefined}
            slotProps={{ input: { sx: config.dataType === 'json' ? { fontFamily: 'monospace' } : undefined } }}
          />
        )}

        <DialogContentText sx={{ mt: 2, color: 'var(--bal-warning)', fontWeight: 500 }}>
          {t('cfg_save_confirm_body')}
        </DialogContentText>
      </DialogContent>
      <DialogActions sx={{ px: 3, pb: 2 }}>
        <AppButton variant="text" color="inherit" onClick={onClose} disabled={update.isPending}>
          {t('cancel')}
        </AppButton>
        <AppButton variant="contained" color="primary" onClick={onSave} disabled={!!errorKey || update.isPending}>
          {update.isPending ? t('saving') : t('save')}
        </AppButton>
      </DialogActions>
    </Dialog>
  );
}

/** The change-history drawer for one config key. */
function ConfigHistoryDrawer({ configKey, onClose }: { configKey: string | null; onClose: () => void }) {
  const t = useTranslations('admin');
  const locale = useLocale();
  const history = useConfigChangeHistory(configKey, 1, configKey != null);
  // RTL-aware: the drawer slides from the reading-end (left on fa/RTL, right on en/LTR).
  const anchor = locale === 'fa' ? 'left' : 'right';

  return (
    <Drawer anchor={anchor} open={configKey != null} onClose={onClose} slotProps={{ paper: { sx: { width: { xs: '100%', sm: 420 }, p: 3 } } }}>
      <Stack direction="row" sx={{ justifyContent: 'space-between', alignItems: 'center', mb: 2 }}>
        <Typography variant="h6">{configKey ? t('cfg_history_title', { key: configKey }) : ''}</Typography>
        <AppButton variant="text" color="inherit" onClick={onClose} sx={{ minWidth: 0 }}>
          <AppIcon icon="close" />
        </AppButton>
      </Stack>

      {history.isLoading ? (
        <Stack sx={{ gap: 1 }}>{[0, 1].map((k) => <Skeleton key={k} variant="rounded" height={64} />)}</Stack>
      ) : (history.data?.items.length ?? 0) === 0 ? (
        <Typography variant="body2" sx={{ color: 'text.secondary' }}>
          {t('cfg_history_empty')}
        </Typography>
      ) : (
        <Stack sx={{ gap: 1.5 }}>
          {history.data?.items.map((change) => (
            <Box key={change.id} sx={{ border: '1px solid', borderColor: 'divider', borderRadius: 2, p: 1.5 }}>
              <Typography variant="body2" sx={{ fontFamily: 'monospace', fontWeight: 700 }}>
                {t('cfg_history_change', { old: change.oldValue ?? '—', new: change.newValue ?? '—' })}
              </Typography>
              <Typography variant="caption" sx={{ color: 'text.secondary' }}>
                {formatShamsiDateTime(change.occurredAt, locale)}
                {change.actorUserId != null ? ` · #${change.actorUserId}` : ''}
              </Typography>
            </Box>
          ))}
        </Stack>
      )}
    </Drawer>
  );
}
