import "./style.pcss";

import { getMergedObj } from "@web3r/flowerkit/obj";
import type {
  FC, ReactNode, ReactElement, PropsWithChildren,
} from "react";
import {
  Children,
  cloneElement,
  isValidElement,
  useMemo,
} from "react";
import { Translation } from "react-i18next";
import type { ILocale, TTranslation } from "./config/types";
import { useMessage, getIsAttr, getUserAttrs } from "./lib";
import { constants } from "../../constants";
import type { IComponentBaseProps } from "../../types/components";
import { useCN } from "../../utils/react/useCN";
import { useLocalisationPlugin } from "../../utils/react/useLocalisationPlugin";
import { useSSGRender } from "../../utils/react/useSSGRender";


/**
 * Вывод данных локализации
 * @returns {ReactNode}
 */
const Message: FC<ILocale & PropsWithChildren<TTranslation>> = ({
  fn,
  code,
  options,
  instance,
  attr,
  children,
}): ReactNode => {

  const { message } = useMessage({
    fn, code, instance, options,
  });

  const isAttr = getIsAttr(attr);

  if (isAttr && !!children) { // перевод только указанного атрибута для единственного дочернего элемента

    return Children
      .toArray(children)
      .filter((child) => isValidElement(child))
      .map((child, index) => {

        const userAttrs = typeof attr === "string" ? getUserAttrs({
          [attr]: message,
        }) : getUserAttrs(Object.fromEntries((attr as string[]).map((str) => [ str, message ])));

        const currentProps: PropsWithChildren<typeof child.props & {
          key: number;
        }> = {
          ...(child?.props ?? {}),
          key: index,
        };

        const computedProps = getMergedObj(currentProps, userAttrs);

        return cloneElement(child, computedProps, currentProps.children);
      });
  } else { // возвращение перевода как дочернего текста
    return message;
  }
};


/**
 * Компонент вывода локали
 * @returns {ReactElement}
 */
const Locale: FC<IComponentBaseProps & ILocale> = (props): ReactElement => {

  const {
    baseClass = "locale",
    extraClasses = {},
    extraAttrs = {},
    children,
    code,
    attr,
    options = {},
    ns,
  } = props;

  const { getCN } = useCN(baseClass);

  const { isLoading, isError, isReady } = useLocalisationPlugin(code);

  const utilClasses = useMemo<string[]>(() => {
    switch (true) {
      case isReady: {
        return [ constants.stateClasses.translated ];
      }
      case isError: {
        return [ constants.stateClasses.translationError ];
      }
      case isLoading:
      default: {
        return [ constants.stateClasses.translationLoading ];
      }
    }
  }, [ isLoading, isError, isReady ]);

  const metaAttr = useMemo<string>(() => {
    return JSON.stringify({
      code,
      options,
      attr,
    });
  }, [ code, options, attr ]);

  const SSGComponent = useSSGRender("data-js-locale", props, "ins", baseClass);

  if (SSGComponent) {
    return SSGComponent;
  }

  return (
    <ins data-js-locale={metaAttr} className={getCN("", extraClasses, utilClasses)} {...extraAttrs}>
      {isLoading && children}
      {isReady && (
        <Translation ns={ns}>
          {(t, instance) => (
            <Message
              attr={attr}
              instance={instance.i18n}
              fn={t}
              code={code}
              options={options}
            >
              {children}
            </Message>
          )}
        </Translation>
      )}
    </ins>
  );

};

export type { ILocale };
export { Locale };
