import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';

import { AttachmentPreviewList } from '@renderer/components/team/attachments/AttachmentPreviewList';
import { DropZoneOverlay } from '@renderer/components/team/attachments/DropZoneOverlay';
import { MarkdownViewer } from '@renderer/components/chat/viewers/MarkdownViewer';
import { Button } from '@renderer/components/ui/button';
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from '@renderer/components/ui/dialog';
import { Input } from '@renderer/components/ui/input';
import { Label } from '@renderer/components/ui/label';
import { MentionableTextarea } from '@renderer/components/ui/MentionableTextarea';
import { Combobox, type ComboboxOption } from '@renderer/components/ui/combobox';
import { Tooltip, TooltipContent, TooltipTrigger } from '@renderer/components/ui/tooltip';
import { getTeamColorSet } from '@renderer/constants/teamColors';
import { useAttachments } from '@renderer/hooks/useAttachments';
import { useChipDraftPersistence } from '@renderer/hooks/useChipDraftPersistence';
import { useDraftPersistence } from '@renderer/hooks/useDraftPersistence';
import { useStore } from '@renderer/store';
import { chipToken, serializeChipsWithText } from '@renderer/types/inlineChip';
import { buildReplyBlock } from '@renderer/utils/agentMessageFormatting';
import { removeChipTokenFromText } from '@renderer/utils/chipUtils';
import { formatAgentRole } from '@renderer/utils/formatAgentRole';
import { buildMemberColorMap } from '@renderer/utils/memberHelpers';
import { Check, ImagePlus, X } from 'lucide-react';

import { MemberBadge } from '../MemberBadge';

import type { InlineChip } from '@renderer/types/inlineChip';
import type { MentionSuggestion } from '@renderer/types/mention';
import type { AttachmentPayload, ResolvedTeamMember, SendMessageResult } from '@shared/types';

interface QuotedMessage {
  from: string;
  text: string;
}

interface SendMessageDialogProps {
  open: boolean;
  teamName: string;
  members: ResolvedTeamMember[];
  defaultRecipient?: string;
  /** Pre-filled message text (e.g. from editor selection action) */
  defaultText?: string;
  /** Pre-filled inline code chip (from editor selection action) */
  defaultChip?: InlineChip;
  quotedMessage?: QuotedMessage;
  isTeamAlive?: boolean;
  sending: boolean;
  sendError: string | null;
  lastResult: SendMessageResult | null;
  onSend: (
    member: string,
    text: string,
    summary?: string,
    attachments?: AttachmentPayload[]
  ) => void;
  onClose: () => void;
}

