import { ConfigProvider, Input as OldInput, InputProps } from 'antd';
import React, {
  ChangeEvent,
  ReactNode,
  useContext,
  useEffect,
  useMemo,
  useState,
} from 'react';
import './index.less';
import classNames from 'classnames';
import { SearchProps } from 'antd/lib/input/Search';
import { Icon } from '../Icon';
import { PasswordProps } from 'antd/lib/input/Password';
import { AOP } from '../utils/AOP';
import { TextAreaProps } from 'antd/lib/input/TextArea';
import { useTheme } from '@btri-ui/hooks';

interface ExtraProps {
  vertify?: VertifyProps;
  textAlign?: 'left' | 'right' | 'center';
}
interface VertifyProps {
  status: 'success' | 'error' | 'warning';
  message?: string;
}

const Input = (props: InputProps & ExtraProps) => {
  const {
    addonAfter,
    addonBefore,
    prefix,
    suffix,
    allowClear,
    value,
    showCount,
    maxLength,
    vertify,
    textAlign = 'left',
  } = props;

  // 为了与 antd 的生态保持兼容性，我们要求必须要使用 `.@{ant-prefix}` 变量来生成类名
  const { getPrefixCls } = useContext(ConfigProvider.ConfigContext);
  const prefixCls = getPrefixCls('btri-input');

  const status = vertify?.status;
  const message = vertify?.message;

  const statusClassName = useMemo(() => {
    let name = `${prefixCls}`;
    if (props.size === 'large') {
      name = `${name}-lg`;
    } else if (props.size === 'small') {
      name = `${name}-sm`;
    }
    return name;
  }, [props.size]);

  const inputIconType = useMemo(() => {
    let type = `${prefixCls}`;
    if (addonAfter || addonBefore) {
      type = `${type}-addon`;
    }
    if (prefix || suffix || allowClear || showCount || maxLength) {
      type = `${type}-pureIcon`;
    }
    return type;
  }, [
    addonAfter,
    addonBefore,
    prefix,
    suffix,
    allowClear,
    showCount,
    maxLength,
  ]);

  const [newVal, setNewVal] = useState(value);
  useEffect(() => {
    setNewVal(value);
  }, [value]);

  const newChange = new AOP<ChangeEvent<HTMLInputElement>, void>(props.onChange)
    .after((e) => {
      setNewVal(e.target.value);
    })
    .getFunction();

  const [theme] = useTheme();

  const newSuffix = useMemo(() => {
    const resIcons: ReactNode[] = [];
    if (allowClear && newVal) {
      resIcons.push(
        <Icon
          iconName="ErrorOne"
          style={{ cursor: 'pointer' }}
          onClick={() => {
            setNewVal('');
            props.onChange({
              target: {
                value: '',
              },
            } as any);
          }}
        ></Icon>,
      );
    }
    if (status) {
      const statusIcons = {
        success: {
          name: 'CheckOnCircleOne',
          color: theme['green-6'],
        },
        error: {
          name: 'AttentionCircleTwo',
          color: theme['red-6'],
        },
        warning: {
          name: 'AttentionCircleTwo',
          color: theme['orange-6'],
        },
      };
      resIcons.push(
        <Icon
          iconName={statusIcons[status].name}
          style={{ color: statusIcons[status].color }}
        ></Icon>,
      );
    }
    return resIcons;
  }, [allowClear, status, theme, newVal]);

  return (
    <>
      <OldInput
        suffix={newSuffix}
        value={newVal}
        {...props}
        className={classNames(
          `${prefixCls}-box`,
          `${prefixCls}-${status}`,
          statusClassName,
          inputIconType,
          `${prefixCls}-${textAlign}`,
          props.className,
        )}
        allowClear={false}
        onChange={(e) => {
          newChange(e);
        }}
      >
        {props.children}
      </OldInput>
      {message && (
        <div
          className={classNames(
            `${prefixCls}-box`,
            `${prefixCls}-${status}`,
            statusClassName,
          )}
        >
          <div className="status-box">
            <div>{message}</div>
          </div>
        </div>
      )}
    </>
  );
};

const Search = (props: SearchProps) => {
  const { getPrefixCls } = useContext(ConfigProvider.ConfigContext);
  const prefixCls = getPrefixCls('btri-input');
  const [value, setValue] = React.useState('');

  // 拦截change
  const newChange = new AOP<React.ChangeEvent<HTMLInputElement>, void>(
    props.onChange,
  )
    .before((e) => {
      setValue(e.target.value);
    })
    .getFunction();

  const searchIcon = props.loading ? (
    <Icon
      iconName={'Loading'}
      spin
      style={{ color: 'var(--primary-6)' }}
    ></Icon>
  ) : (
    <Icon
      iconName={'Search'}
      style={{ cursor: 'pointer' }}
      onClick={(e) => {
        props.onSearch?.(value, e);
      }}
    ></Icon>
  );

  return (
    <OldInput
      onPressEnter={(e) => {
        props.onSearch?.(value, e);
      }}
      suffix={searchIcon}
      {...props}
      onChange={newChange}
      className={classNames(`${prefixCls}-search-box`, props.className)}
    >
      {props.children}
    </OldInput>
  );
};
Input.Search = Search;

const Password = (props: PasswordProps) => {
  const { getPrefixCls } = useContext(ConfigProvider.ConfigContext);
  const prefixCls = getPrefixCls('btri-input');

  const iconRender = (visible: boolean) =>
    visible ? (
      <Icon iconName={'PreviewOpenOne'} style={{ fontSize: '20px' }}></Icon>
    ) : (
      <Icon iconName={'PreviewClose'} style={{ fontSize: '20px' }}></Icon>
    );

  return (
    <OldInput.Password
      iconRender={iconRender}
      {...props}
      className={(classNames(`${prefixCls}-pwd-box`), props.className)}
    >
      {props.children}
    </OldInput.Password>
  );
};

Input.Password = Password;

const TextArea = (props: TextAreaProps) => {
  const { getPrefixCls } = useContext(ConfigProvider.ConfigContext);
  const prefixCls = getPrefixCls('btri-input');

  return (
    <OldInput.TextArea
      {...props}
      className={classNames(`${prefixCls}-text-box`, props.className)}
    >
      {props.children}
    </OldInput.TextArea>
  );
};

Input.TextArea = TextArea;

export { Input };
