import React, { useEffect, useMemo, useRef, useState } from 'react';
import { Link as LinkIcon, Loader2, X } from 'lucide-react';
import type { ResearchComposerState } from '../../hooks/useResearchComposer';
import type {
  NoteEmbedInput,
  NoteType,
  ResearchFile,
  ResearchWorkspace,
  SourceKind,
  UploadResearchFileInput,
} from '../../types/research';
import { NOTE_TYPE_LABELS } from './primitives/researchMeta';
import { embedToHtml, ResearchEditor } from './primitives/ResearchEditor';
import {
  filterResearchFilesByIds,
  ResearchFileList,
  ResearchFilePickerModal,
  ResearchFileUploadButton,
} from './primitives/ResearchFiles';

interface ResearchCaptureModalProps {
  isOpen: boolean;
  draft: ResearchComposerState;
  workspaces: ResearchWorkspace[];
  contextLabel?: string;
  isSubmitting?: boolean;
  error?: string | null;
  onClose: () => void;
  onDraftChange: (patch: Partial<ResearchComposerState>) => void;
  onPreviewLink: (url: string, kind?: SourceKind) => Promise<NoteEmbedInput>;
  workspaceFiles: ResearchFile[];
  onUploadFiles: (files: UploadResearchFileInput[]) => Promise<ResearchFile[] | unknown>;
  onOpenFile: (file: ResearchFile) => Promise<void> | void;
  onPreviewFile: (file: ResearchFile) => void;
  onSubmit: () => void;
}

const noteTypeOptions: NoteType[] = [
  'fact',
  'management_signal',
  'claim',
  'risk',
  'catalyst',
  'valuation_point',
  'question',
];

const sourceKinds: SourceKind[] = [
  'manual',
  'article',
  'transcript',
  'filing',
  'news_feed',
  'model',
];

