import { useMemo } from 'react';
import { Box, Text } from '@chakra-ui/react';

import { CodeTab, PreviewTab, TabsLayout } from '../../components/common/TabsLayout';
import Customize from '../../components/common/Preview/Customize';
import CodeExample from '../../components/code/CodeExample';
import PropTable from '../../components/common/Preview/PropTable';
import PreviewInput from '../../components/common/Preview/PreviewInput';
import PreviewSelect from '../../components/common/Preview/PreviewSelect';
import PreviewSlider from '../../components/common/Preview/PreviewSlider';
import PreviewSwitch from '../../components/common/Preview/PreviewSwitch';
import PreviewColorPickerCustom from '../../components/common/Preview/PreviewColorPickerCustom';

import useComponentProps from '../../hooks/useComponentProps';
import { ComponentPropsProvider } from '../../components/context/ComponentPropsContext';
import { useColorModeValue } from '../../components/setup/color-mode';

import TextCursor from '../../content/TextAnimations/TextCursor/TextCursor';
import { textCursor } from '../../constants/code/TextAnimations/textCursorCode';

const LOOK = {
  text: 'Hello',
  mode: 'stamp',
  fontSize: 28,
  spacing: 88,
  maxPoints: 7,
  shrink: 0.5,
  fade: 0.6,
  smoothing: 0.3,
  exitDuration: 0.5,
  removalInterval: 30,
  followMouseDirection: true,
  keepUpright: true,
  randomFloat: true,
  popIn: true
};

const PRESETS = {
  words: { ...LOOK },
  emoji: { ...LOOK, text: '✨', fontSize: 30, spacing: 46, maxPoints: 10, shrink: 0.6, fade: 0.5 },
  chain: {
    ...LOOK,
    text: '→',
    mode: 'chain',
    fontSize: 24,
    spacing: 22,
    maxPoints: 18,
    shrink: 0.55,
    fade: 0.75,
    randomFloat: false
  },
  ribbon: {
    ...LOOK,
    text: 'React Bits follows your cursor ✦ ',
    mode: 'ribbon',
    fontSize: 26,
    spacing: 1,
    shrink: 0.35,
    fade: 0.7,
    smoothing: 0.4
  }
};

const DEFAULT_PROPS = {
  preset: 'words',
  ...LOOK,
  textColor: '',
  hideCursor: false
};

const PRESET_OPTIONS = [
  { value: 'words', label: 'Words' },
  { value: 'emoji', label: 'Emoji' },
  { value: 'chain', label: 'Chain' },
  { value: 'ribbon', label: 'Ribbon' }
];

const MODE_OPTIONS = [
  { value: 'stamp', label: 'Stamp' },
  { value: 'chain', label: 'Chain' },
  { value: 'ribbon', label: 'Ribbon' }
];

const propData = [
  { name: 'text', type: 'string', default: "'Hello'", description: 'The text or emoji the trail is made of.' },
  {
    name: 'mode',
    type: "'stamp' | 'chain' | 'ribbon'",
    default: "'stamp'",
    description:
      'Stamp leaves copies along the path, chain makes copies follow each other like a snake, and ribbon lays the letters along the path.'
  },
  {
    name: 'spacing',
    type: 'number',
    default: '88',
    description: 'Distance between copies, in px. In ribbon mode, extra space between letters.'
  },
  {
    name: 'maxPoints',
    type: 'number',
    default: '7',
    description: 'Most copies shown at once in stamp and chain modes.'
  },
  { name: 'color', type: 'string', default: "'currentColor'", description: 'Color of the text.' },
  { name: 'fontSize', type: 'number', default: '28', description: 'Font size of the text, in px.' },
  { name: 'fontWeight', type: 'number | string', default: '600', description: 'Font weight of the text.' },
  { name: 'fontFamily', type: 'string', default: "'inherit'", description: 'Font family of the text.' },
  {
    name: 'shrink',
    type: 'number',
    default: '0.5',
    description: 'How much smaller the trail gets toward its end, from 0 to 1.'
  },
  {
    name: 'fade',
    type: 'number',
    default: '0.6',
    description: 'How much the trail fades toward its end, from 0 to 1.'
  },
  {
    name: 'smoothing',
    type: 'number',
    default: '0.3',
    description: 'Softens the path the trail follows, from 0 to 1. Higher values lag a little behind the cursor.'
  },
  {
    name: 'followMouseDirection',
    type: 'boolean',
    default: 'true',
    description: 'Turns the text to face the direction the cursor moves.'
  },
  {
    name: 'randomFloat',
    type: 'boolean',
    default: 'true',
    description: 'Lets stamped copies sway gently, and makes chains and ribbons ripple.'
  },
  { name: 'popIn', type: 'boolean', default: 'true', description: 'Makes new copies pop in with a little overshoot.' },
  {
    name: 'keepUpright',
    type: 'boolean',
    default: 'true',
    description: 'In stamp mode, keeps copies from turning upside down when the cursor moves left.'
  },
  {
    name: 'exitDuration',
    type: 'number',
    default: '0.5',
    description: 'How long a stamped copy takes to shrink away, in seconds.'
  },
  {
    name: 'removalInterval',
    type: 'number',
    default: '30',
    description: 'How quickly the trail pulls back into the cursor once it stops, in ms per copy.'
  },
  { name: 'hideCursor', type: 'boolean', default: 'false', description: 'Hides the system cursor over the element.' },
  { name: 'className', type: 'string', default: "''", description: 'Extra class names for the container.' },
  { name: 'style', type: 'CSSProperties', default: '-', description: 'Inline styles for the container.' }
];

