import {createStore, sample} from "effector";

import {$word} from "@/entites/word/index.js";
import {
  checkUserGuess,
  initUserGuess,
  revealRandomSymbol,
  revealSymbol,
  setSymbol
} from "@/features/input-word/model/events.js";


export const $userGuess = createStore([]);
export const $userGuessLength = $userGuess.map((guesses) => guesses.length);
export const $userGuessString = $userGuess.map((guesses) =>
  guesses.map(({value}) => value).join(''));

$userGuess.on(initUserGuess, (_, wordLength) => {
  return new Array(wordLength)
    .fill(null)
    .map((_, idx) => ({
      idx, value: '',
      isRevealed: false
    }));
});

sample({
  clock: revealRandomSymbol,
  source: {userGuess: $userGuess, word: $word},
  fn: ({ userGuess, word }) => {
    const unrevealedIndexes = userGuess.reduce((acc, symbol, idx) =>
      !symbol.isRevealed ? [...acc, idx] : acc, []
    );

  const randomUnrevealedIdx = unrevealedIndexes[Math.floor(Math.random() * unrevealedIndexes.length)];

    return userGuess.map((symbol, idx) => ({
      ...symbol,
      value: idx === randomUnrevealedIdx || symbol.isRevealed ? word[idx] : symbol.value,
      isRevealed: idx === randomUnrevealedIdx || symbol.isRevealed
    }));
  },
  target: $userGuess,
});

sample({
  clock: checkUserGuess,
  source: { userGuess: $userGuess, word: $word },
  fn: ({ userGuess, word }) => {
    const updatedUserGuess = userGuess.map((symbol, idx) => {
      const newIsRevealed = symbol.isRevealed || word[idx] === symbol.value;
      if (newIsRevealed === symbol.isRevealed) {
        return symbol;
      }
      return {
        ...symbol,
        isRevealed: newIsRevealed,
      };
    });
    return updatedUserGuess;
  },
  target: $userGuess,
});












sample({
  clock: setSymbol,
  source: { userGuess: $userGuess },
  fn: ({ userGuess }, { value, idx }) => {
    const updatedUserGuess = [...userGuess];
    updatedUserGuess[idx] = {
      ...userGuess[idx],
      value,
    };
    return updatedUserGuess;
  },
  target: $userGuess,
}); import {useUnit} from 'effector-react';
import React, {useEffect, useRef, useCallback} from 'react';

import {SymbolInput} from '@/features/input-word/ui/symbol-input/index.jsx';
import * as styles from './word-input.module.css';
import {$userGuess} from '@/features/input-word/model/store.js';
import {checkUserGuess, initUserGuess} from "@/features/input-word/model/events.js";

export const WordInput = ({}) => {
  const userGuess = useUnit($userGuess);
  const userGuessRef = useRef([]);
  const inputRefs = useRef([]);

  const focusNextUnopenedSymbol = useCallback((currentIdx, step) => {
    for(let i = currentIdx + step; i >= 0 && i < userGuess.length; i += step) {
      if(!userGuess[i].isRevealed && inputRefs.current[i]) {
        inputRefs.current[i].focus();
        return;
      }
    }

    requestAnimationFrame(() => {
      inputRefs.current[currentIdx].focus();
    })
  }, [userGuess]);

  const focusNextSymbol = useCallback((currentIdx) => {
    focusNextUnopenedSymbol(currentIdx, 1);
  }, [focusNextUnopenedSymbol]);

  const focusPrevSymbol = useCallback((currentIdx) => {
    focusNextUnopenedSymbol(currentIdx, -1);
  }, [focusNextUnopenedSymbol]);

  useEffect(() => {
    const handleEnter  = (event) => {
      if(event.key !== 'Enter') return;
      checkUserGuess();
    }

    document.addEventListener('keydown', handleEnter);

    return () => document.removeEventListener('keydown', handleEnter);
  }, []);

  useEffect(() => {
    console.log('788787')
  });

  return (
    <div className={styles.wordDisplay}>
      { userGuess.map(({idx, value, isRevealed}) =>
        <SymbolInput
          key={idx}
          ref={el => inputRefs.current[idx] = el}
          idx={idx}
          focusNext={focusNextSymbol}
          focusPrev={focusPrevSymbol}
        />
      )}
    </div>
  );
};import React, {forwardRef, useEffect, useState} from 'react';
import {useUnit} from "effector-react/compat";

import * as styles from './symbol-input.module.css';
import {TEXT_REGEX} from "@/shared/constants/index.js";
import {setSymbol} from "@/features/input-word/model/events.js";
import {$userGuess} from "@/features/input-word/model/store.js";
import {useStoreMap} from "effector-react";

const CSS_CLASS_OPENED = styles['symbol-opened']

export const SymbolInput = React.memo(forwardRef((
  {idx, focusNext, focusPrev, onEnterKeydown},
  ref
) => {
  const { value, isRevealed } = useStoreMap({
    store: $userGuess,
    keys: [idx],
    fn: (symbols, [idx]) => symbols[idx],
  });
  const symbolClasses = `${styles.symbol} ${isRevealed ? CSS_CLASS_OPENED : ''}`;

  const handleInput = (key) => {
    const formattedKey = key.toLowerCase();
    if(TEXT_REGEX.test(formattedKey) && formattedKey.length === 1) {
      setSymbol({value: formattedKey, idx});
      focusNext(idx);
    }
  };

  const handleKeyDown = (e) => {
    switch (e.key) {
      case 'ArrowLeft': focusPrev(idx); break;
      case 'ArrowRight': focusNext(idx); break;
      case 'Backspace':
        e.preventDefault();
        setSymbol({value: '', idx});
        focusPrev(idx);
        break;
      default: handleInput(e.key); break;
    }
  };

  useEffect(() => {
   console.log('render');
  });

  return (
    <input
      ref={ref}
      type={'text'}
      className={symbolClasses}
      disabled={isRevealed}
      maxLength={1}
      value={value}
      onKeyDown={handleKeyDown}
    >
    </input>
  );
}), (prevProps, nextProps) => nextProps.value === prevProps.value && nextProps.isRevealed === prevProps.isRevealed && nextProps.idx === prevProps.idx); нужно чтобы не перерендервался wordInpt а только те символы в которые ввожу но у меня каждый ввод перерендеревается wordInput