import Button from '@app/components/Common/Button';
import SensitiveInput from '@app/components/Common/SensitiveInput';
import JellyfinQuickConnectModal from '@app/components/Login/JellyfinQuickConnectModal';
import useSettings from '@app/hooks/useSettings';
import useToasts from '@app/hooks/useToasts';
import defineMessages from '@app/utils/defineMessages';
import {
  ArrowLeftOnRectangleIcon,
  QrCodeIcon,
} from '@heroicons/react/24/outline';
import { ExclamationTriangleIcon } from '@heroicons/react/24/solid';
import { ApiErrorCode } from '@server/constants/error';
import { MediaServerType, ServerType } from '@server/constants/server';
import axios from 'axios';
import { Field, Form, Formik } from 'formik';
import { useCallback, useState } from 'react';
import { useIntl } from 'react-intl';
import * as Yup from 'yup';

const messages = defineMessages('components.Login', {
  loginwithapp: 'Login with {appName}',
  username: 'Username',
  password: 'Password',
  validationusernamerequired: 'Username required',
  validationpasswordrequired: 'Password required',
  loginerror: 'Something went wrong while trying to sign in.',
  adminerror: 'You must use an admin account to sign in.',
  noadminerror: 'No admin user found on the server.',
  credentialerror: 'The username or password is incorrect.',
  invalidurlerror: 'Unable to connect to {mediaServerName} server.',
  tipUsernameHasTrailingWhitespace: 'The username ends with whitespace',
  signingin: 'Signing In…',
  signin: 'Sign In',
  forgotpassword: 'Forgot Password?',
  quickconnect: 'Quick Connect',
  quickconnecterror: 'Quick Connect failed. Please try again.',
});

interface JellyfinLoginProps {
  revalidate: () => void;
  serverType?: MediaServerType;
}

const JellyfinLogin = ({ revalidate, serverType }: JellyfinLoginProps) => {
  const toasts = useToasts();
  const intl = useIntl();
  const settings = useSettings();
  const [showQuickConnect, setShowQuickConnect] = useState(false);

  const mediaServerFormatValues = {
    mediaServerName:
      serverType === MediaServerType.JELLYFIN
        ? ServerType.JELLYFIN
        : serverType === MediaServerType.EMBY
          ? ServerType.EMBY
          : 'Media Server',
  };

  const handleQuickConnectError = useCallback(
    (error: string) => {
      toasts.addToast(error, {
        autoDismiss: true,
        appearance: 'error',
      });
    },
    [toasts]
  );

  const LoginSchema = Yup.object().shape({
    username: Yup.string().required(
      intl.formatMessage(messages.validationusernamerequired)
    ),
    password: Yup.string(),
  });
  const baseUrl = settings.currentSettings.jellyfinExternalHost
    ? settings.currentSettings.jellyfinExternalHost
    : settings.currentSettings.jellyfinHost;
  const jellyfinForgotPasswordUrl =
    settings.currentSettings.jellyfinForgotPasswordUrl;

  return (
    <div>
      <Formik
        initialValues={{
          username: '',
          password: '',
        }}
        validationSchema={LoginSchema}
        validateOnBlur={false}
        onSubmit={async (values) => {
          try {
            await axios.post('/api/v1/auth/jellyfin', {
              username: values.username,
              password: values.password,
              email: values.username,
            });
          } catch (e) {
            let errorMessage = messages.loginerror;
            switch (e?.response?.data?.message) {
              case ApiErrorCode.InvalidUrl:
                errorMessage = messages.invalidurlerror;
                break;
              case ApiErrorCode.InvalidCredentials:
                errorMessage = messages.credentialerror;
                break;
              case ApiErrorCode.NotAdmin:
                errorMessage = messages.adminerror;
                break;
              case ApiErrorCode.NoAdminUser:
                errorMessage = messages.noadminerror;
                break;
            }
            toasts.addToast(
              intl.formatMessage(errorMessage, mediaServerFormatValues),
              {
                autoDismiss: true,
                appearance: 'error',
              }
            );
          } finally {
            revalidate();
          }
        }}
      >
        {({ errors, touched, values, isSubmitting, isValid }) => {
          return (
            <>
              <Form data-form-type="login">
                <div>
                  <h2 className="-mt-1 mb-6 text-center text-lg font-bold text-neutral-200">
                    {intl.formatMessage(messages.loginwithapp, {
                      appName: mediaServerFormatValues.mediaServerName,
                    })}
                  </h2>

                  <div className="mb-4 mt-1">
                    <div className="form-input-field">
                      <Field
                        id="username"
                        name="username"
                        type="text"
                        placeholder={intl.formatMessage(messages.username)}
                        className="!bg-gray-700/80 placeholder:text-gray-400"
                        data-form-type="username"
                      />
                    </div>
                    {touched.username && values.username.match(/\s$/) && (
                      <div className="warning label-tip flex items-center">
                        <ExclamationTriangleIcon className="mr-1 h-4 w-4" />
                        {intl.formatMessage(
                          messages.tipUsernameHasTrailingWhitespace
                        )}
                      </div>
                    )}
                    {errors.username && touched.username && (
                      <div className="error">{errors.username}</div>
                    )}
                  </div>

                  <div className="mb-2 mt-1">
                    <div className="form-input-field">
                      <SensitiveInput
                        as="field"
                        id="password"
                        name="password"
                        type="password"
                        autoComplete="current-password"
                        placeholder={intl.formatMessage(messages.password)}
                        className="!bg-gray-700/80 placeholder:text-gray-400"
                        data-form-type="password"
                        data-1pignore="false"
                        data-lpignore="false"
                      />
                    </div>
                    <div className="flex">
                      {errors.password && touched.password && (
                        <div className="error">{errors.password}</div>
                      )}
                      <div className="flex-grow" />
                      {baseUrl && (
                        <a
                          href={
                            jellyfinForgotPasswordUrl
                              ? `${jellyfinForgotPasswordUrl}`
                              : `${baseUrl}/web/index.html#!/${
                                  settings.currentSettings.mediaServerType ===
                                  MediaServerType.EMBY
                                    ? 'startup/'
                                    : ''
                                }forgotpassword.html`
                          }
                          className="pt-2 text-sm text-indigo-500 hover:text-indigo-400"
                        >
                          {intl.formatMessage(messages.forgotpassword)}
                        </a>
                      )}
                    </div>
                  </div>
                </div>

                <Button
                  buttonType="primary"
                  type="submit"
                  disabled={isSubmitting || !isValid}
                  className="mt-2 w-full shadow-sm"
                >
                  <ArrowLeftOnRectangleIcon />
                  <span>
                    {isSubmitting
                      ? intl.formatMessage(messages.signingin)
                      : intl.formatMessage(messages.signin)}
                  </span>
                </Button>
              </Form>
            </>
          );
        }}
      </Formik>

      <div className="mt-4">
        <Button
          buttonType="ghost"
          type="button"
          onClick={() => setShowQuickConnect(true)}
          className="w-full"
        >
          <QrCodeIcon />
          <span>{intl.formatMessage(messages.quickconnect)}</span>
        </Button>
      </div>

      {showQuickConnect && (
        <JellyfinQuickConnectModal
          onClose={() => setShowQuickConnect(false)}
          onAuthenticated={() => {
            setShowQuickConnect(false);
            revalidate();
          }}
          onError={handleQuickConnectError}
          mediaServerName={mediaServerFormatValues.mediaServerName}
        />
      )}
    </div>
  );
};

export default JellyfinLogin;
