/**
 * DMS file browser page — complete redesign.
 * 3-column explorer-style layout: SourceTree | FileExplorer | FileDetails.
 * Uses PluginToolbar for actions, ResizablePanel for desktop layout.
 * Supports drag-and-drop: files→folders, folders→folders (reparent), files→root.
 */

import React, { useState, useEffect, useCallback, useRef } from 'react';
import { useTranslation } from 'react-i18next';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
import { Link } from 'react-router-dom';
import { Button } from '@/components/ui/Button';
import { Input } from '@/components/ui/Input';
import { ConfirmDialog } from '@/components/ui/ConfirmDialog';
import { useToast } from '@/components/ui/Toast';
import { ResizablePanel } from '@/components/ui/ResizablePanel';
import { SourceTree } from '@/components/dms/SourceTree';
import { FileExplorer, type ViewMode, type SortBy, type SortOrder } from '@/components/dms/FileExplorer';
import { FileDetails } from '@/components/dms/FileDetails';
import { UploadDropzone } from '@/components/dms/UploadDropzone';
import { FilePreviewModal } from '@/components/dms/FilePreviewModal';
import { ShareDialog } from '@/components/dms/ShareDialog';
import { BulkActions } from '@/components/dms/BulkActions';
import { usePluginToolbarStore } from '@/store/pluginToolbarStore';
import { ArrowRight, ChevronLeft, ChevronRight, Info, Plus, Trash2, Upload } from 'lucide-react';
import {
  fetchFolders,
  createFolder,
  deleteFile,
  searchFiles,
  fetchFilesByFolder,
  fetchAllFiles,
  getSharedWithMe,
  bulkMoveFiles,
  bulkDeleteFiles,
  updateFolder,
  type DmsFolder,
  type DmsFile,
} from '@/api/dms';

