import {
  useMemo,
  useState,
  useEffect,
  useCallback,
} from 'react'

import find from 'lodash/find'
import reduce from 'lodash/reduce'
import isNull from 'lodash/isNull'
import isNumber from 'lodash/isNumber'
import isString from 'lodash/isString'
import isObject from 'lodash/isObject'

import type { Languages } from 'config/languages'
import { formIds } from 'config/form'

import type { UserInfo, SaveUserInfo } from 'requests'
import {
  getUserInfo,
  getCountryCities,
  saveUserInfo,
} from 'requests'

import type { FormState } from 'features/FormStore/hooks/useFormState'
import { useLexicsStore } from 'features/LexicsStore'

export type SaveWithLang = SaveUserInfo & {
  language?: string | null,
}

const transformToFormState = async (userInfo: UserInfo) => {
  const cities = userInfo.country?.id
    ? await getCountryCities('', userInfo.country.id)
    : []
  return reduce(
    formIds,
    (
      acc: FormState,
      field,
    ) => {
      const key = field as keyof UserInfo
      const value = userInfo[key]
      if (key === formIds.cityId && value) {
        const city = find(cities, { id: Number(value) }) || { id: '', name: acc[formIds.city]?.value }
        acc[formIds.cityId] = { value: String(city.id) }
        acc[formIds.city] = { value: city.name }
      } else if (key === formIds.country && isObject(value) && value.id) {
        const formValue = { value: String(value.id) }
        acc[formIds.initialCountryId] = formValue
        acc[formIds.countryId] = formValue
      } else if (isNumber(value) || isString(value)) {
        acc[key] = { value: String(value) }
      } else if (isNull(value)) {
        acc[key] = { value: '' }
      }
      return acc
    },
    {},
  )
}

export const useUserInfo = () => {
  const { changeLang, lang } = useLexicsStore()
  const [userInfo, setUserInfo] = useState<FormState>()
  const [loader, setLoader] = useState<boolean>(false)

  const fetchUserInfo = useCallback(() => {
    getUserInfo()
      .then(transformToFormState)
      .then(setUserInfo)
  }, [])

  const onSubmit = useCallback((data: SaveWithLang) => {
    setLoader(true)
    saveUserInfo(data).then(() => {
      fetchUserInfo()
      if (data.language) {
        changeLang(data.language as Languages)
      }
    }).finally(() => setLoader(false))
  }, [fetchUserInfo, changeLang])

  useEffect(() => {
    fetchUserInfo()
  }, [fetchUserInfo])

  const user = useMemo(() => (userInfo
    ? {
      ...userInfo,
      [formIds.language]: { value: lang },
    }
    : null), [userInfo, lang])

  return {
    loader,
    onSubmit,
    userInfo: user,
  }
}
