import LogoIcon from '@/assets/images/gpustack-logo.png';
import { initialPasswordAtom, userAtom } from '@/atoms/user';
import { resetStorageUserSettings } from '@/atoms/utils';
import DarkMask from '@/components/dark-mask';
import Footer from '@/components/footer';
import LangSelect from '@/components/lang-select';
import ThemeDropActions from '@/components/theme-toggle/theme-drop-actions';
import { PasswordReg } from '@/config';
import { GPUSTACK_API_BASE_URL } from '@/config/settings';
import { COLOR_PRIMARY } from '@/config/theme/constants';
import externalLinks from '@/constants/external-links';
import useUserSettings from '@/hooks/use-user-settings';
import useUserSettingsStorage from '@/hooks/use-user-settings-storage';
import { getGPUStackPlugin } from '@/plugins';
import {
  CRYPT_TEXT,
  IS_FIRST_LOGIN,
  writeState
} from '@/utils/localstore/index';
import { CoreUIProvider } from '@gpustack/core-ui';
import {
  getAllLocales,
  request,
  setLocale,
  useIntl,
  useModel,
  useNavigate
} from '@umijs/max';
import { ConfigProvider, theme } from 'antd';
import { createStyles } from 'antd-style';
import CryptoJS from 'crypto-js';
import { useAtom } from 'jotai';
import { useCallback, useEffect, useMemo } from 'react';
import { flushSync } from 'react-dom';
import styled from 'styled-components';
import { updatePassword as updatePasswordApi } from './apis';
import Background from './components/background';
import LoginForm from './components/login-form';
import PasswordForm from './components/password-form';
import { useLocalAuth } from './hooks/use-local-auth';
import { useSSOAuth } from './hooks/use-sso-auth';
import { checkDefaultPage } from './utils';

const COLOR_LINK = '#1677ff';

const useStyles = createStyles(({ token, css }) => ({
  header: css`
    display: flex;
    align-items: center;
    gap: 8px;
    position: fixed;
    right: 0;
    top: 0;
    height: 60px;
    padding: 20px;
    z-index: 100;
    .anticon-global {
      color: ${token.colorText};
    }
    .anticon:hover {
      color: ${token.colorTextTertiary};
    }
  `,
  formContainer: css`
    height: calc(100vh - 64px);
    width: 100%;
  `
}));

const Box = styled.div`
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  min-height: 100vh;
  .ant-form-item-label {
    line-height: 1;
    padding-bottom: 4px;
  }
  .ant-form-item-label > label:after {
    display: none;
  }
  .ant-form-item-label > label {
    height: auto !important;
  }
`;

const FormWrapper = styled.div`
  margin: 0 auto;
  margin-top: 50vh;
  width: 400px;
  transform: translateY(-50%);
  position: relative;
  z-index: 999;
  border-radius: var(--border-radius-modal);
  height: max-content;
  max-height: 660px;
  padding: 40px;
  background-color: var(--color-modal-content-bg);
  box-shadow: var(--color-modal-box-shadow);
  .field-wrapper {
    background-color: transparent !important;
  }

  .ant-input-outlined.ant-input-status-error:not(.ant-input-disabled) {
    background-color: transparent !important;
  }
`;

const decryptInitialPassword = (password: string) => {
  const bytes = CryptoJS.AES?.decrypt?.(password, CRYPT_TEXT);
  return bytes.toString(CryptoJS.enc.Utf8);
};

