import React, { useCallback, useEffect, useState } from "react";
import styled, { css } from "styled-components";
import PropTypes from "prop-types";
import { withRouter } from "react-router";
import Box from "@appserver/components/box";
import Button from "@appserver/components/button";
import Text from "@appserver/components/text";
import TextInput from "@appserver/components/text-input";
import Link from "@appserver/components/link";
import Checkbox from "@appserver/components/checkbox";
import Toast from "@appserver/components/toast";
import HelpButton from "@appserver/components/help-button";
import PasswordInput from "@appserver/components/password-input";
import FieldContainer from "@appserver/components/field-container";
import SocialButton from "@appserver/components/social-button";
import FacebookButton from "@appserver/components/facebook-button";
import PageLayout from "@appserver/common/components/PageLayout";
import ForgotPasswordModalDialog from "./sub-components/forgot-password-modal-dialog";
import Register from "./sub-components/register-container";
import { getAuthProviders } from "@appserver/common/api/settings";
import { checkPwd } from "@appserver/common/desktop";
import {
  createPasswordHash,
  getProviderTranslation,
} from "@appserver/common/utils";
import { providersData } from "@appserver/common/constants";
import { inject, observer } from "mobx-react";
import i18n from "./i18n";
import {
  I18nextProvider,
  useTranslation,
  withTranslation,
} from "react-i18next";
import toastr from "@appserver/components/toast/toastr";

const ButtonsWrapper = styled.div`
  display: table;
  margin: auto;
`;

const LoginContainer = styled.div`
  display: flex;
  flex-direction: column;
  align-items: center;
  margin: 120px auto 0 auto;
  max-width: 960px;

  .login-tooltip {
    padding-left: 4px;
    display: inline-block;
  }

  .buttonWrapper {
    margin: 6px;
    min-width: 225px;
  }

  .line {
    height: 1px;
    background-color: #eceef1;
    flex-basis: 100%;
    margin: 0 8px;
  }

  @media (max-width: 768px) {
    padding: 0 16px;
    max-width: 475px;
  }
  @media (max-width: 375px) {
    margin: 72px auto 0 auto;
    max-width: 311px;
  }

  .greeting-title {
    width: 100%;

    @media (max-width: 768px) {
      text-align: left;
    }
    @media (max-width: 375px) {
      font-size: 23px;
    }
  }

  .auth-form-container {
    margin: 32px 213px 0 213px;
    width: 311px;

    @media (max-width: 768px) {
      margin: 32px 0 0 0;
      width: 100%;
    }
    @media (max-width: 375px) {
      margin: 32px 0 0 0;
      width: 100%;
    }

    .login-forgot-wrapper {
      height: 36px;
      padding: 14px 0;

      .login-checkbox-wrapper {
        display: flex;

        .login-checkbox {
          float: left;
          span {
            font-size: 12px;
          }
        }
      }

      .login-link {
        line-height: 18px;
        margin-left: auto;
      }
    }

    .login-button {
      margin-bottom: 16px;
    }

    .login-button-dialog {
      margin-right: 8px;
    }

    .login-bottom-border {
      width: 100%;
      height: 1px;
      background: #eceef1;
    }

    .login-bottom-text {
      margin: 0 8px;
    }
  }
`;

const LoginFormWrapper = styled.div`
  display: grid;
  grid-template-rows: ${(props) =>
    props.enabledJoin
      ? props.isDesktop
        ? css`1fr 10px`
        : css`1fr 66px`
      : css`1fr`};
  width: 100%;
  height: calc(100vh-48px);
`;

const settings = {
  minLength: 6,
  upperCase: false,
  digits: false,
  specSymbols: false,
};