const TextCursorDemo = () => {
  const { props, defaultProps, updateProp, updateProps, resetProps, hasChanges } = useComponentProps(DEFAULT_PROPS);
  const { preset, textColor, ...settings } = props;
  const ink = useColorModeValue('#18181b', '#ffffff');

  const applyPreset = value => {
    const base = Object.fromEntries(Object.keys(LOOK).map(name => [name, defaultProps[name]]));
    updateProps({ ...base, ...PRESETS[value], preset: value });
  };

  const computedProps = useMemo(() => (textColor ? { color: textColor } : {}), [textColor]);

  return (
    <ComponentPropsProvider
      props={props}
      defaultProps={DEFAULT_PROPS}
      resetProps={resetProps}
      hasChanges={hasChanges}
      demoOnlyProps={['preset', 'textColor']}
      computedProps={computedProps}
    >
      <TabsLayout>
        <PreviewTab>
          <Box position="relative" className="demo-container" h={460} p={0} overflow="hidden">
            <Text
              position="absolute"
              bottom={5}
              left="50%"
              transform="translateX(-50%)"
              fontSize="sm"
              color="var(--text-dimmed)"
              userSelect="none"
              pointerEvents="none"
            >
              Move around
            </Text>
            <TextCursor {...settings} color={textColor || 'currentColor'} />
          </Box>

          <Customize>
            <PreviewSelect title="Preset" options={PRESET_OPTIONS} value={preset} onChange={applyPreset} />
            <PreviewInput
              title="Text"
              value={settings.text}
              placeholder="Enter text..."
              width={180}
              maxLength={40}
              onChange={value => updateProp('text', value)}
            />
            <PreviewColorPickerCustom
              title="Color"
              color={textColor || ink}
              onChange={value => updateProp('textColor', value)}
            />
            <PreviewSelect
              title="Mode"
              options={MODE_OPTIONS}
              value={settings.mode}
              onChange={value => updateProp('mode', value)}
            />
            <PreviewSlider
              title="Font Size"
              min={12}
              max={72}
              step={1}
              value={settings.fontSize}
              valueUnit="px"
              onChange={value => updateProp('fontSize', value)}
            />
            <PreviewSlider
              title="Spacing"
              min={0}
              max={200}
              step={1}
              value={settings.spacing}
              valueUnit="px"
              onChange={value => updateProp('spacing', value)}
            />
            <PreviewSlider
              title="Max Points"
              min={1}
              max={30}
              step={1}
              value={settings.maxPoints}
              onChange={value => updateProp('maxPoints', value)}
            />
            <PreviewSlider
              title="Shrink"
              min={0}
              max={1}
              step={0.05}
              value={settings.shrink}
              onChange={value => updateProp('shrink', value)}
            />
            <PreviewSlider
              title="Fade"
              min={0}
              max={1}
              step={0.05}
              value={settings.fade}
              onChange={value => updateProp('fade', value)}
            />
            <PreviewSlider
              title="Smoothing"
              min={0}
              max={1}
              step={0.05}
              value={settings.smoothing}
              onChange={value => updateProp('smoothing', value)}
            />
            <PreviewSlider
              title="Exit Duration"
              min={0.1}
              max={2}
              step={0.05}
              value={settings.exitDuration}
              valueUnit="s"
              onChange={value => updateProp('exitDuration', value)}
            />
            <PreviewSlider
              title="Removal Interval"
              min={5}
              max={200}
              step={5}
              value={settings.removalInterval}
              valueUnit="ms"
              onChange={value => updateProp('removalInterval', value)}
            />
            <PreviewSwitch
              title="Follow Mouse Direction"
              isChecked={settings.followMouseDirection}
              onChange={value => updateProp('followMouseDirection', value)}
            />
            <PreviewSwitch
              title="Keep Upright"
              isChecked={settings.keepUpright}
              onChange={value => updateProp('keepUpright', value)}
            />
            <PreviewSwitch
              title="Random Float"
              isChecked={settings.randomFloat}
              onChange={value => updateProp('randomFloat', value)}
            />
            <PreviewSwitch title="Pop In" isChecked={settings.popIn} onChange={value => updateProp('popIn', value)} />
            <PreviewSwitch
              title="Hide Cursor"
              isChecked={settings.hideCursor}
              onChange={value => updateProp('hideCursor', value)}
            />
          </Customize>

          <PropTable data={propData} />
        </PreviewTab>

        <CodeTab>
          <CodeExample codeObject={textCursor} componentName="TextCursor" />
        </CodeTab>
      </TabsLayout>
    </ComponentPropsProvider>
  );
};

export default TextCursorDemo;