/**
 * FileExplorer - middle column file browser with multiple view modes.
 * Replaces FileGrid. Supports: list, table, icons-sm, icons-md, icons-lg.
 */

import React, { useMemo, useRef } from 'react';
import clsx from 'clsx';
import { useTranslation } from 'react-i18next';
import { useVirtualizer } from '@tanstack/react-virtual';
import type { DmsFile } from '@/api/dms';
import { Archive, ChevronDown, ChevronUp, Eye, FileText, Image, Loader2, Share2, Trash2 } from 'lucide-react';

export function getFileIcon(mimeType: string): { icon: React.ElementType; color: string } {
  if (mimeType === 'application/pdf') {
    return { icon: FileText, color: 'text-danger-500' };
  }
  if (mimeType.startsWith('image/')) {
    return { icon: Image, color: 'text-accent-500' };
  }
  if (mimeType.includes('spreadsheet') || mimeType.includes('excel')) {
    return { icon: FileText, color: 'text-success-500' };
  }
  if (mimeType.includes('presentation') || mimeType.includes('powerpoint')) {
    return { icon: FileText, color: 'text-warning-500' };
  }
  if (mimeType.startsWith('text/') || mimeType.includes('document') || mimeType.includes('word')) {
    return { icon: FileText, color: 'text-primary-500' };
  }
  if (mimeType.includes('zip') || mimeType.includes('compressed') || mimeType.includes('archive')) {
    return { icon: Archive, color: 'text-secondary-500' };
  }
  return { icon: FileText, color: 'text-secondary-400' };
}

