"use client";

import {
  InputGroup,
  InputGroupButton,
  InputGroupTextarea,
} from "@code/ui/components/input-group";
import { cn } from "@code/ui/lib/utils";
import type { ChatStatus } from "ai";
import { ArrowUpIcon, LoaderCircleIcon, SquareIcon } from "lucide-react";
import type {
  ComponentProps,
  FormEvent,
  FormEventHandler,
  HTMLAttributes,
  KeyboardEventHandler,
  ReactNode,
} from "react";

export interface PromptInputMessage {
  files: [];
  text: string;
}

export type PromptInputProps = Omit<ComponentProps<"form">, "onSubmit"> & {
  onSubmit: (
    message: PromptInputMessage,
    event: FormEvent<HTMLFormElement>
  ) => Promise<void> | void;
};

export const PromptInput = ({
  children,
  className,
  onSubmit,
  ...props
}: PromptInputProps) => {
  const handleSubmit: FormEventHandler<HTMLFormElement> = (event) => {
    event.preventDefault();
    const text = new FormData(event.currentTarget)
      .get("message")
      ?.toString()
      .trim();

    if (!text) {
      return;
    }

    const submitMessage = async () => {
      try {
        await onSubmit({ files: [], text }, event);
      } catch {
        // The owning chat hook exposes submission failures in the composer status.
      }
    };
    void submitMessage();
  };

  return (
    <form
      className={cn("w-full", className)}
      onSubmit={handleSubmit}
      {...props}
    >
      <InputGroup>{children}</InputGroup>
    </form>
  );
};

export type PromptInputBodyProps = HTMLAttributes<HTMLDivElement>;

export const PromptInputBody = ({
  className,
  ...props
}: PromptInputBodyProps) => (
  <div className={cn("contents", className)} {...props} />
);

export type PromptInputTextareaProps = ComponentProps<
  typeof InputGroupTextarea
>;

export const PromptInputTextarea = ({
  className,
  onKeyDown,
  ...props
}: PromptInputTextareaProps) => {
  const handleKeyDown: KeyboardEventHandler<HTMLTextAreaElement> = (event) => {
    onKeyDown?.(event);

    if (
      event.defaultPrevented ||
      event.key !== "Enter" ||
      event.shiftKey ||
      event.nativeEvent.isComposing
    ) {
      return;
    }

    event.preventDefault();
    event.currentTarget.form?.requestSubmit();
  };

  return (
    <InputGroupTextarea
      className={cn("field-sizing-content", className)}
      name="message"
      onKeyDown={handleKeyDown}
      {...props}
    />
  );
};

export type PromptInputButtonProps = ComponentProps<typeof InputGroupButton>;

export const PromptInputButton = ({
  className,
  size = "icon-sm",
  ...props
}: PromptInputButtonProps) => (
  <InputGroupButton
    className={cn(className)}
    size={size}
    type="button"
    {...props}
  />
);

export type PromptInputSubmitProps = ComponentProps<typeof InputGroupButton> & {
  status?: ChatStatus;
};

export const PromptInputSubmit = ({
  children,
  className,
  disabled,
  size = "icon-sm",
  status = "ready",
  ...props
}: PromptInputSubmitProps) => {
  const isBusy = status === "submitted" || status === "streaming";
  let content: ReactNode = children ?? <ArrowUpIcon className="size-4" />;
  if (status === "streaming") {
    content = <SquareIcon className="size-4 fill-current" />;
  } else if (status === "submitted") {
    content = <LoaderCircleIcon className="size-4 animate-spin" />;
  }

  return (
    <InputGroupButton
      aria-busy={isBusy}
      className={cn(className)}
      disabled={disabled}
      size={size}
      type="submit"
      {...props}
    >
      {content}
    </InputGroupButton>
  );
};