const Form = (props) => {
  const inputRef = React.useRef(null);

  const [identifierValid, setIdentifierValid] = useState(true);
  const [identifier, setIdentifier] = useState("");
  const [isLoading, setIsLoading] = useState(false);
  const [isDisabled, setIsDisabled] = useState(false);

  const [passwordValid, setPasswordValid] = useState(true);
  const [password, setPassword] = useState("");
  const [isChecked, setIsChecked] = useState(false);
  const [isDialogVisible, setIsDialogVisible] = useState(false);

  const [errorText, setErrorText] = useState("");

  const { t } = useTranslation("Login");

  const {
    login,
    hashSettings,
    isDesktop,
    match,
    organizationName,
    greetingTitle,
    history,
    thirdPartyLogin,
    providers,
  } = props;

  const { error, confirmedEmail } = match.params;

  const oAuthLogin = async (profile) => {
    try {
      await thirdPartyLogin(profile);

      const redirectPath = localStorage.getItem("redirectPath");

      if (redirectPath) {
        localStorage.removeItem("redirectPath");
        window.location.href = redirectPath;
      }
    } catch (e) {
      toastr.error(
        t("Common:ProviderNotConnected"),
        t("Common:ProviderLoginError")
      );
    }

    localStorage.removeItem("profile");
    localStorage.removeItem("code");
  };

  useEffect(() => {
    const profile = localStorage.getItem("profile");
    if (!profile) return;

    oAuthLogin(profile);
  }, []);

  const onKeyDown = (e) => {
    //console.log("onKeyDown", e.key);
    if (e.key === "Enter") {
      onClearErrors(e);
      !isDisabled && onSubmit(e);
      e.preventDefault();
    }
  };

  const onClearErrors = (e) => {
    //console.log("onClearErrors", e);
    !identifierValid && setIdentifierValid(true);
    !passwordValid && setPasswordValid(true);
    errorText && setErrorText("");
  };

  //const throttledKeyPress = throttle(onKeyPress, 500);

  const authCallback = (profile) => {
    oAuthLogin(profile);
  };

  const setProviders = async () => {
    const { setProviders } = props;

    try {
      await getAuthProviders().then((providers) => {
        setProviders(providers);
      });
    } catch (e) {
      console.error(e);
    }
  };

  useEffect(async () => {
    document.title = `${t("Authorization")} – ${organizationName}`; //TODO: implement the setDocumentTitle() utility in ASC.Web.Common

    error && setErrorText(error);
    confirmedEmail && setIdentifier(confirmedEmail);

    focusInput();

    window.authCallback = authCallback;

    await setProviders();
    //window.addEventListener("keyup", throttledKeyPress, false);

    /*return () => {
      window.removeEventListener("keyup", throttledKeyPress, false);
    };*/
  }, []);

  const focusInput = () => {
    if (inputRef) {
      inputRef.current.focus();
    }
  };

  const onChangeLogin = (e) => {
    //console.log("onChangeLogin", e.target.value);
    setIdentifier(e.target.value);
    onClearErrors(e);
  };

  const onChangePassword = (e) => {
    //console.log("onChangePassword", e.target.value);
    setPassword(e.target.value);
    onClearErrors(e);
  };

  const onChangeCheckbox = () => setIsChecked(!isChecked);

  const onClick = () => {
    setIsDialogVisible(true);
    setIsDisabled(true);
  };

  const onDialogClose = () => {
    setIsDialogVisible(false);
    setIsDisabled(false);
    setIsLoading(false);
  };

  const onSubmit = () => {
    errorText && setErrorText("");
    let hasError = false;

    const userName = identifier.trim();

    if (!userName) {
      hasError = true;
      setIdentifierValid(false);
    }

    const pass = password.trim();

    if (!pass) {
      hasError = true;
      setPasswordValid(false);
    }

    if (hasError) return false;

    setIsLoading(true);
    const hash = createPasswordHash(pass, hashSettings);

    isDesktop && checkPwd();
    const session = !isChecked;
    login(userName, hash, session)
      .then((res) => {
        const { url, user, hash } = res;
        const redirectPath = localStorage.getItem("redirectPath");

        if (redirectPath) {
          localStorage.removeItem("redirectPath");
          window.location.href = redirectPath;
        } else history.push(url, { user, hash });
      })
      .catch((error) => {
        setErrorText(error);
        setIdentifierValid(!error);
        setPasswordValid(!error);
        setIsLoading(false);
        focusInput();
      });
  };

  const onSocialButtonClick = useCallback((e) => {
    const providerName = e.target.dataset.providername;
    const url = e.target.dataset.url;

    const { getOAuthToken, getLoginLink } = props;

    try {
      const tokenGetterWin = isDesktop
        ? (window.location.href = url)
        : window.open(
            url,
            "login",
            "width=800,height=500,status=no,toolbar=no,menubar=no,resizable=yes,scrollbars=no"
          );

      getOAuthToken(tokenGetterWin).then((code) => {
        const token = window.btoa(
          JSON.stringify({
            auth: providerName,
            mode: "popup",
            callback: "authCallback",
          })
        );

        tokenGetterWin.location.href = getLoginLink(token, code);
      });
    } catch (err) {
      console.log(err);
    }
  }, []);

  const addFacebookToStart = (facebookIndex, providerButtons) => {
    const faceBookData = providers[facebookIndex];
    const { icon, label, iconOptions } = providersData[faceBookData.provider];
    providerButtons.unshift(
      <div
        className="buttonWrapper"
        key={`${faceBookData.provider}ProviderItem`}
      >
        <FacebookButton
          iconName={icon}
          label={getProviderTranslation(label, t)}
          className="socialButton"
          $iconOptions={iconOptions}
          data-url={faceBookData.url}
          data-providername={faceBookData.provider}
          onClick={onSocialButtonClick}
        />
      </div>
    );
  };

  const providerButtons = () => {
    let facebookIndex = null;

    const providerButtons =
      providers &&
      providers.map((item, index) => {
        if (!providersData[item.provider]) return;

        const { icon, label, iconOptions, className } = providersData[
          item.provider
        ];

        if (item.provider === "facebook") {
          facebookIndex = index;
          return;
        }
        return (
          <div className="buttonWrapper" key={`${item.provider}ProviderItem`}>
            <SocialButton
              iconName={icon}
              label={getProviderTranslation(label, t)}
              className={`socialButton ${className ? className : ""}`}
              $iconOptions={iconOptions}
              data-url={item.url}
              data-providername={item.provider}
              onClick={onSocialButtonClick}
            />
          </div>
        );
      });

    if (facebookIndex) addFacebookToStart(facebookIndex, providerButtons);

    return providerButtons;
  };

  const oauthDataExists = () => {
    let existProviders = 0;
    providers && providers.length > 0;
    providers.map((item) => {
      if (!providersData[item.provider]) return;
      existProviders++;
    });

    return !!existProviders;
  };

  //console.log("Login render");

  return (
    <LoginContainer>
      <Text
        fontSize="32px"
        fontWeight={600}
        textAlign="center"
        className="greeting-title"
      >
        {greetingTitle}
      </Text>

      <form className="auth-form-container">
        <FieldContainer
          isVertical={true}
          labelVisible={false}
          hasError={!identifierValid}
          errorMessage={errorText ? errorText : t("Common:RequiredField")} //TODO: Add wrong login server error
        >
          <TextInput
            id="login"
            name="login"
            type="email"
            hasError={!identifierValid}
            value={identifier}
            placeholder={t("RegistrationEmailWatermark")}
            size="large"
            scale={true}
            isAutoFocussed={true}
            tabIndex={1}
            isDisabled={isLoading}
            autoComplete="username"
            onChange={onChangeLogin}
            onKeyDown={onKeyDown}
            forwardedRef={inputRef}
          />
        </FieldContainer>
        <FieldContainer
          isVertical={true}
          labelVisible={false}
          hasError={!passwordValid}
          errorMessage={errorText ? "" : t("Common:RequiredField")} //TODO: Add wrong password server error
        >
          <PasswordInput
            simpleView={true}
            passwordSettings={settings}
            id="password"
            inputName="password"
            placeholder={t("Common:Password")}
            type="password"
            hasError={!passwordValid}
            inputValue={password}
            size="large"
            scale={true}
            tabIndex={1}
            isDisabled={isLoading}
            autoComplete="current-password"
            onChange={onChangePassword}
            onKeyDown={onKeyDown}
          />
        </FieldContainer>
        <div className="login-forgot-wrapper">
          <div className="login-checkbox-wrapper">
            <Checkbox
              className="login-checkbox"
              isChecked={isChecked}
              onChange={onChangeCheckbox}
              label={<Text fontSize="13px">{t("Remember")}</Text>}
            />
            <HelpButton
              className="login-tooltip"
              helpButtonHeaderContent={t("CookieSettingsTitle")}
              tooltipContent={
                <Text fontSize="12px">{t("RememberHelper")}</Text>
              }
            />
            <Link
              fontSize="13px"
              color="#316DAA"
              className="login-link"
              type="page"
              isHovered={false}
              onClick={onClick}
            >
              {t("ForgotPassword")}
            </Link>
          </div>
        </div>

        {isDialogVisible && (
          <ForgotPasswordModalDialog
            visible={isDialogVisible}
            email={identifier}
            onDialogClose={onDialogClose}
          />
        )}

        <Button
          id="submit"
          className="login-button"
          primary
          size="large"
          scale={true}
          label={isLoading ? t("Common:LoadingProcessing") : t("LoginButton")}
          tabIndex={1}
          isDisabled={isLoading}
          isLoading={isLoading}
          onClick={onSubmit}
        />

        {confirmedEmail && (
          <Text isBold={true} fontSize="16px">
            {t("MessageEmailConfirmed")} {t("MessageAuthorize")}
          </Text>
        )}

        {oauthDataExists() && (
          <>
            <Box displayProp="flex" alignItems="center" marginProp="0 0 16px 0">
              <div className="login-bottom-border"></div>
              <Text className="login-bottom-text" color="#A3A9AE">
                {t("Or")}
              </Text>
              <div className="login-bottom-border"></div>
            </Box>

            <ButtonsWrapper>{providerButtons()}</ButtonsWrapper>
          </>
        )}
      </form>
      <Toast />
    </LoginContainer>
  );
};

