import React from 'react';
import type { DragEvent, MouseEvent, RefObject } from 'react';
import { FolderIcon, CheckIcon, CloseIcon } from '../ui/icons';
import { getTagColorStyle } from '../utils/colors';
import { formatDate } from '../utils/date';
import DocumentThumbnailImage from './DocumentThumbnailImage';
import CorrespondentLinks from './CorrespondentLinks';
import { resolveCorrespondents } from './correspondents';
import { writeTagTransferData } from './tagTransfer';
import useInlineRename from './useInlineRename';

export type Identifier = string | number;

export interface FolderLike {
  id?: Identifier | 'root';
  name?: string;
}

export interface DocumentTag {
  id?: Identifier;
  label?: string;
  color?: string | null;
}

export interface DocumentCorrespondent {
  id?: Identifier;
  name?: string;
  count?: number;
}

export interface DocumentLike {
  id?: Identifier;
  title?: string;
  issued_at?: string | null;
  created_at?: string | null;
  uploaded_at?: string | null;
  tags?: DocumentTag[] | null;
  correspondents?: DocumentCorrespondent[] | null;
}

export type FolderEntry = {
  type: 'folder';
  id: Identifier | 'root';
  key: string;
  folder: FolderLike;
};

export type DocumentEntry = {
  type: 'document';
  id: Identifier;
  key: string;
  document: DocumentLike;
};

export type DocumentsListEntry = FolderEntry | DocumentEntry;

export type FolderEventHandler = (folder: FolderLike, event: MouseEvent<HTMLTableRowElement>) => void;
export type DocumentEventHandler = (document: DocumentLike, event: MouseEvent<HTMLTableRowElement>) => void;

export interface DocumentsListProps {
  entries: DocumentsListEntry[];
  focusedRowKey?: string | null;
  selectedDocumentIdsSet?: Set<Identifier> | null;
  selectedFolderIdsSet?: Set<Identifier | 'root'> | null;
  draggingDocumentIdsSet?: Set<Identifier> | null;
  draggedFolderId?: Identifier | 'root' | null;
  ensureAssetUrl?: (...args: any[]) => unknown;
  getDocumentAsset?: (...args: any[]) => unknown;
  onFolderClick?: FolderEventHandler;
  onFolderSelect?: (folderId: Identifier | 'root') => void;
  onFolderDragOver?: (event: DragEvent<HTMLTableRowElement>, folderId: Identifier | 'root') => void;
  onFolderDragLeave?: (event: DragEvent<HTMLTableRowElement>) => void;
  onFolderDrop?: (event: DragEvent<HTMLTableRowElement>, folderId: Identifier | 'root') => void;
  onFolderDragStart?: (event: DragEvent<HTMLTableRowElement>, folderId: Identifier | 'root') => void;
  onFolderDragEnd?: (event: DragEvent<HTMLTableRowElement>) => void;
  onFolderRename?: (folderId: Identifier | 'root', nextName: string) => Promise<boolean> | boolean;
  onDocumentClick?: DocumentEventHandler;
  onDocumentActivate?: DocumentEventHandler;
  onDocumentDragStart?: (event: DragEvent<HTMLTableRowElement>, document: DocumentLike) => void;
  onDocumentDragEnd?: (event: DragEvent<HTMLTableRowElement>) => void;
  onDocumentTagDragOver?: (event: DragEvent<HTMLTableRowElement>) => void;
  onDocumentTagDragLeave?: (event: DragEvent<HTMLTableRowElement>) => void;
  onDocumentTagDrop?: (event: DragEvent<HTMLTableRowElement>, documentId: Identifier) => void;
  onDocumentRename?: (documentId: Identifier, nextTitle: string) => Promise<boolean> | boolean;
  tagLookupById?: Map<Identifier, DocumentTag> | null;
  onTagClick?: (tagId?: Identifier | null) => void;
  onCorrespondentClick?: (correspondentId?: Identifier | null) => void;
  activeCorrespondentIdSet?: Set<Identifier | null | undefined> | null;
  scrollRef?: RefObject<HTMLElement | null>;
  onClearSelection?: () => void;
}