export const SendMessageDialog = ({
  open,
  teamName,
  members,
  defaultRecipient,
  defaultText,
  defaultChip,
  quotedMessage,
  isTeamAlive,
  sending,
  sendError,
  lastResult,
  onSend,
  onClose,
}: SendMessageDialogProps): React.JSX.Element => {
  const colorMap = useMemo(() => buildMemberColorMap(members), [members]);
  const recipientOptions = useMemo<ComboboxOption[]>(
    () =>
      members.map((m) => ({
        value: m.name,
        label: m.name,
        description: formatAgentRole(m.role) ?? formatAgentRole(m.agentType) ?? undefined,
      })),
    [members]
  );
  const projectPath = useStore((s) => s.selectedTeamData?.config.projectPath ?? null);
  const [quote, setQuote] = useState<QuotedMessage | undefined>(undefined);
  const [quoteExpanded, setQuoteExpanded] = useState(false);
  const [member, setMember] = useState('');
  const textDraft = useDraftPersistence({ key: 'sendMessage:text' });
  const chipDraft = useChipDraftPersistence('sendMessage:chips');
  const [summary, setSummary] = useState('');
  const prevOpenRef = useRef(false);
  const prevResultRef = useRef<SendMessageResult | null>(null);

  const [isDragOver, setIsDragOver] = useState(false);
  const dragCounterRef = useRef(0);
  const fileInputRef = useRef<HTMLInputElement>(null);

  const {
    attachments,
    error: attachmentError,
    canAddMore,
    addFiles,
    removeAttachment,
    clearAttachments,
    handlePaste,
    handleDrop,
  } = useAttachments({ persistenceKey: `sendMessage:${teamName}:attachments` });

  const selectedMember = members.find((m) => m.name === member);
  const isLeadRecipient = selectedMember?.role === 'lead' || selectedMember?.name === 'team-lead';
  const canAttach = isLeadRecipient && isTeamAlive && canAddMore;

  const [pendingAutoClose, setPendingAutoClose] = useState(false);
  // Reset form on open transition (avoid setState in render)
  useEffect(() => {
    if (open && !prevOpenRef.current) {
      setMember(defaultRecipient ?? '');
      setSummary('');
      setQuote(quotedMessage);
      setQuoteExpanded(false);
      prevResultRef.current = lastResult;
      if (defaultChip) {
        const token = chipToken(defaultChip);
        textDraft.setValue(token + '\n');
        chipDraft.setChips([defaultChip]);
      } else if (defaultText) {
        textDraft.setValue(defaultText);
      }
    }
    prevOpenRef.current = open;
  }, [open, defaultRecipient, defaultText, defaultChip, quotedMessage, lastResult, textDraft, chipDraft]);

  // Track whether auto-close is needed (avoid setState in render)
  useEffect(() => {
    if (!open) return;
    if (lastResult && lastResult !== prevResultRef.current) {
      prevResultRef.current = lastResult;
      setMember('');
      setSummary('');
      setPendingAutoClose(true);
    }
  }, [open, lastResult]);

  // Side effects (onClose mutates parent state) must run in useEffect, not render phase
  useEffect(() => {
    if (pendingAutoClose) {
      textDraft.clearDraft();
      chipDraft.clearChipDraft();
      clearAttachments();
      setPendingAutoClose(false);
      onClose();
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps -- only trigger on pendingAutoClose flag
  }, [pendingAutoClose]);

  const QUOTE_COLLAPSE_THRESHOLD = 120;
  const isQuoteLong = (quote?.text.length ?? 0) > QUOTE_COLLAPSE_THRESHOLD;

  const mentionSuggestions = useMemo<MentionSuggestion[]>(
    () =>
      members.map((m) => ({
        id: m.name,
        name: m.name,
        subtitle: formatAgentRole(m.role) ?? formatAgentRole(m.agentType) ?? undefined,
        color: colorMap.get(m.name),
      })),
    [members, colorMap]
  );

  const attachmentsBlocked = attachments.length > 0 && !isLeadRecipient;

  const canSend =
    member.trim().length > 0 &&
    textDraft.value.trim().length > 0 &&
    summary.trim().length > 0 &&
    !sending &&
    !attachmentsBlocked;

  const handleChipRemove = (chipId: string): void => {
    const chip = chipDraft.chips.find((c) => c.id === chipId);
    if (chip) {
      textDraft.setValue(removeChipTokenFromText(textDraft.value, chip));
    }
    chipDraft.setChips(chipDraft.chips.filter((c) => c.id !== chipId));
  };

  const handleSubmit = (): void => {
    if (!canSend) return;
    const serialized = serializeChipsWithText(textDraft.value.trim(), chipDraft.chips);
    const finalText = quote ? buildReplyBlock(quote.from, quote.text, serialized) : serialized;
    onSend(
      member.trim(),
      finalText,
      summary.trim(),
      attachments.length > 0 ? attachments : undefined
    );
    textDraft.clearDraft();
    chipDraft.clearChipDraft();
    clearAttachments();
  };

  const handleOpenChange = (nextOpen: boolean): void => {
    if (!nextOpen) {
      onClose();
    }
  };

  const handleFileInputChange = useCallback(
    (e: React.ChangeEvent<HTMLInputElement>) => {
      const input = e.target;
      if (input.files?.length) {
        void addFiles(input.files);
      }
      input.value = '';
    },
    [addFiles]
  );

  const handleDragEnter = useCallback((e: React.DragEvent) => {
    e.preventDefault();
    dragCounterRef.current += 1;
    if (dragCounterRef.current === 1) setIsDragOver(true);
  }, []);

  const handleDragLeave = useCallback((e: React.DragEvent) => {
    e.preventDefault();
    dragCounterRef.current -= 1;
    if (dragCounterRef.current <= 0) {
      dragCounterRef.current = 0;
      setIsDragOver(false);
    }
  }, []);

  const handleDragOver = useCallback((e: React.DragEvent) => {
    e.preventDefault();
  }, []);

  const handleDropWrapper = useCallback(
    (e: React.DragEvent) => {
      dragCounterRef.current = 0;
      setIsDragOver(false);
      if (canAttach) handleDrop(e);
    },
    [canAttach, handleDrop]
  );

  const handlePasteWrapper = useCallback(
    (e: React.ClipboardEvent) => {
      if (canAttach) handlePaste(e);
    },
    [canAttach, handlePaste]
  );

  return (
    <Dialog open={open} onOpenChange={handleOpenChange}>
      <DialogContent
        className="sm:max-w-[560px]"
        onDragEnter={canAttach ? handleDragEnter : undefined}
        onDragLeave={canAttach ? handleDragLeave : undefined}
        onDragOver={canAttach ? handleDragOver : undefined}
        onDrop={canAttach ? handleDropWrapper : undefined}
        onPaste={canAttach ? handlePasteWrapper : undefined}
      >
        <DropZoneOverlay active={isDragOver && !!canAttach} />

        <DialogHeader>
          <DialogTitle>Send Message</DialogTitle>
          <DialogDescription>Send a direct message to a team member.</DialogDescription>
        </DialogHeader>

        <div className="grid gap-4 py-2">
          <div className="grid gap-2">
            <Label htmlFor="smd-recipient">Recipient</Label>
            <Combobox
              value={member}
              onValueChange={setMember}
              placeholder="Select member..."
              searchPlaceholder="Search members..."
              emptyMessage="No members found."
              options={recipientOptions}
              renderOption={(option, isSelected) => {
                const resolvedColor = colorMap.get(option.value);
                const optionColorSet = resolvedColor ? getTeamColorSet(resolvedColor) : null;
                return (
                  <>
                    {optionColorSet ? (
                      <span
                        className="mr-2 inline-block size-2 shrink-0 rounded-full"
                        style={{ backgroundColor: optionColorSet.border }}
                      />
                    ) : (
                      <span className="mr-2 inline-block size-2 shrink-0 rounded-full bg-[var(--color-text-muted)]" />
                    )}
                    <span
                      className="min-w-0 truncate font-medium"
                      style={optionColorSet ? { color: optionColorSet.text } : undefined}
                    >
                      {option.label}
                    </span>
                    {option.description ? (
                      <span className="ml-1 shrink-0 text-[10px] text-[var(--color-text-muted)]">
                        {option.description}
                      </span>
                    ) : null}
                    {isSelected ? (
                      <Check size={12} className="ml-auto shrink-0 text-blue-400" />
                    ) : null}
                  </>
                );
              }}
            />
          </div>

          <div className="grid gap-2">
            <div className="flex items-center gap-2">
              <Label htmlFor="smd-message">Message</Label>
              {isLeadRecipient ? (
                <>
                  <input
                    ref={fileInputRef}
                    type="file"
                    accept="image/png,image/jpeg,image/gif,image/webp"
                    multiple
                    className="hidden"
                    onChange={handleFileInputChange}
                  />
                  <Tooltip>
                    <TooltipTrigger asChild>
                      <button
                        type="button"
                        className={`inline-flex items-center gap-1 rounded p-1 transition-colors ${
                          canAttach
                            ? 'text-[var(--color-text-secondary)] hover:text-[var(--color-text)]'
                            : 'text-[var(--color-text-muted)] opacity-40'
                        }`}
                        disabled={!canAttach}
                        onClick={() => fileInputRef.current?.click()}
                      >
                        <ImagePlus size={14} />
                      </button>
                    </TooltipTrigger>
                    <TooltipContent side="top">
                      {!isTeamAlive
                        ? 'Team must be online to attach images'
                        : !canAddMore
                          ? 'Maximum attachments reached'
                          : 'Attach images (paste or drag & drop)'}
                    </TooltipContent>
                  </Tooltip>
                </>
              ) : null}
            </div>

            <AttachmentPreviewList
              attachments={attachments}
              onRemove={removeAttachment}
              error={attachmentError}
              disabled={attachmentsBlocked}
              disabledHint="Image attachments are only supported when sending to team lead. Remove attachments or switch recipient."
            />

            <div className={quote ? 'flex flex-col' : 'contents'}>
              {quote ? (
                <div className="relative overflow-hidden rounded-t-md border border-b-0 border-blue-500/20 bg-blue-950/20 py-2 pl-3 pr-2">
                  {/* Decorative quotation mark */}
                  <span className="pointer-events-none absolute -right-1 top-1/2 -translate-y-1/2 select-none font-serif text-[64px] leading-none text-blue-400/[0.08]">
                    &ldquo;
                  </span>

                  <Tooltip>
                    <TooltipTrigger asChild>
                      <button
                        type="button"
                        className="absolute right-1.5 top-1.5 z-10 rounded p-0.5 text-blue-300/40 hover:text-blue-200"
                        onClick={() => setQuote(undefined)}
                      >
                        <X size={12} />
                      </button>
                    </TooltipTrigger>
                    <TooltipContent side="left">Remove quote</TooltipContent>
                  </Tooltip>

                  <div className="mb-1 flex items-center gap-1.5">
                    <span className="text-[10px] text-blue-300/60">Replying to</span>
                    <MemberBadge name={quote.from} color={colorMap.get(quote.from)} size="sm" />
                  </div>
                  <div
                    className={`pr-5 opacity-50 ${quoteExpanded ? '' : 'max-h-[3.75rem] overflow-hidden'}`}
                  >
                    <MarkdownViewer
                      content={quote.text}
                      bare
                      maxHeight={quoteExpanded ? 'max-h-48' : 'max-h-[3.75rem]'}
                    />
                  </div>
                  {isQuoteLong ? (
                    <button
                      type="button"
                      className="mt-0.5 text-[10px] text-blue-400/60 hover:text-blue-300"
                      onClick={() => setQuoteExpanded((v) => !v)}
                    >
                      {quoteExpanded ? 'less' : 'more'}
                    </button>
                  ) : null}
                </div>
              ) : null}
              <MentionableTextarea
                id="smd-message"
                className={quote ? 'rounded-t-none' : undefined}
                placeholder="Write your message..."
                value={textDraft.value}
                onValueChange={textDraft.setValue}
                suggestions={mentionSuggestions}
                chips={chipDraft.chips}
                onChipRemove={handleChipRemove}
                projectPath={projectPath}
                onFileChipInsert={(chip) => chipDraft.setChips([...chipDraft.chips, chip])}
                onModEnter={handleSubmit}
                minRows={4}
                maxRows={12}
                footerRight={
                  textDraft.isSaved ? (
                    <span className="text-[10px] text-[var(--color-text-muted)]">Draft saved</span>
                  ) : null
                }
              />
            </div>
          </div>

          <div className="grid gap-2">
            <Label htmlFor="smd-summary">Summary</Label>
            <Input
              id="smd-summary"
              className="h-8 text-xs"
              placeholder="Brief summary reflecting the message intent"
              value={summary}
              onChange={(e) => setSummary(e.target.value)}
            />
            <p className="text-[11px] text-[var(--color-text-muted)]">
              Shown as notification preview. Team lead also sees this for peer messages.
            </p>
          </div>

          {sendError ? <p className="text-xs text-red-400">{sendError}</p> : null}
        </div>

        <DialogFooter>
          <Button variant="outline" size="sm" onClick={onClose} disabled={sending}>
            Cancel
          </Button>
          <Button size="sm" onClick={handleSubmit} disabled={!canSend}>
            {sending ? 'Sending...' : 'Send'}
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
};