Form.propTypes = {
  login: PropTypes.func.isRequired,
  match: PropTypes.object.isRequired,
  hashSettings: PropTypes.object,
  greetingTitle: PropTypes.string.isRequired,
  organizationName: PropTypes.string,
  homepage: PropTypes.string,
  defaultPage: PropTypes.string,
  isDesktop: PropTypes.bool,
};

Form.defaultProps = {
  identifier: "",
  password: "",
  email: "",
};

const LoginForm = (props) => {
  const { enabledJoin, isDesktop } = props;

  return (
    <LoginFormWrapper enabledJoin={enabledJoin} isDesktop={isDesktop}>
      <PageLayout>
        <PageLayout.SectionBody>
          <Form {...props} />
        </PageLayout.SectionBody>
      </PageLayout>
      <Register />
    </LoginFormWrapper>
  );
};

LoginForm.propTypes = {
  isLoaded: PropTypes.bool,
  enabledJoin: PropTypes.bool,
  isDesktop: PropTypes.bool.isRequired,
};

const Login = inject(({ auth }) => {
  const {
    settingsStore,
    isAuthenticated,
    isLoaded,
    login,
    thirdPartyLogin,
    setProviders,
    providers,
  } = auth;
  const {
    greetingSettings: greetingTitle,
    organizationName,
    hashSettings,
    enabledJoin,
    defaultPage,
    isDesktopClient: isDesktop,
    getOAuthToken,
    getLoginLink,
  } = settingsStore;

  return {
    isAuthenticated,
    isLoaded,
    organizationName,
    greetingTitle,
    hashSettings,
    enabledJoin,
    defaultPage,
    isDesktop,
    login,
    thirdPartyLogin,
    getOAuthToken,
    getLoginLink,
    setProviders,
    providers,
  };
})(withRouter(observer(withTranslation(["Login", "Common"])(LoginForm))));

export default (props) => (
  <I18nextProvider i18n={i18n}>
    <Login {...props} />
  </I18nextProvider>
);
