import Image from "next/image"
import useTranslation from "next-translate/useTranslation"
import { useState, useMemo } from "react"
import { Form, useForm } from "react-component-form"
import { EyeIcon, PhotographIcon } from "@heroicons/react/solid"
import { Type } from "@sinclair/typebox"
import axios from "axios"
import Link from "next/link"
import type { HandleUseFormCallback } from "react-component-form"

import { Input } from "../../design/Input"
import { Checkbox } from "../../design/Checkbox"
import { Textarea } from "../../design/Textarea"
import { SocialMediaButton } from "../../design/SocialMediaButton"
import { SwitchTheme } from "../../Header/SwitchTheme"
import { Language } from "../../Header/Language"
import { useAuthentication } from "../../../tools/authentication"
import { Button } from "../../design/Button"
import { FormState } from "../../design/FormState"
import { userSchema } from "../../../models/User"
import { userSettingsSchema } from "../../../models/UserSettings"
import type { ProviderOAuth } from "../../../models/OAuth"
import { providers } from "../../../models/OAuth"
import { useFormTranslation } from "../../../hooks/useFormTranslation"

const schema = {
  name: userSchema.name,
  status: Type.Optional(userSchema.status),
  email: Type.Optional(Type.Union([userSchema.email, Type.Null()])),
  website: Type.Optional(userSchema.website),
  biography: Type.Optional(userSchema.biography),
  isPublicGuilds: userSettingsSchema.isPublicGuilds,
  isPublicEmail: userSettingsSchema.isPublicEmail,
}

