/* eslint-disable react/jsx-curly-newline */
/* eslint-disable sonarjs/no-small-switch */
import TelegramIcon from '../public/assets/images/telegram.svg';
import styles from './Form.module.scss';
import { publicRuntimeConfig } from '@/config/runtime';
import { FormStateContext } from '@/context/form-state';
import { useSocket } from '@/hooks/socket';
import type { TelegramUrlResponse } from '@/types/error';
import type { LdapUser } from '@/types/user';
import axios, { isAxiosError } from 'axios';
import Image from 'next/image';
import type { PropsWithChildren } from 'react';
import { useContext, useEffect } from 'react';
import { useForm } from 'react-hook-form';

const ERROR_INVALID_CREDENTIALS = 'Неверный логин или пароль';
const ERROR_SERVER = 'Не удалось войти. Повторите попытку позже';

const { APP_BASE_PATH, TELEGRAM_BOT_URL } = publicRuntimeConfig;

type FormData = {
  readonly login: string;
  readonly password: string;
};

type FormProps = {
  readonly onSubmit: (data: FormData) => void;
};

function redirect() {
  const redirectUrl =
    (window.location.pathname.replace(APP_BASE_PATH, '') || '/') + (window.location.search || '');

  window.location.replace(redirectUrl);
}

function BaseForm({ children, onSubmit }: FormProps & PropsWithChildren) {
  const { handleSubmit, register } = useForm<FormData>();
  const {
    state: { error, step },
  } = useContext(FormStateContext);

  return (
    <form className={styles.form} onSubmit={handleSubmit(onSubmit)}>
      <input
        disabled={step !== 'login'}
        type="text"
        placeholder="Логин"
        required
        autoComplete="on"
        {...register('login', { required: true })}
      />
      <input
        disabled={step !== 'login'}
        type="password"
        placeholder="Пароль"
        required
        autoComplete="on"
        {...register('password', { required: true })}
      />
      {step === 'telegram-login' ? (
        <a target="_blank" className="info" href={TELEGRAM_BOT_URL} rel="noreferrer">
          Открыть чат с ботом
        </a>
      ) : null}
      {error ? <span className="error">{error}</span> : null}
      {children}
    </form>
  );
}

export const Form = {
  Default() {
    const {
      dispatch,
      state: { step, user },
    } = useContext(FormStateContext);

    function handleRefreshToken() {
      axios
        .get('/refresh-token')
        .then(() => redirect())
        .catch(() =>
          dispatch({
            payload: { error: ERROR_SERVER },
            type: 'set-error',
          })
        );
    }

    if (step === 'login' && user) {
      return (
        <button
          className={styles['button-submit']}
          type="submit"
          onClick={() => handleRefreshToken()}
        >
          Продолжить как <b>{user?.displayName}</b>
        </button>
      );
    }

    function handleLogin(data: FormData) {
      return axios
        .post('/login', data)
        .then(() => redirect())
        .catch(() =>
          dispatch({
            payload: { error: ERROR_INVALID_CREDENTIALS },
            type: 'set-error',
          })
        );
    }

    return (
      <BaseForm onSubmit={(data) => handleLogin(data)}>
        <button className={styles['button-submit']} type="submit">
          Войти
        </button>
      </BaseForm>
    );
  },

  Telegram() {
    const {
      dispatch,
      state: { step, user },
    } = useContext(FormStateContext);

    const { socket } = useSocket();

    useEffect(() => {
      if (step === 'telegram-login') {
        socket.open();
        socket.on('connect', () => {});

        socket.on('auth-allow', () => {
          socket.off('connect');
          axios
            .get('/login-confirm')
            .then(() => redirect())
            .catch(() =>
              dispatch({
                payload: { error: ERROR_SERVER },
                type: 'set-error',
              })
            );
        });
      }

      return () => {
        socket.off('connect');
      };
    }, [dispatch, socket, step]);

    function handleLogin(data: FormData) {
      axios
        .post<LdapUser>('/login', data)
        .then((res) => {
          dispatch({
            payload: {
              step: 'telegram',
              user: res.data,
            },
            type: 'set-step',
          });
        })
        .catch(() =>
          dispatch({
            payload: { error: ERROR_INVALID_CREDENTIALS },
            type: 'set-error',
          })
        );
    }

    function handleTelegramLogin() {
      axios
        .post<LdapUser>('/login-telegram')
        .then(() => {
          dispatch({
            payload: {
              step: 'telegram-login',
            },
            type: 'set-step',
          });
        })
        .catch((error_) => {
          let error = ERROR_SERVER;

          if (isAxiosError<TelegramUrlResponse>(error_) && error_.response?.data?.message) {
            error = error_.response?.data?.message;
          }

          return dispatch({
            payload: { error },
            type: 'set-error',
          });
        });
    }

    // eslint-disable-next-line sonarjs/no-identical-functions
    function handleRefreshToken() {
      axios
        .get('/refresh-token')
        .then(() => redirect())
        .catch(() =>
          dispatch({
            payload: { error: ERROR_SERVER },
            type: 'set-error',
          })
        );
    }

    if (step === 'login' && user) {
      return (
        <button
          className={styles['button-submit']}
          type="submit"
          onClick={() => handleRefreshToken()}
        >
          Продолжить как <b>{user?.displayName}</b>
        </button>
      );
    }

    if (step === 'telegram') {
      return (
        <BaseForm onSubmit={() => handleTelegramLogin()}>
          <button type="submit" className={styles['button-telegram']}>
            <Image
              className={styles['button-telegram-icon']}
              src={TelegramIcon}
              width={24}
              height={22}
              alt="Telegram icon"
            />
            Войти как &nbsp; <b>{user?.displayName}</b>
          </button>
        </BaseForm>
      );
    }

    if (step === 'telegram-login') {
      return (
        <BaseForm onSubmit={() => {}}>
          <button disabled type="submit" className={styles['button-telegram']}>
            <Image
              className={styles['button-telegram-icon']}
              src={TelegramIcon}
              width={24}
              height={22}
              alt="Telegram icon"
            />
            Ожидаем подтверждения...
          </button>
        </BaseForm>
      );
    }

    return (
      <BaseForm onSubmit={(data) => handleLogin(data)}>
        <button className={styles['button-submit']} type="submit">
          Войти
        </button>
      </BaseForm>
    );
  },
};