const Login = () => {
  const { styles } = useStyles();
  const intl = useIntl();
  const navigate = useNavigate();
  const userSettingsStorage = useUserSettingsStorage();
  const { themeData, userSettings, isDarkTheme } = useUserSettings();
  const [userInfo, setUserInfo] = useAtom(userAtom);
  const [initialPassword, setInitialPassword] = useAtom(initialPasswordAtom);
  const { initialState, setInitialState } = useModel('@@initialState') || {};

  const plugin = getGPUStackPlugin();

  const CustomLoginComponent = plugin?.login?.CustomLoginComponent;
  const shouldUseCustomLogin = plugin?.login?.shouldUseCustomLogin;

  const useCustomLogin = useMemo(
    () => shouldUseCustomLogin?.(userSettings),
    [shouldUseCustomLogin, userSettings]
  );

  const gotoDefaultPage = async (info: any) => {
    if (!info || info?.require_password_change) {
      return;
    }

    checkDefaultPage(info, true);
    if (!initialState?.currentUser) {
      setInitialState((preState: any) => ({
        ...preState,
        currentUser: info
      }));
    }
  };

  useEffect(() => {
    gotoDefaultPage(userInfo);
  }, [userInfo]);

  const fetchUserInfo = useCallback(async () => {
    const info = await initialState?.fetchUserInfo?.();
    if (info) {
      flushSync(() => {
        setInitialState((s: any) => ({
          ...s,
          currentUser: info
        }));
      });
    }
    return info;
  }, [initialState, setInitialState]);

  const onPasswordChanged = useCallback(() => {
    resetStorageUserSettings();
    writeState(IS_FIRST_LOGIN, null);
  }, []);

  const kit = useMemo(
    () => ({
      useLocalAuth,
      useSSOAuth,
      userInfo,
      setUserInfo,
      fetchUserInfo,
      checkDefaultPage,
      initialPassword,
      setInitialPassword,
      decryptInitialPassword,
      updatePassword: updatePasswordApi,
      passwordReg: PasswordReg,
      onPasswordChanged,
      resetPasswordUrl: externalLinks.resetPassword,
      formLogoUrl: LogoIcon
    }),
    [
      userInfo,
      setUserInfo,
      fetchUserInfo,
      initialPassword,
      setInitialPassword,
      onPasswordChanged
    ]
  );
  return (
    <ConfigProvider
      componentSize="large"
      theme={{
        algorithm: userSettings.isDarkTheme
          ? theme.darkAlgorithm
          : theme.defaultAlgorithm,
        ...themeData,
        token: {
          ...themeData?.token,
          colorPrimary:
            plugin?.getPrimaryColor?.(userSettings)?.colorPrimary ||
            COLOR_PRIMARY
        }
      }}
    >
      <CoreUIProvider
        config={{
          apiBaseUrl: GPUSTACK_API_BASE_URL,
          theme: userSettings.theme,
          iconUrl: '',
          isDarkTheme: userSettings.isDarkTheme,
          defaultColorPrimary: COLOR_PRIMARY
        }}
        hooks={
          {
            useUserSettings: useUserSettings as any,
            useUserSettingsStorage: () => userSettingsStorage,
            useIntl: useIntl
            // useCurrentUser / useTableFetch are required by the
            // 1.0.10 CoreHooks type but the login page doesn't use
            // either — nothing here lists data or reads the current
            // user. Cast away rather than mounting stubs that would
            // never run.
          } as any
        }
        i18n={intl}
        locale={{
          getAllLocales: getAllLocales,
          setLocale: setLocale
        }}
        services={{
          request: request,
          router: {
            push: (path: string) => navigate(path),
            replace: (path: string) => navigate(path, { replace: true }),
            goBack: () => navigate(-1)
          }
        }}
      >
        <div className={styles.header}>
          <ThemeDropActions></ThemeDropActions>
          <LangSelect />
        </div>
        <DarkMask></DarkMask>
        <Background isDarkTheme={isDarkTheme} />
        {useCustomLogin && CustomLoginComponent ? (
          <CustomLoginComponent kit={kit} />
        ) : (
          <Box>
            <div className={styles.formContainer}>
              <FormWrapper>
                {userInfo?.require_password_change ? (
                  <PasswordForm />
                ) : (
                  <LoginForm />
                )}
              </FormWrapper>
            </div>
            <Footer />
          </Box>
        )}
      </CoreUIProvider>
    </ConfigProvider>
  );
};

export default Login;