export const UserSettings: React.FC = () => {
  const { user, setUser, authentication } = useAuthentication()
  const { t } = useTranslation()
  const [inputValues, setInputValues] = useState({
    name: user.name,
    status: user.status,
    email: user.email,
    website: user.website,
    biography: user.biography,
    isPublicGuilds: user.settings.isPublicGuilds,
    isPublicEmail: user.settings.isPublicEmail,
  })

  const {
    handleUseForm,
    fetchState,
    setFetchState,
    message,
    setMessage,
    errors,
  } = useForm(schema)
  const { getFirstErrorTranslation } = useFormTranslation()

  const hasAllProviders = useMemo(() => {
    return providers.every((provider) => {
      return user.strategies.includes(provider)
    })
  }, [user.strategies])

  const onSubmit: HandleUseFormCallback<typeof schema> = async (formData) => {
    try {
      const { isPublicGuilds, isPublicEmail, ...userData } = formData
      const userSettings = { isPublicEmail, isPublicGuilds }
      const { data: userCurrentData } = await authentication.api.put(
        `/users/current?redirectURI=${window.location.origin}/authentication/signin`,
        userData,
      )
      setInputValues(formData as unknown as any)
      const hasEmailChanged = user.email !== userCurrentData.user.email
      if (hasEmailChanged) {
        return {
          type: "success",
          message: "application:success-email-changed",
        }
      }
      const { data: userCurrentSettings } = await authentication.api.put(
        "/users/current/settings",
        userSettings,
      )
      setUser((oldUser) => {
        return {
          ...oldUser,
          ...userCurrentData,
          settings: {
            ...oldUser.settings,
            ...userCurrentSettings.settings,
          },
        }
      })
      return {
        type: "success",
        message: "application:saved-information",
      }
    } catch (error) {
      if (axios.isAxiosError(error) && error.response?.status === 400) {
        const message = error.response.data.message as string
        if (message.endsWith("already taken.")) {
          return {
            type: "error",
            message: "authentication:already-used",
          }
        } else if (message.endsWith("email to sign in.")) {
          return {
            type: "error",
            message: "authentication:email-required-to-sign-in",
          }
        }
        return {
          type: "error",
          message: "errors:server-error",
        }
      }
      return {
        type: "error",
        message: "errors:server-error",
      }
    }
  }

  const onChange: React.ChangeEventHandler<
    HTMLInputElement | HTMLTextAreaElement
  > = (event) => {
    setInputValues((oldInputValues) => {
      return {
        ...oldInputValues,
        [event.target.name]: event.target.value,
      }
    })
  }

  const onChangeCheckbox: React.ChangeEventHandler<HTMLInputElement> = (
    event,
  ) => {
    setInputValues((oldInputValues) => {
      return {
        ...oldInputValues,
        [event.target.name]: event.target.checked,
      }
    })
  }

  const handleFileChange: React.ChangeEventHandler<HTMLInputElement> = async (
    event,
  ) => {
    setFetchState("loading")
    const files = event?.target?.files
    if (files != null && files.length === 1 && files[0] != null) {
      const file = files[0]
      const formData = new FormData()
      formData.append("logo", file)
      try {
        const { data } = await authentication.api.put(
          `/users/current/logo`,
          formData,
          {
            headers: {
              "Content-Type": "multipart/form-data",
            },
          },
        )
        setUser((oldUser) => {
          return {
            ...oldUser,
            logo: data.user.logo,
          }
        })
        setFetchState("idle")
      } catch (error) {
        setFetchState("error")
        setMessage("errors:server-error")
      }
    }
  }

  const handleSignout = async (): Promise<void> => {
    setFetchState("loading")
    await authentication.signoutServerSide()
  }

  const handleSignoutAllDevices = async (): Promise<void> => {
    setFetchState("loading")
    await authentication.signoutAllDevicesServerSide()
  }

  const handleDeletionProvider = (
    provider: ProviderOAuth,
  ): (() => Promise<void>) => {
    return async () => {
      try {
        setFetchState("loading")
        await authentication.api.delete(`/users/oauth2/${provider}`)
        setUser((oldUser) => {
          return {
            ...oldUser,
            strategies: oldUser.strategies.filter((strategy) => {
              return strategy !== provider
            }),
          }
        })
        setMessage("application:success-deleted-provider")
      } catch (error) {
        setFetchState("error")
        setMessage("errors:server-error")
      }
    }
  }

  const handleAddProvider = (
    provider: ProviderOAuth,
  ): (() => Promise<void>) => {
    return async () => {
      const redirect = window.location.href.replace(location.search, "")
      const { data: url } = await authentication.api.get(
        `/users/oauth2/${provider.toLowerCase()}/add-strategy?redirectURI=${redirect}`,
      )
      window.location.href = url
    }
  }

  return (
    <Form
      onSubmit={handleUseForm(onSubmit)}
      className="my-auto flex flex-col items-center justify-center py-12 lg:min-w-[875px]"
    >
      <div className="flex w-full flex-col items-center justify-center sm:w-fit lg:flex-row">
        <div className=" flex w-full flex-wrap items-center justify-center px-6 sm:w-max">
          <div className="relative">
            <div className="absolute z-50 h-full w-full">
              <button className="relative flex h-full w-full items-center justify-center transition hover:scale-110">
                <input
                  type="file"
                  className="absolute h-full w-full cursor-pointer opacity-0"
                  onChange={handleFileChange}
                />
                <PhotographIcon color="white" className="h-8 w-8" />
              </button>
            </div>
            <div className="flex items-center justify-center rounded-full bg-black shadow-xl">
              <Image
                quality={100}
                className="rounded-full opacity-50"
                src={
                  user.logo != null
                    ? user.logo
                    : "/images/data/user-default.png"
                }
                alt="Profil Picture"
                draggable="false"
                height={125}
                width={125}
              />
            </div>
          </div>
          <div className="mx-12 flex flex-col">
            <Input
              name="name"
              label={t("common:name")}
              placeholder={t("common:name")}
              className="!mt-0"
              onChange={onChange}
              value={inputValues.name ?? ""}
              error={getFirstErrorTranslation(errors.name)}
            />
            <Input
              name="status"
              label={t("application:status")}
              placeholder={t("application:status")}
              className="!mt-4"
              onChange={onChange}
              value={inputValues.status ?? ""}
              error={getFirstErrorTranslation(errors.status)}
            />
          </div>
        </div>
      </div>
      <div className="mt-12 flex w-full flex-col items-center justify-between sm:w-fit lg:flex-row">
        <div className="w-4/5 pr-0 sm:w-[450px] lg:border-r-[1px] lg:border-neutral-700 lg:pr-12">
          <Input
            name="email"
            label="Email"
            placeholder="Email"
            onChange={onChange}
            value={inputValues.email ?? ""}
            error={getFirstErrorTranslation(errors.email)}
          />
          <Checkbox
            name="isPublicEmail"
            label={t("application:label-checkbox-email")}
            id="checkbox-email-visibility"
            onChange={onChangeCheckbox}
            checked={inputValues.isPublicEmail}
          />
          <Input
            name="website"
            label={t("application:website")}
            placeholder={t("application:website")}
            onChange={onChange}
            value={inputValues.website ?? ""}
            error={getFirstErrorTranslation(errors.website)}
          />
          <Textarea
            name="biography"
            label={t("application:biography")}
            placeholder={t("application:biography")}
            id="textarea-biography"
            onChange={onChange}
            value={inputValues.biography ?? ""}
          />
        </div>
        <div className="flex h-full w-4/5 flex-col items-center justify-between pr-0 sm:w-[415px] lg:pl-12">
          <div className="flex w-full items-center pt-10 lg:pt-0">
            <Language className="!top-12" />
            <div className="ml-auto flex">
              <SwitchTheme />
              <Link
                href={`/application/users/${user.id}`}
                className="group ml-3 flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg bg-slate-200 transition-colors hover:bg-slate-300 dark:bg-slate-700 hover:dark:bg-slate-800"
                title="Preview Public Profile"
              >
                <EyeIcon
                  height={20}
                  className="opacity-50 transition-opacity group-hover:opacity-100"
                />
              </Link>
            </div>
          </div>

          <div className="mt-14 flex w-full flex-col gap-4">
            {!hasAllProviders ? (
              <div className="flex w-full flex-col gap-4">
                <h3 className="text-center">
                  {t("application:signin-with-an-account")}
                </h3>
                {providers.map((provider, index) => {
                  if (!user.strategies.includes(provider)) {
                    return (
                      <SocialMediaButton
                        key={index}
                        socialMedia={provider}
                        className="w-full justify-center"
                        onClick={handleAddProvider(provider)}
                      />
                    )
                  }
                  return null
                })}
              </div>
            ) : null}
            {user.strategies.length !== 1 && (
              <div className="mt-4 flex w-full flex-col gap-4">
                <h3 className="text-center">
                  {t("application:signout-with-an-account")}
                </h3>
                {providers.map((provider, index) => {
                  if (user.strategies.includes(provider)) {
                    return (
                      <SocialMediaButton
                        key={index}
                        socialMedia={provider}
                        className="w-full justify-center"
                        onClick={handleDeletionProvider(provider)}
                      />
                    )
                  }
                  return null
                })}
              </div>
            )}
          </div>
        </div>
      </div>

      <div className="mt-12 flex flex-col items-center justify-center sm:w-fit">
        <div className="space-x-6">
          <Button type="submit">{t("application:save")}</Button>
          <Button type="button" color="red" onClick={handleSignout}>
            {t("application:signout")}
          </Button>
        </div>
        <div className="mt-4">
          <Button type="button" color="red" onClick={handleSignoutAllDevices}>
            {t("application:signout-all-devices")}
          </Button>
        </div>
        <FormState
          state={fetchState}
          message={message != null ? t(message) : undefined}
        />
      </div>
    </Form>
  )
}