const DocumentsList: React.FC<DocumentsListProps> = ({
  entries,
  focusedRowKey,
  selectedDocumentIdsSet,
  selectedFolderIdsSet,
  draggingDocumentIdsSet,
  draggedFolderId,
  ensureAssetUrl,
  getDocumentAsset,
  onFolderClick,
  onFolderSelect,
  onFolderDragOver,
  onFolderDragLeave,
  onFolderDrop,
  onFolderDragStart,
  onFolderDragEnd,
  onFolderRename,
  onDocumentClick,
  onDocumentActivate,
  onDocumentDragStart,
  onDocumentDragEnd,
  onDocumentTagDragOver,
  onDocumentTagDragLeave,
  onDocumentTagDrop,
  onDocumentRename,
  tagLookupById,
  onTagClick,
  onCorrespondentClick,
  activeCorrespondentIdSet,
  scrollRef,
  onClearSelection,
}) => {
  const {
    editingId: editingDocumentId,
    draftValue: documentDraft,
    setDraftValue: setDocumentDraft,
    beginEditing: beginDocumentEditing,
    cancelEditing: cancelDocumentEditing,
    submitEditing: submitDocumentEditing,
    savingId: savingDocumentId,
    attachInputRef: attachDocumentInputRef,
  } = useInlineRename<DocumentLike>(onDocumentRename, {
    getCurrentValue: (doc: DocumentLike) => doc?.title ?? '',
    getEntityId: (doc: DocumentLike) => doc?.id ?? null,
  });

  const {
    editingId: editingFolderId,
    draftValue: folderDraft,
    setDraftValue: setFolderDraft,
    beginEditing: beginFolderEditing,
    cancelEditing: cancelFolderEditing,
    submitEditing: submitFolderEditing,
    savingId: savingFolderId,
    attachInputRef: attachFolderInputRef,
  } = useInlineRename<FolderLike>(onFolderRename, {
    getCurrentValue: (folder: FolderLike) => folder?.name ?? '',
    getEntityId: (folder: FolderLike) => folder?.id ?? null,
  });


  const documentSelectionCount = selectedDocumentIdsSet?.size ?? 0;
  const folderSelectionCount = selectedFolderIdsSet?.size ?? 0;
  const totalSelectionCount = documentSelectionCount + folderSelectionCount;

  return (
  <table aria-multiselectable="true">
    <thead
      onClick={() => {
        onClearSelection?.();
      }}
    >
      <tr>
        <th className="thumb-column"></th>
        <th>Name</th>
        <th>Issued</th>
        <th>Added</th>
      </tr>
    </thead>
    <tbody>
      {entries.map((entry) => {
        if (entry.type === 'folder') {
          const folder = entry.folder;
          if (!folder) {
            return null;
          }
          const canDragFolder = folder.id !== 'root';
          const isDraggingFolder = draggedFolderId === folder.id;
          const isSelectedFolder = selectedFolderIdsSet?.has(folder.id);
          const rowKey = `folder:${folder.id}`;
          const canRenameFolder = folder.id !== 'root' && typeof onFolderRename === 'function';
          const isFolderEditing = editingFolderId === folder.id;
          const folderDraftValue = isFolderEditing ? folderDraft : folder.name;
          const trimmedFolderDraft = isFolderEditing ? folderDraft.trim() : '';
          const isFolderSaving = savingFolderId === folder.id;
          const canSubmitFolder =
            isFolderEditing && trimmedFolderDraft.length > 0 && trimmedFolderDraft !== folder.name;
          const allowInlineFolderEdit = canRenameFolder && isSelectedFolder && totalSelectionCount === 1;

          return (
            <tr
              key={entry.key}
              className={`folder${isDraggingFolder ? ' is-dragging' : ''}${
                focusedRowKey === rowKey ? ' focused' : ''
              }${isSelectedFolder ? ' selected' : ''}`}
              id={`folder-row-${folder.id}`}
              onClick={(event) => onFolderClick?.(folder, event)}
              onDoubleClick={(event) => {
                event.preventDefault();
                onFolderSelect?.(folder.id);
              }}
              onDragOver={(event) => onFolderDragOver?.(event, folder.id)}
              onDragLeave={onFolderDragLeave}
              onDrop={(event) => onFolderDrop?.(event, folder.id)}
              draggable={canDragFolder}
              onDragStart={(event) => {
                if (canDragFolder) {
                  onFolderDragStart?.(event, folder.id);
                }
              }}
              onDragEnd={(event) => {
                if (canDragFolder) {
                  onFolderDragEnd?.(event);
                }
              }}
            >
              <td className="thumb-cell">
                <div className="thumb-icon">
                  <FolderIcon className="thumb-icon__image" size={32} />
                </div>
              </td>
              <td className="doc-list__name">
                <div className="doc-list__name-content">
                  <span className="doc-name__title">
                    <span className="doc-name__primary">
                      {isFolderEditing ? (
                        <span className="doc-title-edit">
                          <input
                            type="text"
                            ref={attachFolderInputRef}
                            value={folderDraftValue}
                            onChange={(event) => setFolderDraft(event.target.value)}
                            onClick={(event) => event.stopPropagation()}
                            onKeyDown={(event) => {
                              if (event.key === 'Enter') {
                                event.preventDefault();
                                submitFolderEditing(folder);
                              } else if (event.key === 'Escape') {
                                event.preventDefault();
                                cancelFolderEditing(event);
                              }
                            }}
                            onBlur={(event) => {
                              const nextFocus = event.relatedTarget;
                              if (!nextFocus || !event.currentTarget.parentElement?.contains(nextFocus)) {
                                cancelFolderEditing();
                              }
                            }}
                          />
                          <button
                            type="button"
                            className="icon-button"
                            aria-label="Save name"
                            title="Save name"
                            disabled={!canSubmitFolder || isFolderSaving}
                            onClick={(event) => {
                              event.stopPropagation();
                              submitFolderEditing(folder);
                            }}
                          >
                            <CheckIcon />
                          </button>
                          <button
                            type="button"
                            className="icon-button"
                            aria-label="Cancel"
                            title="Cancel"
                            onClick={(event) => {
                              cancelFolderEditing(event);
                            }}
                          >
                            <CloseIcon />
                          </button>
                        </span>
                      ) : (
                        <span
                          className="doc-name__primary-text"
                          role={allowInlineFolderEdit ? 'button' : undefined}
                          tabIndex={allowInlineFolderEdit ? 0 : undefined}
                          onClick={(event) => {
                            if (!allowInlineFolderEdit) {
                              return;
                            }
                            event.preventDefault();
                            event.stopPropagation();
                            beginFolderEditing(folder);
                          }}
                          onKeyDown={(event) => {
                            if (!allowInlineFolderEdit) {
                              return;
                            }
                            if (event.key === 'Enter') {
                              event.preventDefault();
                              event.stopPropagation();
                              beginFolderEditing(folder);
                            }
                          }}
                        >
                          {folder.name}
                        </span>
                      )}
                    </span>
                  </span>
                </div>
              </td>
              <td>—</td>
              <td>—</td>
            </tr>
          );
        }

        const doc = entry.document;
        if (!doc) {
          return null;
        }
        const isSelected = selectedDocumentIdsSet?.has(doc.id);
        const isDraggingDoc = draggingDocumentIdsSet?.has(doc.id);
        const rowClasses = ['document'];
        if (isSelected) rowClasses.push('selected');
        if (isDraggingDoc) rowClasses.push('is-dragging');
        const correspondents = resolveCorrespondents(doc);
        const isEditingDoc = editingDocumentId === doc.id;
        const documentDraftValue = isEditingDoc ? documentDraft : doc.title;
        const trimmedDocumentDraft = isEditingDoc ? documentDraft.trim() : '';
        const isDocumentSaving = savingDocumentId === doc.id;
        const canSubmitDocument =
          isEditingDoc && trimmedDocumentDraft.length > 0 && trimmedDocumentDraft !== doc.title;
        const allowInlineDocumentEdit =
          onDocumentRename && isSelected && totalSelectionCount === 1;
        const issuedLabel = formatDate(doc.issued_at);
        const addedLabel = formatDate(doc.created_at || doc.uploaded_at);
        return (
          <tr
            key={entry.key}
            className={rowClasses.join(' ')}
            id={`document-row-${doc.id}`}
            data-doc-id={doc.id}
            onClick={(event) => onDocumentClick?.(doc, event)}
            onDoubleClick={(event) => onDocumentActivate?.(doc, event)}
            draggable
            onDragStart={(event) => onDocumentDragStart?.(event, doc)}
            onDragEnd={(event) => onDocumentDragEnd?.(event)}
            onDragOver={onDocumentTagDragOver}
            onDragLeave={onDocumentTagDragLeave}
            onDrop={(event) => onDocumentTagDrop?.(event, doc.id)}
          >
            <td className="thumb-cell">
              <DocumentThumbnailImage
                document={doc}
                ensureAssetUrl={ensureAssetUrl}
                getDocumentAsset={getDocumentAsset}
                alt={`Thumbnail for ${doc.title}`}
                scrollRootRef={scrollRef}
              />
            </td>
            <td className="doc-list__name">
              <div className="doc-name">
                <div className="doc-list__name-content">
                  <span className="doc-name__title">
                    {correspondents.length > 0 ? (
                      <span className="doc-correspondents">
                        <CorrespondentLinks
                          correspondents={correspondents}
                          activeCorrespondentIdSet={activeCorrespondentIdSet}
                          onCorrespondentClick={onCorrespondentClick}
                        />
                      </span>
                    ) : null}
                    <span className="doc-name__primary">
                      {isEditingDoc ? (
                        <span className="doc-title-edit">
                          <input
                            type="text"
                            ref={attachDocumentInputRef}
                            value={documentDraftValue}
                            onChange={(event) => setDocumentDraft(event.target.value)}
                            onClick={(event) => event.stopPropagation()}
                          onKeyDown={(event) => {
                            if (event.key === 'Enter') {
                              event.preventDefault();
                              submitDocumentEditing(doc);
                            } else if (event.key === 'Escape') {
                              event.preventDefault();
                              cancelDocumentEditing(event);
                            }
                          }}
                          onBlur={(event) => {
                            const nextFocus = event.relatedTarget;
                            if (!nextFocus || !event.currentTarget.parentElement?.contains(nextFocus)) {
                              cancelDocumentEditing();
                            }
                          }}
                        />
                          <button
                            type="button"
                            className="icon-button"
                            aria-label="Save title"
                            title="Save title"
                            disabled={!canSubmitDocument || isDocumentSaving}
                            onClick={(event) => {
                              event.stopPropagation();
                              submitDocumentEditing(doc);
                            }}
                          >
                            <CheckIcon />
                          </button>
                          <button
                            type="button"
                            className="icon-button"
                            aria-label="Cancel"
                            title="Cancel"
                            onClick={(event) => {
                              cancelDocumentEditing(event);
                            }}
                          >
                            <CloseIcon />
                          </button>
                        </span>
                      ) : (
                        <span
                          className="doc-name__primary-text"
                          role={allowInlineDocumentEdit ? 'button' : undefined}
                          tabIndex={allowInlineDocumentEdit ? 0 : undefined}
                          onClick={(event) => {
                            if (!allowInlineDocumentEdit) {
                              return;
                            }
                            event.preventDefault();
                            event.stopPropagation();
                            beginDocumentEditing(doc);
                          }}
                          onKeyDown={(event) => {
                            if (!allowInlineDocumentEdit) {
                              return;
                            }
                            if (event.key === 'Enter') {
                              event.preventDefault();
                              event.stopPropagation();
                              beginDocumentEditing(doc);
                            }
                          }}
                        >
                          {doc.title}
                        </span>
                      )}
                    </span>
                  </span>
                </div>
                {(doc.tags || []).length > 0 && (
                  <div className="doc-name__tags">
                    {(doc.tags || []).map((tag) => {
                      const colorSource = tag?.color || tagLookupById?.get(tag.id)?.color;
                      const style = getTagColorStyle(colorSource);
                      return (
                        <span
                          key={tag.id}
                          className="badge tag-chip"
                          style={style || undefined}
                          title={tag.label}
                          role="button"
                          onClick={(event) => {
                            event.stopPropagation();
                            onTagClick?.(tag.id);
                          }}
                          draggable
                          onDragStart={(event) => {
                            event.stopPropagation();
                            try {
                              if (event.dataTransfer) {
                                event.dataTransfer.effectAllowed = 'copyMove';
                              }
                            } catch (error) {
                              console.warn('[documents] Failed to configure drag effect', error);
                            }
                            writeTagTransferData(event.dataTransfer, tag, doc.id);
                          }}
                          onDragEnd={(event) => {
                            event.stopPropagation();
                          }}
                          onKeyDown={(event) => {
                            if (event.key === 'Enter' || event.key === ' ') {
                              event.preventDefault();
                              event.stopPropagation();
                              onTagClick?.(tag.id);
                            }
                          }}
                        >
                          {tag.label}
                        </span>
                      );
                    })}
                  </div>
                )}
              </div>
            </td>
            <td>{issuedLabel}</td>
            <td>{addedLabel}</td>
          </tr>
        );
      })}
    </tbody>
  </table>
  );
};

export default DocumentsList;
