import React, { useState, useEffect, useRef } from 'react';

export interface CommitInputProps
  extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange' | 'value' | 'type'> {
  value: string | number;
  onCommit: (val: string) => void;
  /** number 类型在编辑时用文本框，提交时由外部校验 min/max */
  type?: 'text' | 'number';
}

/**
 * 失焦/回车提交型输入框：编辑过程中不应用 HTML min/max 限制，便于清空后重输。
 */
export const CommitInput: React.FC<CommitInputProps> = ({
  value,
  onCommit,
  type = 'text',
  min: _min,
  max: _max,
  step: _step,
  onFocus,
  onBlur,
  onKeyDown,
  ...props
}) => {
  const [localVal, setLocalVal] = useState<string>(String(value));
  const focusedRef = useRef(false);
  const localValRef = useRef(localVal);
  const valueRef = useRef(value);
  const onCommitRef = useRef(onCommit);
  localValRef.current = localVal;
  valueRef.current = value;
  onCommitRef.current = onCommit;

  useEffect(() => {
    if (!focusedRef.current) {
      setLocalVal(String(value));
    }
  }, [value]);

  useEffect(() => {
    return () => {
      if (
        focusedRef.current &&
        localValRef.current !== String(valueRef.current)
      ) {
        onCommitRef.current(localValRef.current);
      }
    };
  }, []);

  const commitIfChanged = () => {
    if (localValRef.current !== String(valueRef.current)) {
      onCommitRef.current(localValRef.current);
    }
  };

  const handleBlur = (e: React.FocusEvent<HTMLInputElement>) => {
    focusedRef.current = false;
    onBlur?.(e);
    commitIfChanged();
  };

  const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
    if (e.key === 'Enter') {
      (e.target as HTMLInputElement).blur();
    }
    onKeyDown?.(e);
  };

  const inputType = type === 'number' ? 'text' : type;

  return (
    <input
      {...props}
      type={inputType}
      inputMode={type === 'number' ? 'decimal' : props.inputMode}
      value={localVal}
      onChange={(e) => setLocalVal(e.target.value)}
      onFocus={(e) => {
        focusedRef.current = true;
        onFocus?.(e);
      }}
      onBlur={handleBlur}
      onKeyDown={handleKeyDown}
    />
  );
};

export interface CommitTextareaProps
  extends Omit<React.TextareaHTMLAttributes<HTMLTextAreaElement>, 'onChange' | 'value'> {
  value: string;
  onCommit: (val: string) => void;
}

/** 失焦提交型多行输入框 */
export const CommitTextarea: React.FC<CommitTextareaProps> = ({
  value,
  onCommit,
  onFocus,
  onBlur,
  onKeyDown,
  ...props
}) => {
  const [localVal, setLocalVal] = useState<string>(value);
  const focusedRef = useRef(false);
  const localValRef = useRef(localVal);
  const valueRef = useRef(value);
  const onCommitRef = useRef(onCommit);
  localValRef.current = localVal;
  valueRef.current = value;
  onCommitRef.current = onCommit;

  useEffect(() => {
    if (!focusedRef.current) {
      setLocalVal(value);
    }
  }, [value]);

  useEffect(() => {
    return () => {
      if (focusedRef.current && localValRef.current !== valueRef.current) {
        onCommitRef.current(localValRef.current);
      }
    };
  }, []);

  const commitIfChanged = () => {
    if (localValRef.current !== valueRef.current) {
      onCommitRef.current(localValRef.current);
    }
  };

  const handleBlur = (e: React.FocusEvent<HTMLTextAreaElement>) => {
    focusedRef.current = false;
    onBlur?.(e);
    commitIfChanged();
  };

  const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
    if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) {
      (e.target as HTMLTextAreaElement).blur();
    }
    onKeyDown?.(e);
  };

  return (
    <textarea
      {...props}
      value={localVal}
      onChange={(e) => setLocalVal(e.target.value)}
      onFocus={(e) => {
        focusedRef.current = true;
        onFocus?.(e);
      }}
      onBlur={handleBlur}
      onKeyDown={handleKeyDown}
    />
  );
};
