"use client";

import {
  useId,
  useState,
  type ChangeEvent,
  type ComponentPropsWithRef,
  type FormEvent,
  type ReactNode,
} from "react";
import { cx } from "../../utils";
import { FoxFormLabel } from "../fox-form-label";

export type FoxTextAreaState = "default" | "focused" | "completed" | "error" | "disabled" | "view";

/**
 * 네이티브 `<textarea>`가 받는 것을 그대로 넘겨받는다 — rows·cols·maxLength·name·
 * required·readOnly·disabled·autoComplete 등. 이름이 겹치거나 의미가 다른 것만 걷어낸다.
 */
type NativeTextAreaProps = Omit<
  ComponentPropsWithRef<"textarea">,
  "onChange" | "onInput" | "className" | "children" | "hidden"
>;

export interface FoxTextAreaProps extends NativeTextAreaProps {
  /** 값이 첫 인자다. */
  onChange?: (value: string, event: ChangeEvent<HTMLTextAreaElement>) => void;
  onInput?: (value: string, event: FormEvent<HTMLTextAreaElement>) => void;
  label?: string;
  /** 헬퍼 메시지. 색은 상태를 따라간다. */
  message?: string;
  /** 헬퍼 메시지 앞 아이콘. `currentColor`로 그려야 상태 색을 따라간다. */
  messageIcon?: ReactNode;
  /** 글자 수를 오른쪽 아래에 보여준다. `maxLength`가 있으면 `현재/최대`로 적는다. */
  counter?: boolean;
  /** 오류 표시. `aria-invalid`가 되고 테두리·헬퍼·카운터 색이 바뀐다. */
  invalid?: boolean;
  /** 주면 모양이 그 상태로 고정된다. 없으면 포커스·값·비활성으로 브라우저가 판단한다. */
  state?: FoxTextAreaState;
  /** 참이면 렌더하지 않는다(DOM에 남지 않는다). */
  hidden?: boolean;
  /** 배치 조정용. */
  className?: string;
}

/**
 * @fox 여러 줄 입력. 시안에 크기 축이 없어 높이는 `rows`가 정한다(기본 5줄).
 *
 * ⚠️ 스타일은 이 파일이 import하지 않는다 — 호스트 앱이 `@use "@fox/styles/components"`
 * (또는 개별 파티셜)로 한 번 불러와야 한다.
 */
export function FoxTextArea({
  onChange,
  onInput,
  label,
  message,
  messageIcon,
  counter = false,
  invalid = false,
  state,
  hidden = false,
  className,
  id,
  rows = 5,
  value,
  defaultValue,
  maxLength,
  ...rest
}: FoxTextAreaProps) {
  const autoId = useId();

  // 카운터는 현재 길이를 알아야 한다. 비제어 입력은 DOM만 알고 있으므로 직접 따라간다.
  const [typedLength, setTypedLength] = useState(() => String(defaultValue ?? "").length);

  if (hidden) {
    return null;
  }

  const fieldId = id ?? `${autoId}-field`;
  const messageId = `${autoId}-message`;
  const length = value !== undefined ? String(value).length : typedLength;
  const errored = invalid || state === "error";
  const showFooter = Boolean(message) || counter;

  const handleChange = (event: ChangeEvent<HTMLTextAreaElement>) => {
    if (value === undefined) {
      setTypedLength(event.target.value.length);
    }
    onChange?.(event.target.value, event);
  };

  const handleInput = (event: FormEvent<HTMLTextAreaElement>) => {
    onInput?.((event.target as HTMLTextAreaElement).value, event);
  };

  return (
    <div className={cx("fox-text-area", className)} data-state={state}>
      {label && (
        <FoxFormLabel htmlFor={fieldId}>{label}</FoxFormLabel>
      )}

      <div className="fox-text-area__box">
        <textarea
          {...rest}
          id={fieldId}
          className="fox-text-area__field"
          rows={rows}
          value={value}
          defaultValue={defaultValue}
          maxLength={maxLength}
          aria-invalid={errored || undefined}
          aria-describedby={message ? messageId : undefined}
          onChange={handleChange}
          onInput={handleInput}
        />
      </div>

      {showFooter && (
        <div className="fox-text-area__footer">
          {message && (
            <p className="fox-text-area__message" id={messageId}>
              {messageIcon && (
                <span className="fox-text-area__message-icon" aria-hidden="true">
                  {messageIcon}
                </span>
              )}
              {message}
            </p>
          )}

          {counter && (
            <p className="fox-text-area__counter">
              <span className="fox-text-area__counter-current">{length}</span>
              {maxLength !== undefined && `/${maxLength}`}
            </p>
          )}
        </div>
      )}
    </div>
  );
}
