import React, { useEffect, useState } from 'react';
import { Form, Field, useFormState, FormApi } from 'react-final-form';
import { OnChange } from 'react-final-form-listeners';
import { useTranslation } from 'react-i18next';

import Button from '@mui/material/Button';
import Checkbox from '@mui/material/Checkbox';
import FormControlLabel from '@mui/material/FormControlLabel';

import { CheckboxField, InputField, KnownHosts } from '@app/components';
import { LoadingState, useKnownHosts, useSettings } from '@app/hooks';

import './LoginForm.css';

interface LoginFormProps {
  onSubmit: (values: any) => void;
  disableSubmitButton: boolean;
  onResetPassword: () => void;
}

interface LoginFormBodyProps extends LoginFormProps {
  form: FormApi;
  handleSubmit: (event?: React.SyntheticEvent) => void;
}

const LoginFormBody = ({
  form,
  handleSubmit,
  disableSubmitButton,
  onResetPassword,
}: LoginFormBodyProps) => {
  const { t } = useTranslation();
  const PASSWORD_LABEL = t('Common.label.password');
  const STORED_PASSWORD_LABEL = `* ${t('LoginForm.label.savedPassword')} *`;

  const settings = useSettings();
  const hosts = useKnownHosts();
  const { values } = useFormState();

  const selectedHost = hosts.status === LoadingState.READY ? hosts.value?.selectedHost : undefined;

  const [useStoredPasswordLabel, setUseStoredPasswordLabel] = useState(false);
  const [storedHashInvalidated, setStoredHashInvalidated] = useState(false);

  const canUseStoredPassword = (remember: boolean, password: string | undefined) =>
    Boolean(remember && selectedHost?.hashedPassword && !password && !storedHashInvalidated);

  const togglePasswordLabel = (on: boolean) => setUseStoredPasswordLabel(on);

  // @critical Host-sync must not touch autoConnect — app-level setting, not per-host.
  useEffect(() => {
    if (!selectedHost) {
      return;
    }

    form.change('userName', selectedHost.userName);
    form.change('password', '');
    form.change('remember', Boolean(selectedHost.remember));

    setStoredHashInvalidated(false);
    togglePasswordLabel(
      Boolean(selectedHost.remember && selectedHost.hashedPassword)
    );
  }, [selectedHost, form]);

  useEffect(() => {
    if (settings.status !== LoadingState.READY) {
      return;
    }
    form.change('autoConnect', settings.value?.autoConnect);
  }, [settings, form]);

  const onUserNameChange = (userName: string | undefined) => {
    const fieldChanged = selectedHost?.userName?.toLowerCase() !== userName?.toLowerCase();
    if (canUseStoredPassword(values.remember, values.password) && fieldChanged) {
      setStoredHashInvalidated(true);
    }
  };

  const onRememberChange = (checked: boolean) => {
    // @critical Writes form-only, never to persisted setting — "remember" toggle isn't a preference edit.
    if (!checked && values.autoConnect) {
      form.change('autoConnect', false);
    }

    togglePasswordLabel(canUseStoredPassword(checked, values.password));
  };

  // @critical Only persist-path for autoConnect; wired to native onChange, not <OnChange>,
  // to avoid leaking form.change() writes into Dexie.
  const onUserToggleAutoConnect = (checked: boolean, fieldOnChange: (v: boolean) => void) => {
    fieldOnChange(checked);

    if (settings.status === LoadingState.READY) {
      void settings.update({ autoConnect: checked });
    }

    if (checked && !values.remember) {
      form.change('remember', true);
    }
  };

  return (
    <form className="loginForm" onSubmit={handleSubmit}>
      <div className="loginForm-items">
        <div className="loginForm-item">
          <Field
            label={t('Common.label.username')}
            name="userName"
            component={InputField}
            autoComplete="username"
          />
          <OnChange name="userName">{onUserNameChange}</OnChange>
        </div>
        <div className="loginForm-item">
          <Field
            label={useStoredPasswordLabel ? STORED_PASSWORD_LABEL : PASSWORD_LABEL}
            onFocus={() => setUseStoredPasswordLabel(false)}
            onBlur={() =>
              togglePasswordLabel(canUseStoredPassword(values.remember, values.password))
            }
            name="password"
            type="password"
            component={InputField}
            autoComplete="new-password"
          />
        </div>
        <div className="loginForm-actions">
          <Field
            label={t('LoginForm.label.savePassword')}
            name="remember"
            component={CheckboxField}
          />
          <OnChange name="remember">{onRememberChange}</OnChange>

          <Button color="primary" onClick={onResetPassword}>
            {t('LoginForm.label.forgot')}
          </Button>
        </div>
        <div className="loginForm-item">
          <Field name="selectedHost" component={KnownHosts} />
        </div>
        <div className="loginForm-actions">
          <Field name="autoConnect" type="checkbox">
            {({ input }) => (
              <FormControlLabel
                className="checkbox-field"
                label={t('LoginForm.label.autoConnect')}
                control={
                  <Checkbox
                    className="checkbox-field__box"
                    checked={!!input.value}
                    onChange={(_e, checked) => onUserToggleAutoConnect(checked, input.onChange)}
                    color="primary"
                  />
                }
              />
            )}
          </Field>
        </div>
      </div>
      <Button
        className="loginForm-submit rounded tall"
        color="primary"
        variant="contained"
        type="submit"
        disabled={disableSubmitButton}
      >
        {t('LoginForm.label.login')}
      </Button>
    </form>
  );
};

const LoginForm = (props: LoginFormProps) => {
  const { t } = useTranslation();
  const knownHosts = useKnownHosts();
  const settings = useSettings();

  const validate = (values: any) => {
    const errors: any = {};

    if (!values.userName) {
      errors.userName = t('Common.validation.required');
    }
    if (!values.selectedHost) {
      errors.selectedHost = t('Common.validation.required');
    }

    return errors;
  };

  const handleOnSubmit = ({ userName, ...values }: any) => {
    userName = userName?.trim();
    props.onSubmit({ userName, ...values });
  };

  if (knownHosts.status !== LoadingState.READY || settings.status !== LoadingState.READY) {
    return null;
  }

  const selectedHost = knownHosts.value?.selectedHost;
  const initialValues = {
    selectedHost,
    userName: selectedHost?.userName ?? '',
    remember: Boolean(selectedHost?.remember),
    autoConnect: Boolean(settings.value?.autoConnect),
    password: '',
  };

  return (
    <Form
      onSubmit={handleOnSubmit}
      validate={validate}
      initialValues={initialValues}
      keepDirtyOnReinitialize
    >
      {({ handleSubmit, form }) => (
        <LoginFormBody {...props} form={form} handleSubmit={handleSubmit} />
      )}
    </Form>
  );
};

export default LoginForm;
