import React, { useState, useRef, useCallback, useMemo, useEffect } from 'react';
import { useChatStore } from '../../stores/chatStore';
import { isDmChannel, getChannelOrigin, getApiForOrigin, useSpaceStore } from '../../stores/spaceStore';
import { wsSend } from '../../hooks/useWebSocket';
import { MentionPopover } from './MentionPopover';
import { TypingIndicator } from './TypingIndicator';
import { InputPopover, type InputPopoverTab } from './InputPopover';
import { hasPermissionBit, PermissionBits } from '../../utils/permissions';
import { MAX_MESSAGE_LENGTH, type MemberWithUser } from '@backspace/shared';
import { useSettingsStore } from '../../stores/settingsStore';
import { useUIStore } from '../../stores/uiStore';

interface MessageInputProps {
  channelId: string;
  channelName: string;
}

interface MentionState {
  query: string;
  startIndex: number;
  selectedIndex: number;
}

export function MessageInput({ channelId, channelName }: MessageInputProps) {
  const [content, setContent] = useState('');
  const [files, setFiles] = useState<File[]>([]);
  const [isUploading, setIsUploading] = useState(false);
  const [uploadProgress, setUploadProgress] = useState<Map<number, number>>(new Map());
  const addToast = useUIStore((s) => s.addToast);
  const [mentionState, setMentionState] = useState<MentionState | null>(null);
  const [activePopover, setActivePopover] = useState<InputPopoverTab | null>(null);
  const fileInputRef = useRef<HTMLInputElement>(null);
  const textareaRef = useRef<HTMLTextAreaElement>(null);
  const inputContainerRef = useRef<HTMLDivElement>(null);
  const popoverAnchorRef = useRef<HTMLDivElement>(null);
  const sendMessage = useChatStore((s) => s.sendMessage);
  const replyTo = useChatStore((s) => s.replyTo);
  const setReplyTo = useChatStore((s) => s.setReplyTo);
  const members = useSpaceStore((s) => s.members);
  const typingTimeoutRef = useRef<ReturnType<typeof setTimeout>>();

  // Feature flags
  const gifEnabled = useSettingsStore((s) => s.gifEnabled);

  // Permission gating: DM channels always allow sending; space channels check SEND_MESSAGES
  const channelPerms = useSpaceStore((s) => s.channelPermissions.get(channelId));
  const isDm = isDmChannel(channelId);
  const canSendMessages = isDm || hasPermissionBit(channelPerms, PermissionBits.SEND_MESSAGES);
  const canAttachFiles = isDm || hasPermissionBit(channelPerms, PermissionBits.ATTACH_FILES);

  // Auto-focus textarea on channel navigation
  useEffect(() => {
    textareaRef.current?.focus();
  }, [channelId]);

  // Auto-focus textarea when replying
  useEffect(() => {
    if (replyTo) {
      textareaRef.current?.focus();
    }
  }, [replyTo]);

  // Close popover on channel change
  useEffect(() => {
    setActivePopover(null);
  }, [channelId]);

  // Filter members for the mention popover
  const filteredMembers = useMemo(() => {
    if (!mentionState) return [];
    const q = mentionState.query.toLowerCase();
    return members
      .filter((m) => {
        const name = (m.user.displayName ?? m.user.username).toLowerCase();
        const username = m.user.username.toLowerCase();
        return name.includes(q) || username.includes(q);
      })
      .slice(0, 8);
  }, [members, mentionState]);

  const handleTyping = useCallback(() => {
    if (typingTimeoutRef.current) return;
    const isDm = isDmChannel(channelId);
    if (isDm) {
      wsSend({ type: 'dm_typing_start', dmChannelId: channelId }, getChannelOrigin(channelId));
    } else {
      wsSend({ type: 'typing_start', channelId }, getChannelOrigin(channelId));
    }
    typingTimeoutRef.current = setTimeout(() => {
      typingTimeoutRef.current = undefined;
    }, 3000);
  }, [channelId]);

  const remaining = MAX_MESSAGE_LENGTH - content.length;
  const isOverLimit = remaining < 0;

  const handleSubmit = async () => {
    const trimmed = content.trim();
    if (!trimmed && files.length === 0) return;
    if (isOverLimit) return;

    setIsUploading(true);
    setMentionState(null);
    setActivePopover(null);
    setUploadProgress(new Map());
    try {
      // Upload files first — route to the correct instance for this channel
      const attachmentIds: string[] = [];
      const uploadClient = getApiForOrigin(getChannelOrigin(channelId));
      const failedFiles: string[] = [];

      for (let i = 0; i < files.length; i++) {
        const file = files[i]!;
        try {
          const attachment = await uploadClient.uploads.uploadWithProgress(file, (loaded, total) => {
            setUploadProgress(prev => new Map(prev).set(i, Math.round((loaded / total) * 100)));
          });
          attachmentIds.push(attachment.id);
          setUploadProgress(prev => new Map(prev).set(i, 100));
        } catch (err) {
          failedFiles.push(file.name);
          const msg = err instanceof Error ? err.message : 'Upload failed';
          addToast(`Failed to upload ${file.name}: ${msg}`, 'warning');
        }
      }

      if (failedFiles.length > 0 && attachmentIds.length === 0 && !trimmed) {
        // All uploads failed, no text — nothing to send
        return;
      }

      await sendMessage(channelId, trimmed || '', attachmentIds.length > 0 ? attachmentIds : undefined);
      setContent('');
      setFiles([]);

      // Reset textarea height and re-focus
      if (textareaRef.current) {
        textareaRef.current.style.height = 'auto';
        textareaRef.current.focus();
      }

      // Clear typing timeout
      if (typingTimeoutRef.current) {
        clearTimeout(typingTimeoutRef.current);
        typingTimeoutRef.current = undefined;
      }
    } catch (err) {
      const msg = err instanceof Error ? err.message : 'Failed to send message';
      addToast(msg, 'warning');
    } finally {
      setIsUploading(false);
      setUploadProgress(new Map());
    }
  };

  const selectMention = useCallback((member: MemberWithUser) => {
    if (!mentionState) return;
    const textarea = textareaRef.current;
    const cursorPos = textarea?.selectionStart ?? content.length;
    const before = content.slice(0, mentionState.startIndex);
    const after = content.slice(cursorPos);
    const insertion = `<@${member.userId}> `;
    const newContent = before + insertion + after;
    setContent(newContent);
    setMentionState(null);

    // Restore cursor position after React re-renders
    const newCursorPos = before.length + insertion.length;
    requestAnimationFrame(() => {
      if (textarea) {
        textarea.focus();
        textarea.selectionStart = newCursorPos;
        textarea.selectionEnd = newCursorPos;
      }
    });
  }, [mentionState, content]);

  const handleKeyDown = (e: React.KeyboardEvent) => {
    // Mention popover keyboard navigation
    if (mentionState && filteredMembers.length > 0) {
      if (e.key === 'ArrowDown') {
        e.preventDefault();
        setMentionState((prev) =>
          prev ? { ...prev, selectedIndex: Math.min(prev.selectedIndex + 1, filteredMembers.length - 1) } : null
        );
        return;
      }
      if (e.key === 'ArrowUp') {
        e.preventDefault();
        setMentionState((prev) =>
          prev ? { ...prev, selectedIndex: Math.max(prev.selectedIndex - 1, 0) } : null
        );
        return;
      }
      if (e.key === 'Enter' || e.key === 'Tab') {
        e.preventDefault();
        const selected = filteredMembers[mentionState.selectedIndex];
        if (selected) selectMention(selected);
        return;
      }
      if (e.key === 'Escape') {
        e.preventDefault();
        setMentionState(null);
        return;
      }
    }

    // Default: Enter to submit
    if (e.key === 'Enter' && !e.shiftKey) {
      e.preventDefault();
      handleSubmit();
    }
  };

  const handlePaste = (e: React.ClipboardEvent) => {
    const items = e.clipboardData.items;
    const pastedFiles: File[] = [];
    for (let i = 0; i < items.length; i++) {
      const item = items[i];
      if (item && item.type.startsWith('image/')) {
        const file = item.getAsFile();
        if (file) pastedFiles.push(file);
      }
    }
    if (pastedFiles.length > 0) {
      setFiles((prev) => [...prev, ...pastedFiles]);
    }
  };

  const handleDrop = (e: React.DragEvent) => {
    e.preventDefault();
    const droppedFiles = Array.from(e.dataTransfer.files);
    if (droppedFiles.length > 0) {
      setFiles((prev) => [...prev, ...droppedFiles]);
    }
  };

  const handleDragOver = (e: React.DragEvent) => {
    e.preventDefault();
  };

  const removeFile = (index: number) => {
    setFiles((prev) => prev.filter((_, i) => i !== index));
  };

  const handleChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
    const value = e.target.value;
    const cursorPos = e.target.selectionStart;
    setContent(value);

    // Detect @mention trigger
    const textBeforeCursor = value.slice(0, cursorPos);
    const mentionMatch = textBeforeCursor.match(/@([^\s<]*)$/);

    if (mentionMatch) {
      const atIndex = cursorPos - mentionMatch[0].length;
      // Only trigger at word boundary: start of input, after space, or after newline
      const charBefore = atIndex > 0 ? value[atIndex - 1] : undefined;
      if (charBefore === undefined || charBefore === ' ' || charBefore === '\n') {
        setMentionState({
          query: mentionMatch[1]!,
          startIndex: atIndex,
          selectedIndex: 0,
        });
      } else {
        setMentionState(null);
      }
    } else {
      setMentionState(null);
    }

    handleTyping();

    // Auto-resize textarea
    const textarea = e.target;
    textarea.style.height = 'auto';
    textarea.style.height = Math.min(textarea.scrollHeight, 300) + 'px';
  };

  const handleEmojiSelect = useCallback((emoji: { native: string }) => {
    const textarea = textareaRef.current;
    if (!textarea) {
      setContent((prev) => prev + emoji.native);
      return;
    }
    const start = textarea.selectionStart;
    const end = textarea.selectionEnd;
    const before = content.slice(0, start);
    const after = content.slice(end);
    const newContent = before + emoji.native + after;
    setContent(newContent);

    // Restore cursor position after the emoji
    const newCursorPos = start + emoji.native.length;
    requestAnimationFrame(() => {
      textarea.focus();
      textarea.selectionStart = newCursorPos;
      textarea.selectionEnd = newCursorPos;
    });
  }, [content]);

  const handleGifSelect = useCallback((url: string) => {
    setActivePopover(null);
    sendMessage(channelId, url);
  }, [channelId, sendMessage]);

  const togglePopover = useCallback((tab: InputPopoverTab) => {
    setActivePopover((prev) => prev === tab ? null : tab);
  }, []);

  const canSend = (content.trim() || files.length > 0) && !isOverLimit && !isUploading;

  if (!canSendMessages) {
    return (
      <div data-pip-obstacle="bottom" className="relative px-3 pb-3 flex-shrink-0 md:absolute md:bottom-3 md:left-3 md:right-3 md:z-[110] md:px-0 md:pb-0 md:glass-bubble md:rounded-[14px]">
        <div className="flex items-center justify-center py-[14px] px-4">
          <span className="text-txt-tertiary text-[14px]">You do not have permission to send messages in this channel</span>
        </div>
      </div>
    );
  }

  return (
    <div ref={popoverAnchorRef} data-pip-obstacle="bottom" className="relative px-3 pb-3 flex-shrink-0 md:absolute md:bottom-3 md:left-3 md:right-3 md:z-[110] md:px-0 md:pb-0 md:glass-bubble md:rounded-[14px]">
      <TypingIndicator channelId={channelId} />

      {/* Input popover (emoji / gif) */}
      {activePopover && (
        <InputPopover
          activeTab={activePopover}
          onClose={() => setActivePopover(null)}
          onEmojiSelect={handleEmojiSelect}
          onGifSelect={handleGifSelect}
          anchorRef={popoverAnchorRef}
          gifEnabled={gifEnabled}
          onTabChange={setActivePopover}
        />
      )}

      {replyTo && (
        <div className="bg-interactive-hover rounded-t-lg px-4 py-2 flex items-center justify-between border-b border-white/[0.06]">
          <div className="flex items-center gap-1 text-[14px] text-txt-message truncate">
            <span className="opacity-60">Replying to</span>
            <span className="font-bold">{replyTo.user.displayName ?? replyTo.user.username}</span>
          </div>
          <button
            onClick={() => setReplyTo(null)}
            className="text-txt-tertiary hover:text-txt-primary transition-colors"
          >
            <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
              <path d="M18.4 4L12 10.4L5.6 4L4 5.6L10.4 12L4 18.4L5.6 20L12 13.6L18.4 20L20 18.4L13.6 12L20 5.6L18.4 4Z" />
            </svg>
          </button>
        </div>
      )}
      <div
        ref={inputContainerRef}
        className={`relative bg-surface-input md:bg-transparent ${replyTo ? 'rounded-b-lg' : 'rounded-lg md:rounded-none'} overflow-visible`}
        onDrop={canAttachFiles ? handleDrop : undefined}
        onDragOver={canAttachFiles ? handleDragOver : undefined}
      >
        {/* Mention autocomplete popover */}
        {mentionState && filteredMembers.length > 0 && (
          <MentionPopover
            query={mentionState.query}
            selectedIndex={mentionState.selectedIndex}
            onSelect={selectMention}
            anchorRef={inputContainerRef}
          />
        )}

        {/* File previews */}
        {files.length > 0 && (
          <div className="p-4 flex flex-wrap gap-4 bg-surface-channel/30">
            {files.map((file, i) => {
              const progress = uploadProgress.get(i);
              return (
                <div key={i} className="relative group bg-surface-channel rounded-lg p-2 max-w-[200px] shadow-elevation-low border border-border-hard overflow-hidden">
                  {file.type.startsWith('image/') ? (
                    <img
                      src={URL.createObjectURL(file)}
                      alt={file.name}
                      className="max-h-[150px] rounded object-cover"
                    />
                  ) : (
                    <div className="flex items-center gap-2 text-sm text-txt-secondary py-4 px-2">
                      <svg className="w-8 h-8 opacity-60" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                        <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
                      </svg>
                      <span className="truncate max-w-[120px] font-medium">{file.name}</span>
                    </div>
                  )}
                  {/* Upload progress bar */}
                  {progress !== undefined && progress < 100 && (
                    <div className="absolute bottom-0 left-0 right-0 h-1 bg-white/10">
                      <div
                        className="h-full bg-accent-primary transition-all duration-200"
                        style={{ width: `${progress}%` }}
                      />
                    </div>
                  )}
                  {progress !== undefined && progress < 100 && (
                    <div className="absolute inset-0 bg-black/40 flex items-center justify-center rounded-lg">
                      <span className="text-xs font-medium text-white">{progress}%</span>
                    </div>
                  )}
                  {!isUploading && (
                    <button
                      onClick={() => removeFile(i)}
                      className="absolute -top-2 -right-2 w-7 h-7 bg-accent-rose hover:bg-accent-rose/80 shadow-elevation-high rounded-lg flex items-center justify-center text-white transition-colors z-10"
                    >
                      <svg width="14" height="14" viewBox="0 0 16 16" fill="currentColor">
                        <path d="M5 2a1 1 0 011-1h4a1 1 0 011 1v1h3a1 1 0 110 2h-.08L13 14a2 2 0 01-2 2H5a2 2 0 01-2-2L2.08 5H2a1 1 0 110-2h3V2zm2 0v1h2V2H7z" />
                      </svg>
                    </button>
                  )}
                </div>
              );
            })}
          </div>
        )}

        <div className="flex items-center pl-[10px] pr-1">
          {/* File attach button */}
          {canAttachFiles && (
            <button
              onClick={() => fileInputRef.current?.click()}
              className="w-[34px] h-[34px] flex items-center justify-center rounded-[6px] text-txt-tertiary hover:text-txt-secondary transition-colors flex-shrink-0"
              title="Attach file"
            >
              <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor">
                <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm5 11h-4v4h-2v-4H7v-2h4V7h2v4h4v2z" />
              </svg>
            </button>
          )}
          <input
            ref={fileInputRef}
            type="file"
            multiple
            className="hidden"
            onChange={(e) => {
              const selected = Array.from(e.target.files ?? []);
              if (selected.length > 0) {
                setFiles((prev) => [...prev, ...selected]);
              }
              e.target.value = '';
            }}
          />

          {/* Text input */}
          <textarea
            ref={textareaRef}
            value={content}
            onChange={handleChange}
            onKeyDown={handleKeyDown}
            onPaste={canAttachFiles ? handlePaste : undefined}
            placeholder={`Message ${channelName.startsWith('@') ? channelName : `#${channelName}`}`}
            className="input-embedded flex-1 py-[10px] px-1 resize-none text-[15px] leading-[1.375rem] max-h-[50vh] scrollbar-thin"
            rows={1}

          />

          {/* Send indicator */}
          {isUploading && (
            <div className="p-3 text-txt-tertiary">
              <svg className="w-5 h-5 animate-spin" viewBox="0 0 24 24" fill="none">
                <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
                <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" />
              </svg>
            </div>
          )}

          {/* Character counter (shows when near or over limit) */}
          {content.length > MAX_MESSAGE_LENGTH - 200 && (
            <span className={`text-[12px] font-medium tabular-nums flex-shrink-0 px-1 ${isOverLimit ? 'text-accent-rose' : 'text-txt-tertiary'}`}>
              {remaining}
            </span>
          )}

          {/* GIF button */}
          {gifEnabled && (
            <button
              onClick={() => togglePopover('gif')}
              className={`w-[34px] h-[34px] flex items-center justify-center rounded-[6px] transition-colors flex-shrink-0 ${
                activePopover === 'gif' ? 'text-accent-primary' : 'text-txt-tertiary hover:text-txt-secondary'
              }`}
              title="GIF"
            >
              <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor">
                <path d="M2 5.5A2.5 2.5 0 0 1 4.5 3h15A2.5 2.5 0 0 1 22 5.5v13a2.5 2.5 0 0 1-2.5 2.5h-15A2.5 2.5 0 0 1 2 18.5v-13ZM5.1 14V10h3.2v1.2H6.5v.6h1.6v1.1H6.5V14H5.1Zm4.5 0V10h1.4v4H9.6Zm2.5 0V10h3.2v1.2h-1.8v.5h1.6v1h-1.6V14h-1.4Z" />
              </svg>
            </button>
          )}

          {/* Emoji button */}
          <button
            onClick={() => togglePopover('emoji')}
            className={`w-[34px] h-[34px] flex items-center justify-center rounded-[6px] transition-colors flex-shrink-0 ${
              activePopover === 'emoji' ? 'text-accent-primary' : 'text-txt-tertiary hover:text-txt-secondary'
            }`}
            title="Emoji"
          >
            <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor">
              <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm3.5-9c.83 0 1.5-.67 1.5-1.5S16.33 8 15.5 8 14 8.67 14 9.5s.67 1.5 1.5 1.5zm-7 0c.83 0 1.5-.67 1.5-1.5S9.33 8 8.5 8 7 8.67 7 9.5s.67 1.5 1.5 1.5zm3.5 6.5c2.33 0 4.31-1.46 5.11-3.5H6.89c.8 2.04 2.78 3.5 5.11 3.5z" />
            </svg>
          </button>

          {/* Send button — appears when there's content to send */}
          {canSend && (
            <button
              onClick={handleSubmit}
              disabled={isUploading}
              className="w-[34px] h-[34px] flex items-center justify-center rounded-[6px] bg-accent-primary hover:bg-accent-primary-hover text-white transition-all duration-150 flex-shrink-0 disabled:opacity-50"
              aria-label="Send message"
              title="Send"
            >
              <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
                <path d="M3.4 20.4l17.45-7.48a1 1 0 000-1.84L3.4 3.6a.993.993 0 00-1.39.91L2 9.12c0 .5.37.93.87.99L17 12 2.87 13.88c-.5.07-.87.5-.87 1l.01 4.61c0 .71.73 1.2 1.39.91z" />
              </svg>
            </button>
          )}
        </div>
      </div>
    </div>
  );
}