export function DmsPage() {
  const { t } = useTranslation();
  const toast = useToast();

  // Data state
  const [folders, setFolders] = useState<DmsFolder[]>([]);
  const [files, setFiles] = useState<DmsFile[]>([]);
  const [sharedFiles, setSharedFiles] = useState<DmsFile[]>([]);
  const [loadingFolders, setLoadingFolders] = useState(true);
  const [loadingFiles, setLoadingFiles] = useState(false);
  const [error, setError] = useState<string | null>(null);

  // Navigation state
  const [selectedFolderId, setSelectedFolderId] = useState<string | null>(null);
  const [selectedSource, setSelectedSource] = useState<string | null>('local');

  // Selection state
  const [selectedFileIds, setSelectedFileIds] = useState<Set<string>>(new Set());
  const [selectedFile, setSelectedFile] = useState<DmsFile | null>(null);

  // Search state
  const [searchQuery, setSearchQuery] = useState('');

  // View state
  const [viewMode, setViewMode] = useState<ViewMode>('icons-md');
  const [showDetails, setShowDetails] = useState(false);
  const [sortBy, setSortBy] = useState<SortBy>('name');
  const [sortOrder, setSortOrder] = useState<SortOrder>('asc');

  // Modal state
  const [showUpload, setShowUpload] = useState(false);
  const [showNewFolder, setShowNewFolder] = useState(false);
  const [previewFile, setPreviewFile] = useState<DmsFile | null>(null);
  const [shareFile, setShareFile] = useState<DmsFile | null>(null);
  const [deleteTarget, setDeleteTarget] = useState<DmsFile | null>(null);
  const [submittingFolder, setSubmittingFolder] = useState(false);
  const [showBulkMove, setShowBulkMove] = useState(false);
  const [bulkMoveTarget, setBulkMoveTarget] = useState<string>('');

  // ── Folder create form (RHF + Zod) ──
  const folderSchema = z.object({
    name: z.string().min(1, 'required'),
  });
  type FolderFormData = z.infer<typeof folderSchema>;

  const { register: registerFolder, handleSubmit: handleSubmitFolder, reset: resetFolder, formState: { errors: folderErrors } } = useForm<FolderFormData>({
    resolver: zodResolver(folderSchema),
    defaultValues: { name: '' },
  });

  // Mobile view state
  const [activeView, setActiveView] = useState<'tree' | 'files' | 'details'>('tree');

  // Ref for race condition prevention
  const currentLoadId = useRef<string>('');

  // Load folders
  const loadFolders = useCallback(async () => {
    setLoadingFolders(true);
    try {
      const folderList = await fetchFolders();
      setFolders(folderList);
    } catch (err) {
      const msg = err instanceof Error ? err.message : String(err);
      setError(msg);
    }
    setLoadingFolders(false);
  }, []);

  // Load shared files
  const loadSharedFiles = useCallback(async () => {
    try {
      const shared = await getSharedWithMe();
      setSharedFiles(shared);
    } catch {
      setSharedFiles([]);
    }
  }, []);

  useEffect(() => {
    loadFolders();
    loadSharedFiles();
  }, [loadFolders, loadSharedFiles]);

  // Load files based on current selection
  const loadFiles = useCallback(async () => {
    const loadId = `${selectedSource}-${selectedFolderId}-${searchQuery}`;
    currentLoadId.current = loadId;
    setLoadingFiles(true);
    try {
      let result: DmsFile[] = [];
      if (searchQuery.trim()) {
        const searchResult = await searchFiles(searchQuery);
        result = searchResult.files;
      } else if (selectedSource === 'shared') {
        result = await getSharedWithMe();
      } else if (selectedFolderId) {
        result = await fetchFilesByFolder(selectedFolderId);
      } else {
        result = await fetchAllFiles();
      }
      if (currentLoadId.current === loadId) {
        setFiles(result);
      }
    } catch (err) {
      const msg = err instanceof Error ? err.message : String(err);
      if (currentLoadId.current === loadId) {
        setError(msg);
        setFiles([]);
      }
    }
    if (currentLoadId.current === loadId) {
      setLoadingFiles(false);
    }
  }, [selectedSource, selectedFolderId, searchQuery]);

  useEffect(() => {
    const debounce = setTimeout(() => {
      loadFiles();
    }, 300);
    return () => clearTimeout(debounce);
  }, [loadFiles]);

  // Handle folder selection
  const handleSelectFolder = useCallback((folderId: string | null) => {
    setSelectedFolderId(folderId);
    setSelectedSource('local');
    setSearchQuery('');
    setSelectedFile(null);
    setSelectedFileIds(new Set());
    setActiveView('files');
  }, []);

  // Handle source selection
  const handleSelectSource = useCallback((source: string) => {
    setSelectedSource(source);
    if (source !== 'local') {
      setSelectedFolderId(null);
    }
    setSearchQuery('');
    setSelectedFile(null);
    setSelectedFileIds(new Set());
    setActiveView('files');
  }, []);

  // Handle file click (select for details)
  const handleFileClick = useCallback((file: DmsFile) => {
    setSelectedFile(file);
    if (showDetails) {
      setActiveView('details');
    }
  }, [showDetails]);

  // Handle file double click (open preview)
  const handleFileDoubleClick = useCallback((file: DmsFile) => {
    setPreviewFile(file);
  }, []);

  // Handle file share
  const handleFileShare = useCallback((file: DmsFile) => {
    setShareFile(file);
  }, []);

  // Handle file delete
  const handleFileDelete = useCallback((file: DmsFile) => {
    setDeleteTarget(file);
  }, []);

  // Handle file preview
  const handleFilePreview = useCallback((file: DmsFile) => {
    setPreviewFile(file);
  }, []);

  // Handle toggle select
  const handleToggleSelect = useCallback((fileId: string) => {
    setSelectedFileIds((prev) => {
      const next = new Set(prev);
      if (next.has(fileId)) {
        next.delete(fileId);
      } else {
        next.add(fileId);
      }
      return next;
    });
  }, []);

  // Handle range select (Shift+Click or rubber-band)
  const handleRangeSelect = useCallback((fileIds: string[]) => {
    setSelectedFileIds(new Set(fileIds));
  }, []);

  // Handle confirm delete
  const handleConfirmDelete = useCallback(async () => {
    if (!deleteTarget) return;
    try {
      await deleteFile(deleteTarget.id);
      toast.success(t('dms.deleted'));
      setFiles((prev) => prev.filter((f) => f.id !== deleteTarget.id));
      if (selectedFile?.id === deleteTarget.id) {
        setSelectedFile(null);
      }
      setDeleteTarget(null);
    } catch (err) {
      const msg = err instanceof Error ? err.message : String(err);
      toast.error(msg);
    }
  }, [deleteTarget, selectedFile, toast, t]);

  // Handle create folder
  const handleCreateFolder = useCallback(async (data: FolderFormData) => {
    setSubmittingFolder(true);
    try {
      const folder = await createFolder({
        name: data.name.trim(),
        parent_id: selectedFolderId,
      });
      setFolders((prev) => [...prev, folder]);
      resetFolder({ name: '' });
      setShowNewFolder(false);
      toast.success(t('dms.createFolder'));
    } catch (err) {
      const msg = err instanceof Error ? err.message : String(err);
      toast.error(msg);
    }
    setSubmittingFolder(false);
  }, [selectedFolderId, toast, t, resetFolder]);

  // Handle upload complete
  const handleUploadComplete = useCallback(() => {
    loadFiles();
  }, [loadFiles]);

  // Handle clear selection
  const handleClearSelection = useCallback(() => {
    setSelectedFileIds(new Set());
  }, []);

  // Handle sort change
  const handleSortChange = useCallback((by: string, order: string) => {
    setSortBy(by as SortBy);
    setSortOrder(order as SortOrder);
  }, []);

  // Handle bulk delete
  const handleBulkDelete = useCallback(async () => {
    const fileIds = Array.from(selectedFileIds);
    try {
      await bulkDeleteFiles({ file_ids: fileIds });
      toast.success(t('dms.deleted'));
      setFiles((prev) => prev.filter((f) => !selectedFileIds.has(f.id)));
      setSelectedFileIds(new Set());
    } catch (err) {
      const msg = err instanceof Error ? err.message : String(err);
      toast.error(msg);
    }
  }, [selectedFileIds, toast, t]);

  // Handle bulk move
  const handleBulkMove = useCallback(async () => {
    const fileIds = Array.from(selectedFileIds);
    try {
      await bulkMoveFiles({
        file_ids: fileIds,
        target_folder_id: bulkMoveTarget || null,
      });
      toast.success(t('dms.bulkMove'));
      setFiles((prev) => prev.filter((f) => !selectedFileIds.has(f.id)));
      setSelectedFileIds(new Set());
      setShowBulkMove(false);
      setBulkMoveTarget('');
    } catch (err) {
      const msg = err instanceof Error ? err.message : String(err);
      toast.error(msg);
    }
  }, [selectedFileIds, bulkMoveTarget, toast, t]);

  // Handle search
  const handleSearch = useCallback((query: string) => {
    setSearchQuery(query);
    setSelectedFolderId(null);
    setSelectedSource('local');
  }, []);

  // ─── Drag-and-drop handlers ───

  // Handle files dropped onto a folder (or root when targetFolderId is null)
  const handleDropFiles = useCallback(async (fileIds: string[], targetFolderId: string | null) => {
    if (fileIds.length === 0) return;
    try {
      await bulkMoveFiles({
        file_ids: fileIds,
        target_folder_id: targetFolderId,
      });
      toast.success(
        targetFolderId
          ? t('dms.filesMoved')
          : t('dms.filesMovedRoot')
      );
      // Remove moved files from current view (unless we're in the target folder)
      if (selectedFolderId !== targetFolderId) {
        setFiles((prev) => prev.filter((f) => !fileIds.includes(f.id)));
      }
      // Reload folders to update file counts
      loadFolders();
      // If dropping into a folder, navigate to it
      if (targetFolderId) {
        setSelectedFolderId(targetFolderId);
        setSelectedSource('local');
        setSearchQuery('');
        setSelectedFileIds(new Set());
      }
    } catch (err) {
      const msg = err instanceof Error ? err.message : String(err);
      toast.error(msg);
    }
  }, [selectedFolderId, toast, t, loadFolders]);

  // Handle folder dropped onto another folder (reparent) or root
  const handleDropFolder = useCallback(async (sourceFolderId: string, targetFolderId: string | null) => {
    if (sourceFolderId === targetFolderId) return;
    try {
      await updateFolder(sourceFolderId, { parent_id: targetFolderId });
      toast.success(t('dms.folderMoved'));
      loadFolders();
    } catch (err) {
      const msg = err instanceof Error ? err.message : String(err);
      toast.error(msg);
    }
  }, [toast, t, loadFolders]);

  // Register toolbar items
  const registerItems = usePluginToolbarStore((s) => s.registerItems);
  const unregisterPlugin = usePluginToolbarStore((s) => s.unregisterPlugin);
  const hasBulkSelection = selectedFileIds.size > 0;

  useEffect(() => {
    const items = [
      // File actions group
      {
        id: 'new-folder',
        plugin: 'dms',
        label: t('dms.newFolder'),
        group: 'file-actions',
        icon: (
          <Plus className="w-3.5 h-3.5" strokeWidth={2} />
        ),
        onClick: () => setShowNewFolder((v) => !v),
      },
      {
        id: 'upload',
        plugin: 'dms',
        label: t('dms.upload'),
        group: 'file-actions',
        icon: (
          <Upload className="w-3.5 h-3.5" strokeWidth={2} />
        ),
        onClick: () => setShowUpload((v) => !v),
      },
      // View modes group
      {
        id: 'view-mode',
        plugin: 'dms',
        label: t('dms.viewList'),
        group: 'view-modes',
        type: 'select' as const,
        selectValue: viewMode,
        selectOptions: [
          { value: 'list', label: t('dms.viewList') },
          { value: 'table', label: t('dms.viewTable') },
          { value: 'icons-sm', label: t('dms.viewIconsSm') },
          { value: 'icons-md', label: t('dms.viewIconsMd') },
          { value: 'icons-lg', label: t('dms.viewIconsLg') },
        ],
        onSelect: (value: string) => setViewMode(value as ViewMode),
        onClick: () => {},
      },
      // Search group
      {
        id: 'search',
        plugin: 'dms',
        label: t('dms.search'),
        type: 'search' as const,
        group: 'search',
        searchPlaceholder: t('dms.searchPlaceholder'),
        onSearch: handleSearch,
        onClick: () => {},
      },
      // Details toggle group
      {
        id: 'toggle-details',
        plugin: 'dms',
        label: t('dms.toggleDetails'),
        group: 'details',
        active: showDetails,
        icon: (
          <Info className="w-3.5 h-3.5" strokeWidth={2} />
        ),
        onClick: () => setShowDetails((v) => !v),
      },
    ];

    // Add bulk actions when files are selected
    if (hasBulkSelection) {
      items.push(
        {
          id: 'bulk-move',
          plugin: 'dms',
          label: t('dms.bulkMove'),
          group: 'bulk-actions',
          icon: (
            <ArrowRight className="w-3.5 h-3.5" strokeWidth={2} />
          ),
          onClick: () => setShowBulkMove(true),
        },
        {
          id: 'bulk-delete',
          plugin: 'dms',
          label: t('dms.bulkDelete'),
          group: 'bulk-actions',
          icon: (
            <Trash2 className="w-3.5 h-3.5" strokeWidth={2} />
          ),
          onClick: handleBulkDelete,
        },
      );
    }

    registerItems('dms', items);
    return () => unregisterPlugin('dms');
  }, [viewMode, showDetails, hasBulkSelection, handleSearch, handleBulkDelete, t]);

  return (
    <div className="flex flex-col h-full" data-testid="dms-page">
      {error && (
        <div className="mb-2 p-3 bg-danger-50 border border-danger-200 rounded-md" role="alert" data-testid="dms-error">
          <p className="text-sm text-danger-700">{error}</p>
        </div>
      )}

      {/* New folder form */}
      {showNewFolder && (
        <form onSubmit={handleSubmitFolder(handleCreateFolder)} className="mb-2 p-3 bg-secondary-50 border-b border-secondary-200" data-testid="new-folder-form">
          <div className="flex items-center gap-3 max-w-md">
            <Input
              label={t('dms.folderName')}
              {...registerFolder('name')}
              error={folderErrors.name?.message === 'required' ? t('validation.required') : undefined}
              placeholder={t('dms.folderName')}
            />
            <Button size="sm" type="submit" isLoading={submittingFolder}>
              {t('dms.createFolder')}
            </Button>
            <Button variant="secondary" size="sm" type="button" onClick={() => { setShowNewFolder(false); resetFolder({ name: '' }); }}>
              {t('dms.cancel')}
            </Button>
          </div>
        </form>
      )}

      {/* Upload dropzone */}
      {showUpload && (
        <div className="mb-2 p-3 bg-secondary-50 border-b border-secondary-200" data-testid="upload-section">
          <UploadDropzone folderId={selectedFolderId} onUploaded={handleUploadComplete} />
        </div>
      )}

      {/* Desktop: three-pane layout with resizable panels */}
      <div className="hidden md:flex flex-1 overflow-hidden">
        {/* Left: SourceTree */}
        <ResizablePanel
          initialWidth={240}
          minWidth={180}
          maxWidth={400}
          className="border-r border-secondary-200 bg-white"
          data-testid="dms-source-pane"
        >
          <SourceTree
            folders={folders}
            sharedFiles={sharedFiles}
            selectedFolderId={selectedFolderId}
            selectedSource={selectedSource}
            onSelectFolder={handleSelectFolder}
            onSelectSource={handleSelectSource}
            loading={loadingFolders}
            onDropFiles={handleDropFiles}
            onDropFolder={handleDropFolder}
          />
        </ResizablePanel>

        {/* Middle: FileExplorer */}
        <ResizablePanel
          resizable={false}
          className="bg-white"
          data-testid="dms-explorer-pane"
        >
          <FileExplorer
            files={files}
            selectedFileIds={selectedFileIds}
            selectedFile={selectedFile}
            viewMode={viewMode}
            onToggleSelect={handleToggleSelect}
            onFileClick={handleFileClick}
            onFileDoubleClick={handleFileDoubleClick}
            onFileShare={handleFileShare}
            onFileDelete={handleFileDelete}
            onFilePreview={handleFilePreview}
            loading={loadingFiles}
            sortBy={sortBy}
            sortOrder={sortOrder}
            onSortChange={handleSortChange}
            onRangeSelect={handleRangeSelect}
          />
        </ResizablePanel>

        {/* Right: FileDetails (only when toggled on) */}
        {showDetails && (
          <ResizablePanel
            initialWidth={280}
            minWidth={200}
            maxWidth={400}
            handleSide="left"
            className="border-l border-secondary-200 bg-white"
            data-testid="dms-details-pane"
          >
            <FileDetails
              file={selectedFile}
              onPreview={handleFilePreview}
              onShare={handleFileShare}
              onDelete={handleFileDelete}
              onClose={() => setShowDetails(false)}
            />
          </ResizablePanel>
        )}
      </div>

      {/* Mobile: single-pane view switching */}
      <div className="flex md:hidden flex-1 overflow-hidden flex-col">
        {/* View 1: SourceTree */}
        {activeView === 'tree' && (
          <div className="flex-1 overflow-y-auto bg-white" data-testid="mobile-source-pane">
            <div className="flex items-center gap-2 px-3 py-2 border-b border-secondary-200 sticky top-0 bg-white z-10">
              <h2 className="text-sm font-semibold text-secondary-900">{t('dms.title')}</h2>
              <Link to="/dms/trash" className="ml-auto text-xs text-primary-600 hover:text-primary-700">
                {t('dms.trash')}
              </Link>
            </div>
            <SourceTree
              folders={folders}
              sharedFiles={sharedFiles}
              selectedFolderId={selectedFolderId}
              selectedSource={selectedSource}
              onSelectFolder={handleSelectFolder}
              onSelectSource={handleSelectSource}
              loading={loadingFolders}
              onDropFiles={handleDropFiles}
              onDropFolder={handleDropFolder}
            />
          </div>
        )}

        {/* View 2: FileExplorer */}
        {activeView === 'files' && (
          <div className="flex-1 overflow-y-auto bg-white" data-testid="mobile-explorer-pane">
            <div className="flex items-center gap-2 px-3 py-2 border-b border-secondary-200 sticky top-0 bg-white z-10">
              <button
                onClick={() => setActiveView('tree')}
                className="inline-flex items-center gap-1 px-2 py-1 rounded text-sm text-secondary-700 hover:bg-secondary-100 min-h-touch"
                aria-label={t('common.back')}
                data-testid="mobile-back-to-tree"
              >
                <ChevronLeft className="w-4 h-4" aria-hidden="true" strokeWidth={2} />
                <span className="text-sm font-medium">{t('dms.sources')}</span>
              </button>
              {showDetails && (
                <button
                  onClick={() => setActiveView('details')}
                  className="ml-auto inline-flex items-center gap-1 px-2 py-1 rounded text-sm text-secondary-700 hover:bg-secondary-100 min-h-touch"
                  aria-label={t('dms.details')}
                  data-testid="mobile-go-to-details"
                >
                  <span className="text-sm font-medium">{t('dms.details')}</span>
                  <ChevronRight className="w-4 h-4" aria-hidden="true" strokeWidth={2} />
                </button>
              )}
            </div>
            <FileExplorer
              files={files}
              selectedFileIds={selectedFileIds}
              selectedFile={selectedFile}
              viewMode={viewMode}
              onToggleSelect={handleToggleSelect}
              onFileClick={handleFileClick}
              onFileDoubleClick={handleFileDoubleClick}
              onFileShare={handleFileShare}
              onFileDelete={handleFileDelete}
              onFilePreview={handleFilePreview}
              loading={loadingFiles}
              sortBy={sortBy}
              sortOrder={sortOrder}
              onSortChange={handleSortChange}
              onRangeSelect={handleRangeSelect}
            />
          </div>
        )}

        {/* View 3: FileDetails */}
        {activeView === 'details' && showDetails && (
          <div className="flex-1 overflow-y-auto bg-white" data-testid="mobile-details-pane">
            <div className="flex items-center gap-2 px-3 py-2 border-b border-secondary-200 sticky top-0 bg-white z-10">
              <button
                onClick={() => setActiveView('files')}
                className="inline-flex items-center gap-1 px-2 py-1 rounded text-sm text-secondary-700 hover:bg-secondary-100 min-h-touch"
                aria-label={t('common.back')}
                data-testid="mobile-back-to-files"
              >
                <ChevronLeft className="w-4 h-4" aria-hidden="true" strokeWidth={2} />
                <span className="text-sm font-medium">{t('dms.files')}</span>
              </button>
            </div>
            <FileDetails
              file={selectedFile}
              onPreview={handleFilePreview}
              onShare={handleFileShare}
              onDelete={handleFileDelete}
              onClose={() => {
                setShowDetails(false);
                setActiveView('files');
              }}
            />
          </div>
        )}
      </div>

      {/* Floating bulk action bar */}
      {hasBulkSelection && (
        <BulkActions
          selectedFileIds={selectedFileIds}
          folders={folders}
          onClear={handleClearSelection}
          onActionComplete={loadFiles}
        />
      )}

      {/* Bulk move dialog */}
      {showBulkMove && (
        <ConfirmDialog
          open={showBulkMove}
          title={t('dms.bulkMoveTitle')}
          message={t('dms.selectTargetFolder')}
          confirmLabel={t('dms.bulkMove')}
          onConfirm={handleBulkMove}
          onCancel={() => { setShowBulkMove(false); setBulkMoveTarget(''); }}
        />
      )}

      {/* Delete confirmation */}
      <ConfirmDialog
        open={!!deleteTarget}
        title={t('dms.delete')}
        message={t('dms.confirmDelete')}
        confirmLabel={t('dms.delete')}
        variant="danger"
        onConfirm={handleConfirmDelete}
        onCancel={() => setDeleteTarget(null)}
      />

      {/* File preview modal */}
      <FilePreviewModal
        open={!!previewFile}
        file={previewFile}
        onClose={() => setPreviewFile(null)}
      />

      {/* Share dialog */}
      <ShareDialog
        open={!!shareFile}
        file={shareFile}
        onClose={() => setShareFile(null)}
        onShared={() => loadFiles()}
      />
    </div>
  );
}
