import { useEffect, useState } from 'react';

import {
  Alert,
  Box,
  Button,
  Chip,
  Divider,
  Stack,
  Switch,
  TextField,
  Typography,
} from '@mui/material';
import { type Meta, type StoryObj } from '@storybook/react-vite';

import { useAutoSave } from '.';

const STATUS_COLORS: Record<
  string,
  'default' | 'warning' | 'success' | 'error'
> = {
  idle: 'default',
  saving: 'warning',
  saved: 'success',
  error: 'error',
};

const formatTimeAgo = (date: Date | null) => {
  if (!date) return '—';
  const seconds = Math.floor((Date.now() - date.getTime()) / 1000);
  if (seconds < 5) return 'just now';
  if (seconds < 60) return `${seconds}s ago`;
  return `${Math.floor(seconds / 60)}m ago`;
};

type DemoProps = {
  debounceMs?: number;
  shouldFail?: boolean;
  saveDelayMs?: number;
};

const useMockSave = (saveDelayMs: number, failNext: boolean) => {
  const [savedValue, setSavedValue] = useState('Hello world');
  const [saveLog, setSaveLog] = useState<string[]>([]);

  const onSave = async (v: string) => {
    const timestamp = new Date().toLocaleTimeString();
    await new Promise((resolve, reject) =>
      setTimeout(
        () =>
          failNext ? reject(new Error('Simulated error')) : resolve(undefined),
        saveDelayMs,
      ),
    );

    if (!failNext) {
      setSavedValue(v);
      setSaveLog(prev => [
        `[${timestamp}] Saved: "${v.length > 40 ? `${v.slice(0, 40)}…` : v}"`,
        ...prev.slice(0, 9),
      ]);
    }
  };

  return { savedValue, saveLog, onSave };
};

const AutoSaveDemo = ({
  debounceMs = 2000,
  shouldFail = false,
  saveDelayMs = 800,
}: DemoProps) => {
  const [failNext, setFailNext] = useState(shouldFail);
  const { savedValue, saveLog, onSave } = useMockSave(saveDelayMs, failNext);
  const [value, setValue] = useState(savedValue);
  const [now, setNow] = useState(Date.now());

  useEffect(() => {
    const interval = setInterval(() => setNow(Date.now()), 1000);
    return () => clearInterval(interval);
  }, []);

  const { status, lastSavedAt, retrySave } = useAutoSave({
    value,
    savedValue,
    onSave,
    debounceMs,
  });

  return (
    <Stack sx={{ gap: 3, p: 2, maxWidth: 600 }}>
      <Stack sx={{ gap: 1 }}>
        <Stack
          sx={{
            flexDirection: 'row',
            alignItems: 'center',
            justifyContent: 'space-between',
          }}
        >
          <Typography variant="subtitle2">Article Body</Typography>
          <Stack sx={{ flexDirection: 'row', alignItems: 'center', gap: 1.5 }}>
            <Chip
              label={status}
              color={STATUS_COLORS[status]}
              size="small"
              variant="outlined"
            />
            <Typography
              variant="caption"
              sx={{ color: 'text.secondary', minWidth: 60, textAlign: 'right' }}
              key={now}
            >
              {formatTimeAgo(lastSavedAt)}
            </Typography>
          </Stack>
        </Stack>

        <TextField
          multiline
          minRows={4}
          maxRows={10}
          value={value}
          onChange={e => setValue(e.target.value)}
          placeholder="Type something… changes auto-save after debounce"
          fullWidth
        />
      </Stack>

      <Divider />

      <Typography
        variant="caption"
        sx={{ fontWeight: 600 }}
      >
        Debug panel
      </Typography>

      <Stack
        sx={{
          flexDirection: 'row',
          alignItems: 'center',
          gap: 2,
          p: 1.5,
          borderRadius: 1,
          bgcolor: 'action.hover',
        }}
      >
        <Switch
          checked={failNext}
          onChange={(_, checked) => setFailNext(checked)}
          size="small"
        />
        <Typography variant="body2">Simulate save failure</Typography>
        {status === 'error' && (
          <Button
            size="small"
            variant="outlined"
            color="error"
            onClick={retrySave}
          >
            Retry
          </Button>
        )}
      </Stack>

      <Stack sx={{ flexDirection: 'row', alignItems: 'center', gap: 2 }}>
        <Typography
          variant="caption"
          sx={{ color: 'text.secondary' }}
        >
          Debounce: {debounceMs}ms · Save delay: {saveDelayMs}ms
        </Typography>
      </Stack>

      <Box sx={{ display: 'flex', gap: 1 }}>
        <Alert
          severity={value === savedValue ? 'success' : 'info'}
          sx={{ flex: 1, py: 0 }}
        >
          {value === savedValue ? 'In sync with server' : 'Pending changes'}
        </Alert>
      </Box>

      {saveLog.length > 0 && (
        <Stack sx={{ gap: 0.5 }}>
          <Typography
            variant="caption"
            sx={{ fontWeight: 600 }}
          >
            Save log
          </Typography>
          {saveLog.map((entry, i) => (
            <Typography
              key={i}
              variant="caption"
              sx={{ fontFamily: 'monospace', color: 'text.secondary' }}
            >
              {entry}
            </Typography>
          ))}
        </Stack>
      )}
    </Stack>
  );
};

const meta: Meta = {
  title: 'Hooks/useAutoSave',
  tags: ['autodocs'],
  parameters: {
    docs: {
      description: {
        component:
          'Generic auto-save hook. Debounces value changes, tracks save status (idle/saving/saved/error) and lastSavedAt timestamp. Protects against data loss with beforeunload and flush-on-unmount.',
      },
    },
  },
};

export default meta;

type Story = StoryObj<typeof meta>;

export const Default: Story = {
  render: () => <AutoSaveDemo />,
  parameters: {
    docs: {
      description: {
        story:
          'Type in the text area — changes auto-save after a 2s debounce. The status chip and relative timestamp update in real time.',
      },
    },
  },
};

export const FastDebounce: Story = {
  render: () => (
    <AutoSaveDemo
      debounceMs={500}
      saveDelayMs={300}
    />
  ),
  parameters: {
    docs: {
      description: {
        story:
          'Same behavior with a 500ms debounce and 300ms save delay for a snappier feel.',
      },
    },
  },
};

export const WithError: Story = {
  render: () => <AutoSaveDemo shouldFail />,
  parameters: {
    docs: {
      description: {
        story:
          'Starts with simulated failures enabled. Toggle the switch off and use the Retry button to recover.',
      },
    },
  },
};

export const SlowNetwork: Story = {
  render: () => <AutoSaveDemo saveDelayMs={3000} />,
  parameters: {
    docs: {
      description: {
        story:
          'Simulates a slow network with a 3s save delay. The "saving" status stays visible longer.',
      },
    },
  },
};