export const ResearchCaptureModal: React.FC<ResearchCaptureModalProps> = ({
  isOpen,
  draft,
  workspaces,
  contextLabel,
  isSubmitting = false,
  error,
  onClose,
  onDraftChange,
  onPreviewLink,
  workspaceFiles,
  onUploadFiles,
  onOpenFile,
  onPreviewFile,
  onSubmit,
}) => {
  const editorContainerRef = useRef<HTMLDivElement>(null);
  const linkInputRef = useRef<HTMLInputElement>(null);
  const [isFetchingPreview, setIsFetchingPreview] = useState(false);
  const [previewError, setPreviewError] = useState<string | null>(null);
  const [fileError, setFileError] = useState<string | null>(null);
  const [isFilePickerOpen, setIsFilePickerOpen] = useState(false);

  useEffect(() => {
    if (!isOpen) {
      return;
    }

    if (draft.captureMode === 'link' && linkInputRef.current) {
      linkInputRef.current.focus();
      return;
    }

    if (!editorContainerRef.current) {
      return;
    }
    const editorEl = editorContainerRef.current.querySelector('.tiptap');
    if (editorEl instanceof HTMLElement) {
      editorEl.focus();
    }
  }, [draft.captureMode, isOpen]);

  const activeWorkspaceLabel = useMemo(
    () =>
      workspaces.find((workspace) => workspace.id === draft.workspaceId)?.name ??
      'Choose workspace',
    [draft.workspaceId, workspaces],
  );

  const isValid = Boolean(draft.rawText.trim());
  const attachedFiles = useMemo(
    () => filterResearchFilesByIds(workspaceFiles, draft.fileIds),
    [draft.fileIds, workspaceFiles],
  );

  const previewLink = async (url: string, kind = draft.sourceKind) => {
    const embed = await onPreviewLink(url, kind);
    return embed;
  };

  const handleFetchPreview = async () => {
    const url = draft.linkUrlDraft.trim() || draft.sourceUrl.trim();
    if (!url) {
      setPreviewError('Enter a URL to preview.');
      return;
    }

    setIsFetchingPreview(true);
    setPreviewError(null);
    try {
      const embed = await onPreviewLink(url, draft.sourceKind);
      onDraftChange({
        linkUrlDraft: embed.url,
        sourceUrl: embed.url,
        sourceTitle: embed.title,
        sourceKind: embed.kind,
        embeds: [embed],
        bodyHtml: embedToHtml(embed),
        rawText: embed.excerpt || embed.title,
      });
    } catch (previewFailure) {
      setPreviewError(
        previewFailure instanceof Error ? previewFailure.message : String(previewFailure),
      );
    } finally {
      setIsFetchingPreview(false);
    }
  };

  const handleKeyDown = (event: React.KeyboardEvent) => {
    if (event.key === 'Escape') {
      onClose();
      return;
    }

    if ((event.metaKey || event.ctrlKey) && event.key === 'Enter' && isValid) {
      event.preventDefault();
      onSubmit();
    }
  };

  if (!isOpen) {
    return null;
  }

  return (
    <div
      className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4"
      onClick={onClose}
      role="dialog"
      aria-modal="true"
      aria-labelledby="capture-modal-title"
    >
      <div
        className="flex max-h-[90vh] w-full max-w-3xl flex-col overflow-hidden rounded-[24px] border border-term-border bg-term-elevated shadow-2xl"
        onClick={(event) => event.stopPropagation()}
        onKeyDown={handleKeyDown}
      >
        <div className="flex items-center justify-between border-b border-term-border bg-term-surface px-6 py-4">
          <div>
            <h2 id="capture-modal-title" className="text-lg font-mono font-semibold text-term-text">
              Capture Research Note
            </h2>
            {contextLabel ? (
              <p className="mt-1 text-xs text-term-text-muted">{contextLabel}</p>
            ) : null}
          </div>
          <button
            type="button"
            onClick={onClose}
            className="text-term-text-tertiary transition-colors hover:text-term-text"
            aria-label="Close modal"
          >
            <X className="h-5 w-5" />
          </button>
        </div>

        <div className="flex-1 space-y-4 overflow-y-auto p-6">
          <div className="grid gap-3 md:grid-cols-3">
            <label className="flex flex-col gap-2">
              <span className="text-xs font-mono text-term-text-muted">Workspace</span>
              <select
                value={draft.workspaceId}
                onChange={(event) => onDraftChange({ workspaceId: event.target.value })}
                className="w-full rounded border border-term-border bg-term-bg px-3 py-2 text-sm font-mono text-term-text transition-colors focus:border-info focus:outline-none"
              >
                <option value="">{workspaces.length > 0 ? 'Choose workspace' : 'No workspaces yet'}</option>
                {workspaces.map((workspace) => (
                  <option key={workspace.id} value={workspace.id}>
                    {workspace.name}
                  </option>
                ))}
              </select>
            </label>
            <label className="flex flex-col gap-2">
              <span className="text-xs font-mono text-term-text-muted">Ticker</span>
              <input
                type="text"
                value={draft.ticker}
                onChange={(event) =>
                  onDraftChange({ ticker: event.target.value.toUpperCase() })
                }
                placeholder="AAPL"
                className="w-full rounded border border-term-border bg-term-bg px-3 py-2 text-sm font-mono text-term-text transition-colors placeholder:text-term-text-tertiary focus:border-info focus:outline-none"
              />
            </label>
            <label className="flex flex-col gap-2">
              <span className="text-xs font-mono text-term-text-muted">Type</span>
              <select
                value={draft.userNoteTypeOverride ?? ''}
                onChange={(event) =>
                  onDraftChange({
                    userNoteTypeOverride: (event.target.value || undefined) as NoteType | undefined,
                  })
                }
                className="w-full rounded border border-term-border bg-term-bg px-3 py-2 text-sm font-mono text-term-text transition-colors focus:border-info focus:outline-none"
              >
                <option value="">Auto-detect</option>
                {noteTypeOptions.map((noteType) => (
                  <option key={noteType} value={noteType}>
                    {NOTE_TYPE_LABELS[noteType] ?? noteType.replace(/_/g, ' ')}
                  </option>
                ))}
              </select>
            </label>
          </div>

          {draft.captureMode === 'link' ? (
            <div className="rounded-lg border border-term-border bg-term-surface p-3">
              <div className="grid gap-3 md:grid-cols-[minmax(0,1fr)_180px_auto]">
                <label className="flex flex-col gap-2">
                  <span className="text-xs font-mono text-term-text-muted">Link URL</span>
                  <input
                    ref={linkInputRef}
                    type="url"
                    value={draft.linkUrlDraft}
                    onChange={(event) =>
                      onDraftChange({
                        linkUrlDraft: event.target.value,
                        sourceUrl: event.target.value,
                      })
                    }
                    placeholder="https://..."
                    className="w-full rounded border border-term-border bg-term-bg px-3 py-2 text-sm font-mono text-term-text transition-colors placeholder:text-term-text-tertiary focus:border-info focus:outline-none"
                  />
                </label>
                <label className="flex flex-col gap-2">
                  <span className="text-xs font-mono text-term-text-muted">Source Type</span>
                  <select
                    value={draft.sourceKind}
                    onChange={(event) =>
                      onDraftChange({ sourceKind: event.target.value as SourceKind })
                    }
                    className="w-full rounded border border-term-border bg-term-bg px-3 py-2 text-sm font-mono text-term-text transition-colors focus:border-info focus:outline-none"
                  >
                    {sourceKinds.map((kind) => (
                      <option key={kind} value={kind}>
                        {kind.replace(/_/g, ' ')}
                      </option>
                    ))}
                  </select>
                </label>
                <button
                  type="button"
                  onClick={() => {
                    void handleFetchPreview();
                  }}
                  disabled={isFetchingPreview}
                  className="inline-flex h-10 items-center justify-center gap-2 self-end rounded border border-info/40 bg-info/10 px-3 text-xs font-mono uppercase tracking-[0.16em] text-info transition-colors hover:border-info hover:text-term-text disabled:cursor-not-allowed disabled:opacity-50"
                >
                  {isFetchingPreview ? (
                    <Loader2 className="h-3.5 w-3.5 animate-spin" />
                  ) : (
                    <LinkIcon className="h-3.5 w-3.5" />
                  )}
                  Fetch Preview
                </button>
              </div>
              {previewError ? (
                <div className="mt-3 rounded border border-negative/40 bg-negative/10 px-3 py-2 text-xs font-mono text-negative">
                  {previewError}
                </div>
              ) : null}
            </div>
          ) : null}

          <div ref={editorContainerRef}>
            <label className="mb-1.5 block text-xs font-mono text-term-text-muted">
              Note Content
            </label>
            <ResearchEditor
              content={draft.bodyHtml || draft.rawText}
              embeds={draft.embeds}
              onPreviewLink={previewLink}
              onChange={(html, text, embeds) =>
                onDraftChange({ bodyHtml: html, rawText: text, embeds })
              }
              placeholder="Capture a fact, quote, thesis fragment, risk, catalyst, or unresolved question..."
              minRows={8}
              compact
            />
          </div>

          <div className="space-y-3 rounded-lg border border-term-border bg-term-surface p-3">
            <div className="flex flex-wrap items-center justify-between gap-2">
              <div className="text-xs font-mono text-term-text-muted">Attached Files</div>
              <div className="flex flex-wrap gap-2">
                <ResearchFileUploadButton
                  disabled={!draft.workspaceId}
                  label="Upload"
                  onError={setFileError}
                  onUpload={async (files) => {
                    setFileError(null);
                    const uploaded = await onUploadFiles(files);
                    const uploadedIds = Array.isArray(uploaded)
                      ? uploaded.map((file) => file.id)
                      : [];
                    onDraftChange({
                      fileIds: Array.from(new Set([...draft.fileIds, ...uploadedIds])),
                    });
                  }}
                />
                <button
                  type="button"
                  disabled={!draft.workspaceId}
                  onClick={() => setIsFilePickerOpen(true)}
                  className="inline-flex items-center gap-2 rounded-xl border border-term-border bg-term-bg px-3 py-2 text-xs uppercase tracking-[0.16em] text-term-text-tertiary transition-colors hover:border-info/60 hover:text-term-text disabled:cursor-not-allowed disabled:opacity-50"
                >
                  Link Existing
                </button>
              </div>
            </div>
            <ResearchFileList
              files={attachedFiles}
              selectedFileIds={draft.fileIds}
              emptyLabel="No attached files"
              compact
              onOpenFile={onOpenFile}
              onPreviewFile={onPreviewFile}
              onRemoveFile={(fileId) =>
                onDraftChange({ fileIds: draft.fileIds.filter((id) => id !== fileId) })
              }
            />
            {fileError ? (
              <div className="rounded border border-negative/40 bg-negative/10 px-3 py-2 text-xs font-mono text-negative">
                {fileError}
              </div>
            ) : null}
          </div>

          <div className="grid gap-3 md:grid-cols-[minmax(0,1fr)_220px]">
            <label className="flex flex-col gap-2">
              <span className="text-xs font-mono text-term-text-muted">Source URL</span>
              <input
                type="url"
                value={draft.sourceUrl}
                onChange={(event) => onDraftChange({ sourceUrl: event.target.value })}
                placeholder="https://..."
                className="w-full rounded border border-term-border bg-term-bg px-3 py-2 text-sm font-mono text-term-text transition-colors placeholder:text-term-text-tertiary focus:border-info focus:outline-none"
              />
            </label>
            <label className="flex flex-col gap-2">
              <span className="text-xs font-mono text-term-text-muted">Source Type</span>
              <select
                value={draft.sourceKind}
                onChange={(event) =>
                  onDraftChange({ sourceKind: event.target.value as SourceKind })
                }
                className="w-full rounded border border-term-border bg-term-bg px-3 py-2 text-sm font-mono text-term-text transition-colors focus:border-info focus:outline-none"
              >
                {sourceKinds.map((kind) => (
                  <option key={kind} value={kind}>
                    {kind.replace(/_/g, ' ')}
                  </option>
                ))}
              </select>
            </label>
          </div>

          {error ? (
            <div className="rounded border border-negative/40 bg-negative/10 px-3 py-2 text-xs font-mono text-negative">
              {error}
            </div>
          ) : null}

          <p className="text-[10px] font-mono text-term-text-tertiary">
            Press <kbd className="rounded border border-term-border bg-term-surface px-1 py-0.5">⌘ Enter</kbd> to submit
          </p>
        </div>

        <div className="flex items-center justify-between border-t border-term-border bg-term-surface px-6 py-4">
          <div className="text-xs font-mono text-term-text-muted">
            {activeWorkspaceLabel}
          </div>
          <div className="flex gap-2">
            <button
              type="button"
              onClick={onClose}
              disabled={isSubmitting}
              className="rounded border border-term-border bg-term-bg px-4 py-2 text-xs font-mono text-term-text transition-colors hover:border-info hover:text-info disabled:cursor-not-allowed disabled:opacity-50"
            >
              Cancel
            </button>
            <button
              type="button"
              onClick={onSubmit}
              disabled={!isValid || isSubmitting}
              className="rounded border border-info bg-info px-4 py-2 text-xs font-mono font-semibold text-term-bg transition-colors hover:brightness-110 disabled:cursor-not-allowed disabled:opacity-50"
            >
              {isSubmitting ? 'Capturing...' : 'Capture Note'}
            </button>
          </div>
        </div>
      </div>
      <ResearchFilePickerModal
        isOpen={isFilePickerOpen}
        files={workspaceFiles}
        selectedFileIds={draft.fileIds}
        onClose={() => setIsFilePickerOpen(false)}
        onConfirm={(fileIds) => {
          onDraftChange({ fileIds });
          setIsFilePickerOpen(false);
        }}
        onOpenFile={onOpenFile}
        onPreviewFile={onPreviewFile}
      />
    </div>
  );
};
