/*
 * Copyright 2025 Palantir Technologies, Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { useCallback, useRef, useState } from "react";
import { isDateInRange } from "../dateUtils.js";
/**
 * Manages the editing lifecycle for a single date text input.
 *
 * Handles the two-phase display pattern where the input shows a formatted
 * display value when idle and switches to an editable format when focused.
 */
export function useDateEditState({
  value,
  displayFormatFn,
  editFormatFn,
  parseFn,
  min,
  max,
  onChange
}) {
  const [isEditing, setIsEditing] = useState(false);
  const [inputValue, setInputValue] = useState("");

  // Sync inputValue when external value changes (e.g. parent resets)
  const prevValueTimeRef = useRef(value?.getTime() ?? null);
  const currentValueTime = value?.getTime() ?? null;
  if (prevValueTimeRef.current !== currentValueTime) {
    prevValueTimeRef.current = currentValueTime;
    if (!isEditing) {
      setInputValue(value != null ? editFormatFn(value) : "");
    }
  }

  // During editing the user needs parsable text they can modify and that
  // round-trips through parseFn (e.g. "2024-01-15"). When idle the input may
  // show a different display string. displayedValue is the single source of
  // truth for the input's visible text.
  const displayedValue = isEditing ? inputValue : value != null ? displayFormatFn(value) : "";

  // Parse the input once per render and derive all validation state from it.
  const dateValue = inputValue !== "" ? parseFn(inputValue) : undefined;
  const inputError = (() => {
    // Not editing: no validation feedback.
    // Empty input: the user cleared the field — that means null, not invalid.
    if (!isEditing || inputValue === "") return null;
    if (dateValue == null) return "invalid";
    if (!isDateInRange(dateValue, min, max)) return "out-of-range";
    return null;
  })();

  // The validated date ready for onChange, derived from dateValue + inputError.
  const validatedDate = inputError == null && dateValue != null ? dateValue : null;
  const setDateValue = useCallback(date => {
    setInputValue(date != null ? editFormatFn(date) : "");
  }, [editFormatFn]);
  const startEditing = useCallback(() => {
    setIsEditing(true);
    setDateValue(value);
  }, [value, setDateValue]);
  const stopEditing = useCallback(() => {
    setIsEditing(false);
    setDateValue(value);
  }, [value, setDateValue]);

  // Refs so commitAndStopEditing reads the latest derived values without
  // closing over inputValue/validatedDate (which change every keystroke).
  const inputValueRef = useRef(inputValue);
  inputValueRef.current = inputValue;
  const validatedDateRef = useRef(validatedDate);
  validatedDateRef.current = validatedDate;
  const commitAndStopEditing = useCallback(() => {
    if (inputValueRef.current === "") {
      onChange?.(null);
    } else if (validatedDateRef.current != null) {
      onChange?.(validatedDateRef.current);
    }
    setIsEditing(false);
    setDateValue(value);
  }, [onChange, setDateValue, value]);
  return {
    isEditing,
    displayedValue,
    inputError,
    dateValue,
    startEditing,
    stopEditing,
    commitAndStopEditing,
    setInputValue,
    setDateValue
  };
}
//# sourceMappingURL=useDateEditState.js.map