/*!
 * Copyright (c) 2024 PLANKA Software GmbH
 * Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
 */

import { dequal } from 'dequal';
import omit from 'lodash/omit';
import React, { useCallback, useMemo, useRef } from 'react';
import classNames from 'classnames';
import { useDispatch, useSelector } from 'react-redux';
import { useTranslation } from 'react-i18next';
import TextareaAutosize from 'react-textarea-autosize';
import { Button, Checkbox, Divider, Form, Header, Tab, TextArea } from 'semantic-ui-react';
import { Input } from '../../../lib/custom-ui';

import selectors from '../../../selectors';
import entryActions from '../../../entry-actions';
import { useForm, useNestedRef } from '../../../hooks';

import styles from './SmtpPane.module.scss';

const SmtpPane = React.memo(() => {
  const config = useSelector(selectors.selectConfig);
  const smtpTestState = useSelector(selectors.selectSmtpTestState);

  const dispatch = useDispatch();
  const [t] = useTranslation();

  const [passwordFieldRef, handlePasswordFieldRef] = useNestedRef('inputRef');
  const isPasswordTouchedRef = useRef(false);

  const defaultData = useMemo(
    () => ({
      smtpHost: config.smtpHost,
      smtpPort: config.smtpPort,
      smtpName: config.smtpName,
      smtpSecure: config.smtpSecure,
      smtpTlsRejectUnauthorized: config.smtpTlsRejectUnauthorized,
      smtpUser: config.smtpUser,
      smtpPassword: config.smtpPassword,
      smtpFrom: config.smtpFrom,
    }),
    [config],
  );

  const [data, handleFieldChange] = useForm(() => ({
    ...defaultData,
    smtpHost: defaultData.smtpHost || '',
    smtpPort: defaultData.smtpPort === null ? '' : `${defaultData.smtpPort}`,
    smtpName: defaultData.smtpName || '',
    smtpSecure: defaultData.smtpSecure,
    smtpTlsRejectUnauthorized: defaultData.smtpTlsRejectUnauthorized,
    smtpUser: defaultData.smtpUser || '',
    smtpPassword: defaultData.smtpPassword || '',
    smtpFrom: defaultData.smtpFrom || '',
  }));

  const isPasswordSet = defaultData.smtpPassword === undefined;

  const cleanData = useMemo(
    () => ({
      ...data,
      smtpHost: data.smtpHost.trim() || null,
      smtpPort: parseInt(data.smtpPort, 10) || null,
      smtpName: data.smtpName.trim() || null,
      smtpUser: data.smtpUser.trim() || null,
      smtpPassword: data.smtpPassword || (isPasswordSet ? undefined : null),
      smtpFrom: data.smtpFrom.trim() || null,
    }),
    [data, isPasswordSet],
  );

  const isModified = useMemo(() => {
    const cleanDataToCheck = omit(cleanData, 'smtpPassword');
    const defaultDataToCheck = omit(defaultData, 'smtpPassword');

    return !dequal(cleanDataToCheck, defaultDataToCheck) || isPasswordTouchedRef.current;
  }, [defaultData, cleanData]);

  const handleSubmit = useCallback(() => {
    isPasswordTouchedRef.current = false;
    dispatch(entryActions.updateConfig(cleanData));
  }, [dispatch, cleanData]);

  const handlePasswordClear = useCallback(() => {
    dispatch(
      entryActions.updateConfig({
        smtpPassword: null,
      }),
    );

    passwordFieldRef.current.focus();
  }, [dispatch, passwordFieldRef]);

  const handleTestClick = useCallback(() => {
    dispatch(entryActions.testSmtpConfig());
  }, [dispatch]);

  const handlePasswordChange = useCallback(
    (event, { value, ...props }) => {
      isPasswordTouchedRef.current = value !== '';
      handleFieldChange(event, { value, ...props });
    },
    [handleFieldChange],
  );

  return (
    <Tab.Pane attached={false} className={styles.wrapper}>
      <Form onSubmit={handleSubmit}>
        <div className={styles.text}>{t('common.host')}</div>
        <Input
          fluid
          name="smtpHost"
          value={data.smtpHost}
          maxLength={256}
          className={styles.field}
          onChange={handleFieldChange}
        />
        <div className={styles.text}>{t('common.port')}</div>
        <Input
          fluid
          type="number"
          name="smtpPort"
          value={data.smtpPort}
          placeholder={data.smtpSecure ? '465' : '587'}
          min={0}
          max={65535}
          step={1}
          className={styles.field}
          onChange={handleFieldChange}
        />
        <div className={styles.text}>
          {t('common.clientHostnameInEhlo')} (
          {t('common.optional', {
            context: 'inline',
          })}
          )
        </div>
        <Input
          fluid
          name="smtpName"
          value={data.smtpName}
          maxLength={256}
          className={styles.field}
          onChange={handleFieldChange}
        />
        <Checkbox
          name="smtpSecure"
          checked={data.smtpSecure}
          label={t('common.useSecureConnection')}
          className={styles.checkbox}
          onChange={handleFieldChange}
        />
        <Checkbox
          name="smtpTlsRejectUnauthorized"
          checked={data.smtpTlsRejectUnauthorized}
          label={t('common.rejectUnauthorizedTlsCertificates')}
          className={classNames(styles.field, styles.checkbox)}
          onChange={handleFieldChange}
        />
        <div className={styles.text}>
          {t('common.username')} (
          {t('common.optional', {
            context: 'inline',
          })}
          )
        </div>
        <Input
          fluid
          name="smtpUser"
          value={data.smtpUser}
          maxLength={256}
          className={styles.field}
          onChange={handleFieldChange}
        />
        <div className={styles.text}>
          {t('common.password')} (
          {t('common.optional', {
            context: 'inline',
          })}
          )
        </div>
        <Input.Password
          fluid
          ref={handlePasswordFieldRef}
          name="smtpPassword"
          value={data.smtpPassword}
          placeholder={isPasswordSet ? t('common.passwordIsSet') : undefined}
          maxLength={256}
          className={styles.field}
          onClear={!data.smtpPassword && isPasswordSet ? handlePasswordClear : undefined}
          onChange={handlePasswordChange}
        />
        <div className={styles.text}>
          {t('common.defaultFrom')} (
          {t('common.optional', {
            context: 'inline',
          })}
          )
        </div>
        <Input
          fluid
          name="smtpFrom"
          value={data.smtpFrom}
          maxLength={256}
          className={styles.field}
          onChange={handleFieldChange}
        />
        <div className={styles.controls}>
          <Button positive disabled={!isModified} content={t('action.save')} />
          {config.smtpHost && !isModified && (
            <Button
              type="button"
              content={t('action.sendTestEmail')}
              loading={smtpTestState.isLoading}
              disabled={smtpTestState.isLoading}
              onClick={handleTestClick}
            />
          )}
        </div>
      </Form>
      {smtpTestState.logs && (
        <>
          <Divider horizontal>
            <Header as="h4">
              {t('common.testLog', {
                context: 'title',
              })}
            </Header>
          </Divider>
          <TextArea
            readOnly
            as={TextareaAutosize}
            value={smtpTestState.logs.join('\n')}
            className={styles.testLog}
          />
        </>
      )}
    </Tab.Pane>
  );
});

export default SmtpPane;
