import type {
  ChangeEvent,
  CSSProperties,
  DragEvent as ReactDragEvent,
  KeyboardEvent as ReactKeyboardEvent,
  PointerEvent as ReactPointerEvent,
  ReactNode,
  RefObject
} from "react"
import type { ChatAttachment } from "@qjclaw/shared-types"

interface ComposerSkill {
  id: string
  name: string
  description: string
}

interface ChatComposerProps {
  prompt: string
  isBound: boolean
  sending: boolean
  canSend: boolean
  isDragOver: boolean
  isResizeActive: boolean
  viewMode: "chat" | "experts" | "plugins" | "settings" | "knowledge"
  shellStyle: CSSProperties
  attachmentInputRef: RefObject<HTMLInputElement | null>
  skillMenuRef: RefObject<HTMLDivElement | null>
  attachmentAccept: string
  attachments: ChatAttachment[]
  placeholder: string
  sendButtonLabel: string
  skillMenuTitle: string
  defaultChatLabel: string
  defaultSkillId: string
  selectedSkillId: string
  selectedSkillName: string
  skills: ComposerSkill[]
  skillMenuOpen: boolean
  attachmentIcon: ReactNode
  submitIcon: ReactNode
  onSubmit: () => void | Promise<void>
  onPromptChange: (value: string) => void
  onTextareaKeyDown: (event: ReactKeyboardEvent<HTMLTextAreaElement>) => void | Promise<void>
  onAttachmentSelection: (event: ChangeEvent<HTMLInputElement>) => void
  onOpenAttachmentPicker: () => void
  onRemoveAttachment: (localPath: string) => void
  onToggleSkillMenu: () => void
  onClearSelectedSkill: () => void
  onChooseSkill: (skillId: string) => void
  onDragEnter: (event: ReactDragEvent<HTMLFormElement>) => void
  onDragOver: (event: ReactDragEvent<HTMLFormElement>) => void
  onDragLeave: (event: ReactDragEvent<HTMLFormElement>) => void
  onDrop: (event: ReactDragEvent<HTMLFormElement>) => void
  onResizePointerDown: (event: ReactPointerEvent<HTMLDivElement>) => void
  onResizePointerMove: (event: ReactPointerEvent<HTMLDivElement>) => void
  onResizePointerEnd: (event: ReactPointerEvent<HTMLDivElement>) => void
}

export function ChatComposer({
  prompt,
  isBound,
  sending,
  canSend,
  isDragOver,
  isResizeActive,
  viewMode,
  shellStyle,
  attachmentInputRef,
  skillMenuRef,
  attachmentAccept,
  attachments,
  placeholder,
  sendButtonLabel,
  skillMenuTitle,
  defaultChatLabel,
  defaultSkillId,
  selectedSkillId,
  selectedSkillName,
  skills,
  skillMenuOpen,
  attachmentIcon,
  submitIcon,
  onSubmit,
  onPromptChange,
  onTextareaKeyDown,
  onAttachmentSelection,
  onOpenAttachmentPicker,
  onRemoveAttachment,
  onToggleSkillMenu,
  onClearSelectedSkill,
  onChooseSkill,
  onDragEnter,
  onDragOver,
  onDragLeave,
  onDrop,
  onResizePointerDown,
  onResizePointerMove,
  onResizePointerEnd
}: ChatComposerProps) {
  return (
    <form
      className={
        "composer-shell"
        + (isDragOver ? " dragging" : "")
        + (isResizeActive ? " resizing" : "")
        + (viewMode === "chat" ? " composer-shell-home" : "")
        + (viewMode === "experts" ? " composer-shell-expert" : "")
      }
      style={shellStyle}
      onSubmit={(event) => {
        event.preventDefault()
        void onSubmit()
      }}
      onDragEnter={onDragEnter}
      onDragOver={onDragOver}
      onDragLeave={onDragLeave}
      onDrop={onDrop}
    >
      <input
        ref={attachmentInputRef}
        className="composer-attachment-input"
        type="file"
        accept={attachmentAccept}
        multiple
        tabIndex={-1}
        onChange={onAttachmentSelection}
      />
      {isDragOver ? <div className="composer-drop-indicator">释放以上传附件</div> : null}
      <div
        className="composer-resize-handle"
        role="separator"
        aria-orientation="horizontal"
        aria-label={"\u8c03\u6574\u8f93\u5165\u6846\u9ad8\u5ea6"}
        title={"\u8c03\u6574\u8f93\u5165\u6846\u9ad8\u5ea6"}
        onPointerDown={onResizePointerDown}
        onPointerMove={onResizePointerMove}
        onPointerUp={onResizePointerEnd}
        onPointerCancel={onResizePointerEnd}
      >
        <span aria-hidden="true" />
      </div>
      <div className="composer-surface">
        <label className="composer-field">
          <textarea
            value={prompt}
            disabled={!isBound}
            onChange={(event) => onPromptChange(event.target.value)}
            onKeyDown={(event) => void onTextareaKeyDown(event)}
            placeholder={placeholder}
            className="composer-textarea"
          />
        </label>
        {attachments.length ? (
          <div className="composer-attachment-strip">
            {attachments.map((attachment) => (
              <span key={attachment.localPath} className="composer-attachment-chip">
                <span className="composer-attachment-chip-label">{attachment.name}</span>
                <button type="button" className="composer-attachment-remove" onClick={() => onRemoveAttachment(attachment.localPath)} aria-label={`移除附件 ${attachment.name}`}>
                  x
                </button>
              </span>
            ))}
          </div>
        ) : null}
        <div className="composer-footer">
          <div className="composer-left-tools" ref={skillMenuRef}>
            <button type="button" className="attachment-trigger icon-only" disabled={!isBound || sending} onClick={onOpenAttachmentPicker} aria-label="上传附件" title="上传附件">
              {attachmentIcon}
            </button>
            <button type="button" className="skill-trigger" disabled={!isBound} aria-label={skillMenuTitle} aria-expanded={skillMenuOpen} onClick={onToggleSkillMenu}>
              @
            </button>
            {selectedSkillId !== defaultSkillId ? (
              <button type="button" className="skill-chip" disabled={!isBound} onClick={onClearSelectedSkill}>
                {"@" + selectedSkillName}
              </button>
            ) : null}
            {skillMenuOpen ? (
              <div className="skill-menu" role="menu" aria-label={skillMenuTitle}>
                {skills.map((skill) => {
                  const active = skill.id === selectedSkillId
                  return (
                    <button
                      key={skill.id}
                      type="button"
                      role="menuitemradio"
                      aria-checked={active}
                      className={"skill-menu-item" + (active ? " active" : "")}
                      onClick={() => onChooseSkill(skill.id)}
                    >
                      <strong>{skill.id === defaultSkillId ? defaultChatLabel : "@" + skill.name}</strong>
                      <span>{skill.description}</span>
                    </button>
                  )
                })}
              </div>
            ) : null}
          </div>
          <button
            type="submit"
            className={"composer-submit" + (sending ? " is-busy" : "")}
            disabled={!canSend}
            aria-label={sendButtonLabel}
            title={sendButtonLabel}
          >
            {sending ? <span className="composer-submit-spinner" aria-hidden="true" /> : submitIcon}
            <span className="visually-hidden">{sendButtonLabel}</span>
          </button>
        </div>
        <p className="composer-hint">按 Enter 发送，Shift + Enter 换行</p>
      </div>
    </form>
  )
}