export function formatFileSize(bytes: number): string {
  if (!bytes || bytes < 0) return '0 B';
  if (bytes < 1024) return `${bytes} B`;
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
  if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
  return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`;
}
import { formatDateShort } from '@/utils/date';


function getFileSize(file: DmsFile): number {
  return file.size_bytes ?? file.size ?? 0;
}

function formatDate(dateStr: string | null | undefined): string {
  if (!dateStr) return '';
  return formatDateShort(dateStr) || '';
}

export type ViewMode = 'list' | 'table' | 'icons-sm' | 'icons-md' | 'icons-lg';
export type SortBy = 'name' | 'size' | 'date' | 'type';
export type SortOrder = 'asc' | 'desc';

export interface FileExplorerProps {
  files: DmsFile[];
  selectedFileIds: Set<string>;
  selectedFile: DmsFile | null;
  viewMode: ViewMode;
  onToggleSelect: (fileId: string) => void;
  onFileClick: (file: DmsFile) => void;
  onFileDoubleClick: (file: DmsFile) => void;
  onFileShare: (file: DmsFile) => void;
  onFileDelete: (file: DmsFile) => void;
  onFilePreview: (file: DmsFile) => void;
  loading?: boolean;
  sortBy: SortBy;
  sortOrder: SortOrder;
  onSortChange: (by: string, order: string) => void;
  onRangeSelect?: (fileIds: string[]) => void;
}

function SortHeader({
  label,
  field,
  sortBy,
  sortOrder,
  onSortChange,
  className,
}: {
  label: string;
  field: SortBy;
  sortBy: SortBy;
  sortOrder: SortOrder;
  onSortChange: (by: string, order: string) => void;
  className?: string;
}) {
  const isActive = sortBy === field;
  return (
    <button
      type="button"
      onClick={() => onSortChange(field, isActive && sortOrder === 'asc' ? 'desc' : 'asc')}
      className={clsx(
        'inline-flex items-center gap-1 text-xs font-medium hover:text-secondary-700',
        isActive ? 'text-primary-600' : 'text-secondary-500',
        className,
      )}
    >
      {label}
      {isActive && (
        sortOrder === 'asc' ? <ChevronUp className="w-3 h-3" aria-hidden="true" strokeWidth={2} /> : <ChevronDown className="w-3 h-3" aria-hidden="true" strokeWidth={2} />
      )}
    </button>
  );
}

function ActionButtons({
  file,
  onFilePreview,
  onFileShare,
  onFileDelete,
  t,
}: {
  file: DmsFile;
  onFilePreview: (file: DmsFile) => void;
  onFileShare: (file: DmsFile) => void;
  onFileDelete: (file: DmsFile) => void;
  t: (key: string) => string;
}) {
  return (
    <div className="flex items-center gap-1">
      <button
        onClick={(e) => { e.stopPropagation(); onFilePreview(file); }}
        className="p-1.5 rounded text-secondary-400 hover:text-primary-600 hover:bg-primary-50 min-h-touch min-w-touch"
        aria-label={t('dms.preview')}
        title={t('dms.preview')}
      >
        <Eye className="w-4 h-4" aria-hidden="true" strokeWidth={2} />
      </button>
      <button
        onClick={(e) => { e.stopPropagation(); onFileShare(file); }}
        className="p-1.5 rounded text-secondary-400 hover:text-primary-600 hover:bg-primary-50 min-h-touch min-w-touch"
        aria-label={t('dms.share')}
        title={t('dms.share')}
      >
        <Share2 className="w-4 h-4" aria-hidden="true" strokeWidth={2} />
      </button>
      <button
        onClick={(e) => { e.stopPropagation(); onFileDelete(file); }}
        className="p-1.5 rounded text-secondary-400 hover:text-danger-600 hover:bg-danger-50 min-h-touch min-w-touch"
        aria-label={t('dms.delete')}
        title={t('dms.delete')}
      >
        <Trash2 className="w-4 h-4" aria-hidden="true" strokeWidth={2} />
      </button>
    </div>
  );
}

export function FileExplorer({
  files,
  selectedFileIds,
  selectedFile,
  viewMode,
  onToggleSelect,
  onFileClick,
  onFileDoubleClick,
  onFileShare,
  onFileDelete,
  onFilePreview,
  loading = false,
  sortBy,
  sortOrder,
  onSortChange,
}: FileExplorerProps) {
  const { t } = useTranslation();

  const sortedFiles = useMemo(() => {
    const sorted = [...files];
    sorted.sort((a, b) => {
      let cmp = 0;
      if (sortBy === 'name') {
        cmp = a.name.localeCompare(b.name);
      } else if (sortBy === 'size') {
        cmp = getFileSize(a) - getFileSize(b);
      } else if (sortBy === 'date') {
        cmp = (a.updated_at || a.created_at || '').localeCompare(b.updated_at || b.created_at || '');
      } else if (sortBy === 'type') {
        cmp = a.mime_type.localeCompare(b.mime_type);
      }
      return sortOrder === 'asc' ? cmp : -cmp;
    });
    return sorted;
  }, [files, sortBy, sortOrder]);

  const scrollRef = useRef<HTMLDivElement>(null);
  const shouldVirtualize = sortedFiles.length >= 50;

  const rowVirtualizer = useVirtualizer({
    count: shouldVirtualize ? sortedFiles.length : 0,
    getScrollElement: () => scrollRef.current,
    estimateSize: () => 44,
    overscan: 10,
    enabled: shouldVirtualize,
  });

  if (loading) {
    return (
      <div className="flex items-center justify-center py-12" data-testid="file-explorer-loading">
        <Loader2 className="animate-spin h-6 w-6 text-secondary-400" aria-hidden="true" />
        <span className="ml-2 text-secondary-500 text-sm">{t('dms.loading')}</span>
      </div>
    );
  }

  if (files.length === 0) {
    return (
      <div className="text-center py-12" data-testid="file-explorer-empty">
        <FileText className="mx-auto h-12 w-12 text-secondary-300" aria-hidden="true" strokeWidth={1.5} />
        <p className="mt-2 text-sm text-secondary-500">{t('dms.noFiles')}</p>
      </div>
    );
  }

  // ─── List View ───
  if (viewMode === 'list') {
    const renderFileRow = (file: DmsFile) => {
      const icon = getFileIcon(file.mime_type);
      const isSelected = selectedFileIds.has(file.id);
      const isActive = selectedFile?.id === file.id;
      return (
        <li key={file.id}>
          <div
            className={clsx(
              'flex items-center gap-2 px-3 py-2 cursor-pointer motion-safe:transition-colors',
              isActive ? 'bg-primary-50' : 'hover:bg-secondary-50',
            )}
            onClick={() => onFileClick(file)}
            onDoubleClick={() => onFileDoubleClick(file)}
            data-testid={`file-row-${file.id}`}
          >
            <input
              type="checkbox"
              checked={isSelected}
              onChange={() => onToggleSelect(file.id)}
              onClick={(e) => e.stopPropagation()}
              className="rounded border-secondary-300 text-primary-600 focus:ring-primary-500 flex-shrink-0"
              aria-label={t('dms.bulkSelect')}
            />
            <icon.icon className={clsx('w-5 h-5 flex-shrink-0', icon.color)} aria-hidden="true" strokeWidth={1.5} />
            <span className="text-sm font-medium text-secondary-900 truncate flex-1" title={file.name}>{file.name}</span>
            <span className="text-xs text-secondary-500 flex-shrink-0">{formatFileSize(getFileSize(file))}</span>
            <span className="text-xs text-secondary-400 flex-shrink-0 hidden sm:inline">{formatDate(file.updated_at || file.created_at)}</span>
            <ActionButtons file={file} onFilePreview={onFilePreview} onFileShare={onFileShare} onFileDelete={onFileDelete} t={t} />
          </div>
        </li>
      );
    };

    return (
      <div className="overflow-y-auto h-full" data-testid="file-explorer-list" ref={scrollRef}>
        {/* Sort header */}
        <div className="flex items-center gap-2 px-3 py-2 border-b border-secondary-100 sticky top-0 bg-white z-10">
          <SortHeader label={t('dms.sortName')} field="name" sortBy={sortBy} sortOrder={sortOrder} onSortChange={onSortChange} />
          <span className="text-secondary-300">|</span>
          <SortHeader label={t('dms.sortSize')} field="size" sortBy={sortBy} sortOrder={sortOrder} onSortChange={onSortChange} />
          <span className="text-secondary-300">|</span>
          <SortHeader label={t('dms.sortDate')} field="date" sortBy={sortBy} sortOrder={sortOrder} onSortChange={onSortChange} />
        </div>
        {shouldVirtualize ? (
          <ul className="divide-y divide-secondary-50" style={{ height: rowVirtualizer.getTotalSize(), position: 'relative' }}>
            {rowVirtualizer.getVirtualItems().map((virtualRow) => {
              const file = sortedFiles[virtualRow.index];
              return (
                <div
                  key={file.id}
                  style={{
                    position: 'absolute',
                    top: 0,
                    left: 0,
                    width: '100%',
                    transform: `translateY(${virtualRow.start}px)`,
                  }}
                >
                  {renderFileRow(file)}
                </div>
              );
            })}
          </ul>
        ) : (
          <ul className="divide-y divide-secondary-50">
            {sortedFiles.map((file) => renderFileRow(file))}
          </ul>
        )}
      </div>
    );
  }

  // ─── Table View ───
  if (viewMode === 'table') {
    const renderFileRow = (file: DmsFile) => {
      const icon = getFileIcon(file.mime_type);
      const isSelected = selectedFileIds.has(file.id);
      const isActive = selectedFile?.id === file.id;
      return (
        <tr
          key={file.id}
          className={clsx(
            'cursor-pointer motion-safe:transition-colors',
            isActive ? 'bg-primary-50' : 'hover:bg-secondary-50',
          )}
          onClick={() => onFileClick(file)}
          onDoubleClick={() => onFileDoubleClick(file)}
          data-testid={`file-row-${file.id}`}
        >
          <td className="px-3 py-2" onClick={(e) => e.stopPropagation()}>
            <input
              type="checkbox"
              checked={isSelected}
              onChange={() => onToggleSelect(file.id)}
              className="rounded border-secondary-300 text-primary-600 focus:ring-primary-500"
              aria-label={t('dms.bulkSelect')}
            />
          </td>
          <td className="px-3 py-2">
            <div className="flex items-center gap-2">
              <icon.icon className={clsx('w-5 h-5 flex-shrink-0', icon.color)} aria-hidden="true" strokeWidth={1.5} />
              <span className="font-medium text-secondary-900 truncate" title={file.name}>{file.name}</span>
            </div>
          </td>
          <td className="px-3 py-2 text-secondary-600">{formatFileSize(getFileSize(file))}</td>
          <td className="px-3 py-2 text-secondary-600">{file.mime_type.split('/')[1]?.toUpperCase() || t('dms.icon.other')}</td>
          <td className="px-3 py-2 text-secondary-600">{formatDate(file.updated_at || file.created_at)}</td>
          <td className="px-3 py-2" onClick={(e) => e.stopPropagation()}>
            <ActionButtons file={file} onFilePreview={onFilePreview} onFileShare={onFileShare} onFileDelete={onFileDelete} t={t} />
          </td>
        </tr>
      );
    };

    return (
      <div className="overflow-auto h-full" data-testid="file-explorer-table" ref={scrollRef} style={shouldVirtualize ? { maxHeight: '70vh', overflowY: 'auto' } : undefined}>
        <table className="w-full text-sm">
          <thead className="sticky top-0 bg-white border-b border-secondary-200 z-10">
            <tr>
              <th className="px-3 py-2 w-8">
                <input
                  type="checkbox"
                  className="rounded border-secondary-300 text-primary-600 focus:ring-primary-500"
                  aria-label={t('dms.bulkSelect')}
                  onChange={() => {}}
                />
              </th>
              <th className="px-3 py-2 text-left">
                <SortHeader label={t('dms.sortName')} field="name" sortBy={sortBy} sortOrder={sortOrder} onSortChange={onSortChange} />
              </th>
              <th className="px-3 py-2 text-left">
                <SortHeader label={t('dms.fileSize')} field="size" sortBy={sortBy} sortOrder={sortOrder} onSortChange={onSortChange} />
              </th>
              <th className="px-3 py-2 text-left">
                <SortHeader label={t('dms.fileType')} field="type" sortBy={sortBy} sortOrder={sortOrder} onSortChange={onSortChange} />
              </th>
              <th className="px-3 py-2 text-left">
                <SortHeader label={t('dms.fileModified')} field="date" sortBy={sortBy} sortOrder={sortOrder} onSortChange={onSortChange} />
              </th>
              <th className="px-3 py-2 text-right">{t('common.actions')}</th>
            </tr>
          </thead>
          <tbody className="divide-y divide-secondary-50">
            {shouldVirtualize ? (
              <>
                {rowVirtualizer.getVirtualItems().map((virtualRow, idx) => {
                  const file = sortedFiles[virtualRow.index];
                  return (
                    <React.Fragment key={file.id}>
                      {idx === 0 && virtualRow.start > 0 && (
                        <tr style={{ height: virtualRow.start }}>
                          <td colSpan={6} style={{ padding: 0, border: 'none' }} />
                        </tr>
                      )}
                      {renderFileRow(file)}
                      {idx === rowVirtualizer.getVirtualItems().length - 1 && (
                        <tr style={{ height: rowVirtualizer.getTotalSize() - virtualRow.end }}>
                          <td colSpan={6} style={{ padding: 0, border: 'none' }} />
                        </tr>
                      )}
                    </React.Fragment>
                  );
                })}
              </>
            ) : (
              sortedFiles.map((file) => renderFileRow(file))
            )}
          </tbody>
        </table>
      </div>
    );
  }

  // ─── Icon Views ───
  const minColWidth =
    viewMode === 'icons-sm' ? '80px'
      : viewMode === 'icons-md' ? '120px'
        : '180px';

  const iconSize =
    viewMode === 'icons-sm' ? 'w-6 h-6'
      : viewMode === 'icons-md' ? 'w-8 h-8'
        : 'w-16 h-16';

  const isSmall = viewMode === 'icons-sm';

  return (
    <div
      className="grid gap-1.5 p-2 overflow-y-auto h-full items-start content-start"
      style={{ gridTemplateColumns: `repeat(auto-fill, minmax(${minColWidth}, 1fr))` }}
      data-testid={`file-explorer-${viewMode}`}
    >
      {sortedFiles.map((file) => {
        const icon = getFileIcon(file.mime_type);
        const isSelected = selectedFileIds.has(file.id);
        const isActive = selectedFile?.id === file.id;
        return (
          <div
            key={file.id}
            className={clsx(
              isSmall
                ? clsx(
                    'rounded p-1.5 motion-safe:transition-all cursor-pointer flex flex-col items-center text-center overflow-hidden',
                    isActive ? 'bg-primary-50' : isSelected ? 'bg-primary-50/50' : 'hover:bg-secondary-50',
                  )
                : clsx(
                    'rounded-lg border p-2 motion-safe:transition-all cursor-pointer flex flex-col items-center text-center overflow-hidden',
                    isActive
                      ? 'border-primary-500 ring-1 ring-primary-200'
                      : isSelected
                        ? 'border-primary-400'
                        : 'border-secondary-200 hover:border-secondary-300 hover:shadow-sm',
                  ),
            )}
            onClick={() => onFileClick(file)}
            onDoubleClick={() => onFileDoubleClick(file)}
            data-testid={`file-card-${file.id}`}
          >
            <div className={clsx('flex items-center w-full', isSmall ? 'mb-0.5 justify-center' : 'mb-1.5 justify-between')}>
              <input
                type="checkbox"
                checked={isSelected}
                onChange={() => onToggleSelect(file.id)}
                onClick={(e) => e.stopPropagation()}
                className="rounded border-secondary-300 text-primary-600 focus:ring-primary-500"
                aria-label={t('dms.bulkSelect')}
              />
            </div>
            {viewMode === 'icons-lg' && file.mime_type.startsWith('image/') ? (
              <div className="w-16 h-16 bg-secondary-100 rounded-lg flex items-center justify-center mb-2 overflow-hidden">
                <img
                  src={`/api/v1/dms/files/${file.id}/preview`}
                  alt={file.name}
                  className="w-full h-full object-cover"
                  onError={(e) => {
                    (e.target as HTMLImageElement).style.display = 'none';
                  }}
                />
              </div>
            ) : (
              <icon.icon className={clsx(iconSize, icon.color, isSmall ? 'mb-0.5' : 'mb-1')} aria-hidden="true" strokeWidth={1.5} />
            )}
            <p className={clsx('font-medium text-secondary-900 truncate w-full', isSmall ? 'text-[10px]' : 'text-xs')} title={file.name}>{file.name}</p>
            {!isSmall && (
              <div className="mt-0.5 flex items-center gap-2 text-xs text-secondary-500">
                <span>{formatFileSize(getFileSize(file))}</span>
              </div>
            )}
            {!isSmall && (
              <div className="mt-1.5">
                <ActionButtons file={file} onFilePreview={onFilePreview} onFileShare={onFileShare} onFileDelete={onFileDelete} t={t} />
              </div>
            )}
          </div>
        );
      })}
    </div>
  );
}
