"use client";
import {
  ChevronDownIcon,
  ChevronRightIcon,
  TrashIcon
} from "@heroicons/react/24/outline";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { useEffect, useMemo, useState } from "react";
import toast from "react-hot-toast";
import { del, get, post } from "../../lib/api";
import ConfirmationDialog from "../components/ConfirmationDialog";
import FileCrud from "../components/FileCrud";
import LoadingCard from "../components/Loading";
import { useNotifications } from "../components/NotificationContext";
import Pagination from "../components/Pagination";

export default function FileList() {
  const queryClient = useQueryClient();
  const { addNotification } = useNotifications();

  // Get available datasets
  const { data: datasets } = useQuery({
    queryKey: ["datasets"],
    queryFn: () => get(`/files/all-datasets`)
  });

  // Get files from all datasets
  const {
    data: allFiles,
    isLoading,
    error
  } = useQuery({
    queryKey: ["all-files"],
    queryFn: async () => {
      if (!datasets) return [];
      const allFilesPromises = datasets.map((datasetName: string) =>
        get(`/files/${datasetName}`).catch(() => [])
      );
      const results = await Promise.all(allFilesPromises);
      return results.flat().map((file: any) => ({
        ...file
      }));
    },
    enabled: !!datasets
  });

  // State for filters and search
  const [enabledDatasets, setEnabledDatasets] = useState<Set<string>>(
    new Set()
  );
  const [searchTerm, setSearchTerm] = useState("");
  const [sortField, setSortField] = useState<"input" | "date">("date");
  const [sortDirection, setSortDirection] = useState<"asc" | "desc">("desc");

  // Pagination state
  const [currentPage, setCurrentPage] = useState(1);
  const [pageSize, setPageSize] = useState(25);

  // Initialize enabled datasets when datasets are loaded
  useEffect(() => {
    if (datasets && enabledDatasets.size === 0) {
      const datasetNames = datasets
        .map((path: string) => path.split("/").pop())
        .filter(Boolean);
      setEnabledDatasets(new Set(datasetNames));
    }
  }, [datasets, enabledDatasets.size]);

  // Listen for WebSocket events
  useEffect(() => {
    const handleFileUpdate = (event: CustomEvent) => {
      const fileData = event.detail;
      // Refetch files when file updates occur
      queryClient.refetchQueries({ queryKey: ["all-files"] });
    };

    const handleTaskUpdate = (event: CustomEvent) => {
      const taskData = event.detail;
      // Refetch files when task updates occur (e.g., requeue processing)
      if (taskData.task === "handbrake") {
        queryClient.refetchQueries({ queryKey: ["all-files"] });
      }
    };

    window.addEventListener("fileUpdate", handleFileUpdate as EventListener);
    window.addEventListener("taskUpdate", handleTaskUpdate as EventListener);

    return () => {
      window.removeEventListener(
        "fileUpdate",
        handleFileUpdate as EventListener
      );
      window.removeEventListener(
        "taskUpdate",
        handleTaskUpdate as EventListener
      );
    };
  }, [queryClient]);

  const [editFile, setEditFile] = useState<any>(null);

  // Confirmation dialog state
  const [deleteConfirm, setDeleteConfirm] = useState<{
    isOpen: boolean;
    file?: any;
    isBatch?: boolean;
    selectedFiles?: any[];
  }>({
    isOpen: false
  });

  // Batch selection state
  const [selectedFiles, setSelectedFiles] = useState<Set<string>>(new Set());

  // Expanded rows state
  const [expandedRows, setExpandedRows] = useState<Set<string>>(new Set());

  // Dropdown state
  const [openDropdown, setOpenDropdown] = useState<string | null>(null);

  const deleteMutation = useMutation({
    mutationFn: async (params: { file?: string; files?: any[] }) => {
      if (params.files && params.files.length > 0) {
        // Batch delete
        const deletePromises = params.files.map((file) =>
          del(`/files/${file.dataset}/${encodeURIComponent(file.input)}`)
        );
        await Promise.all(deletePromises);
        return params.files;
      } else if (params.file) {
        // Single delete
        const fileData = deleteConfirm.file;
        return del(
          `/files/${fileData?.dataset || "pr0n"}/${encodeURIComponent(params.file)}`
        );
      }
    },
    onSuccess: (result, params) => {
      queryClient.refetchQueries({ queryKey: ["all-files"] });
      setSelectedFiles(new Set()); // Clear selections after delete

      if (params.files && params.files.length > 0) {
        toast.success(`${params.files.length} files deleted successfully`);
        addNotification({
          type: "success",
          title: "Files Deleted",
          message: `${params.files.length} files have been deleted successfully.`
        });
      } else {
        toast.success("File deleted successfully");
        addNotification({
          type: "success",
          title: "File Deleted",
          message: `File "${params.file}" has been deleted successfully.`
        });
      }
    },
    onError: (error, params) => {
      console.error("Failed to delete file(s):", error);
      toast.error("Failed to delete file(s)");
      addNotification({
        type: "error",
        title: "Delete Failed",
        message: `Failed to delete file(s). Please try again.`
      });
    }
  });

  const requeueMutation = useMutation({
    mutationFn: ({ dataset, file }: { dataset: string; file: string }) =>
      post(`/files/${dataset}/${encodeURIComponent(file)}/requeue`),
    onSuccess: (_, { file }) => {
      queryClient.refetchQueries({ queryKey: ["all-files"] });
      queryClient.refetchQueries({ queryKey: ["tasks"] });
      toast.success("File requeued for processing");
      addNotification({
        type: "success",
        title: "File Requeued",
        message: `File "${file}" has been requeued for processing.`
      });
    },
    onError: (error, { file }) => {
      console.error("Failed to requeue file:", error);
      toast.error("Failed to requeue file");
      addNotification({
        type: "error",
        title: "Requeue Failed",
        message: `Failed to requeue file "${file}". Please try again.`
      });
    }
  });

  const handleEdit = (file: any) => {
    setEditFile(file);
  };

  const handleEditClose = () => {
    setEditFile(null);
  };

  // Confirmation dialog handlers
  const handleDeleteClick = (file: any) => {
    setDeleteConfirm({
      isOpen: true,
      file,
      isBatch: false
    });
  };

  const handleBatchDeleteClick = () => {
    const filesToDelete = displayFiles.filter((file) =>
      selectedFiles.has(`${file.dataset}-${file.input}`)
    );
    setDeleteConfirm({
      isOpen: true,
      isBatch: true,
      selectedFiles: filesToDelete
    });
  };

  const handleBatchRequeueClick = () => {
    const filesToRequeue = displayFiles.filter((file) =>
      selectedFiles.has(`${file.dataset}-${file.input}`)
    );
    filesToRequeue.forEach((file) => {
      requeueMutation.mutate({
        dataset: file.dataset,
        file: file.input
      });
    });
    setSelectedFiles(new Set()); // Clear selection after requeue
  };

  const handleDeleteConfirm = () => {
    if (deleteConfirm.isBatch && deleteConfirm.selectedFiles) {
      deleteMutation.mutate({ files: deleteConfirm.selectedFiles });
    } else if (deleteConfirm.file) {
      deleteMutation.mutate({ file: deleteConfirm.file.input });
    }
    setDeleteConfirm({ isOpen: false });
  };

  const handleDeleteCancel = () => {
    setDeleteConfirm({ isOpen: false });
  };

  // Batch selection handlers
  const handleSelectAll = () => {
    if (selectedFiles.size === displayFiles.length) {
      setSelectedFiles(new Set());
    } else {
      const allIds = new Set(
        displayFiles.map((file) => `${file.dataset}-${file.input}`)
      );
      setSelectedFiles(allIds);
    }
  };

  const handleSelectFile = (file: any) => {
    const fileId = `${file.dataset}-${file.input}`;
    const newSelected = new Set(selectedFiles);
    if (newSelected.has(fileId)) {
      newSelected.delete(fileId);
    } else {
      newSelected.add(fileId);
    }
    setSelectedFiles(newSelected);
  };

  // Expanded row handlers
  const handleToggleExpanded = (fileId: string) => {
    const newExpanded = new Set(expandedRows);
    if (newExpanded.has(fileId)) {
      newExpanded.delete(fileId);
    } else {
      newExpanded.add(fileId);
    }
    setExpandedRows(newExpanded);
  };

  // Dropdown handlers
  const handleToggleDropdown = (fileId: string) => {
    setOpenDropdown(openDropdown === fileId ? null : fileId);
  };

  const handleDropdownAction = (action: string, file: any) => {
    setOpenDropdown(null);
    switch (action) {
      case "edit":
        handleEdit(file);
        break;
      case "delete":
        handleDeleteClick(file);
        break;
    }
  };

  // Close dropdown when clicking outside
  useEffect(() => {
    const handleClickOutside = (event: MouseEvent) => {
      if (
        openDropdown &&
        !(event.target as Element).closest(".dropdown-container")
      ) {
        setOpenDropdown(null);
      }
    };

    document.addEventListener("mousedown", handleClickOutside);
    return () => document.removeEventListener("mousedown", handleClickOutside);
  }, [openDropdown]);

  const formatDate = (dateString: string) => {
    if (!dateString) return "-";
    try {
      const date = new Date(dateString);
      return date.toLocaleString();
    } catch {
      return dateString;
    }
  };

  const toggleDataset = (datasetName: string) => {
    const newEnabled = new Set(enabledDatasets);
    if (newEnabled.has(datasetName)) {
      newEnabled.delete(datasetName);
    } else {
      newEnabled.add(datasetName);
    }
    setEnabledDatasets(newEnabled);
  };

  const handleSort = (field: "input" | "date") => {
    if (sortField === field) {
      setSortDirection(sortDirection === "asc" ? "desc" : "asc");
    } else {
      setSortField(field);
      setSortDirection("asc");
    }
  };

  // Filter and sort data
  const filteredAndSortedData = useMemo(() => {
    if (!allFiles) return [];

    let filtered = allFiles.filter(
      (file: any) =>
        enabledDatasets.has(file.dataset) &&
        (file.input.toLowerCase().includes(searchTerm.toLowerCase()) ||
          (file.output &&
            file.output.toLowerCase().includes(searchTerm.toLowerCase())))
    );

    filtered.sort((a: any, b: any) => {
      let aValue = a[sortField];
      let bValue = b[sortField];

      if (sortField === "date") {
        aValue = new Date(aValue).getTime();
        bValue = new Date(bValue).getTime();
      } else {
        aValue = aValue.toLowerCase();
        bValue = bValue.toLowerCase();
      }

      if (aValue < bValue) return sortDirection === "asc" ? -1 : 1;
      if (aValue > bValue) return sortDirection === "asc" ? 1 : -1;
      return 0;
    });

    return filtered;
  }, [allFiles, enabledDatasets, searchTerm, sortField, sortDirection]);

  // Handle pagination
  const paginatedData = useMemo(() => {
    const startIndex = (currentPage - 1) * pageSize;
    const endIndex = startIndex + pageSize;
    return filteredAndSortedData.slice(startIndex, endIndex);
  }, [filteredAndSortedData, currentPage, pageSize]);

  // Reset to page 1 when filters change
  useEffect(() => {
    setCurrentPage(1);
  }, [enabledDatasets, searchTerm, sortField, sortDirection]);

  const displayFiles = paginatedData;

  if (isLoading) return <LoadingCard message="Loading files..." />;
  if (error) {
    return (
      <div className="text-center p-8 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg">
        <div className="mb-6">
          <svg
            className="mx-auto h-16 w-16 text-red-400"
            fill="none"
            viewBox="0 0 24 24"
            stroke="currentColor"
          >
            <path
              strokeLinecap="round"
              strokeLinejoin="round"
              strokeWidth={2}
              d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L4.082 16.5c-.77.833.192 2.5 1.732 2.5z"
            />
          </svg>
        </div>
        <h2 className="text-xl font-semibold text-red-800 dark:text-red-200 mb-4">
          Failed to load files
        </h2>
        <p className="text-gray-600 dark:text-gray-400 mb-6">
          There was an error loading the files data.
        </p>
        <button
          onClick={() =>
            queryClient.refetchQueries({ queryKey: ["all-files"] })
          }
          className="inline-flex items-center px-6 py-3 border border-transparent text-base font-medium rounded-md text-white bg-red-600 hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500"
        >
          Try Again
        </button>
      </div>
    );
  }

  return (
    <>
      <div className="mb-6 p-4 border rounded bg-gray-50 dark:bg-gray-800">
        <div className="flex items-center justify-between mb-4">
          <h3 className="font-semibold">Files</h3>
          <div className="flex items-center gap-2">
            <span className="text-sm text-gray-600 dark:text-gray-400">
              Total: {filteredAndSortedData.length} files
            </span>
          </div>
        </div>

        {/* Filter Controls */}
        <div className="mb-4 space-y-4">
          {/* Search */}
          <div className="flex items-center gap-4">
            <div className="flex-1">
              <input
                type="text"
                placeholder="Search files..."
                value={searchTerm}
                onChange={(e) => setSearchTerm(e.target.value)}
                className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:text-white"
              />
            </div>
          </div>

          {/* Dataset Toggles */}
          <div className="flex flex-wrap gap-2">
            <span className="text-sm text-gray-600 dark:text-gray-400 mr-2">
              Datasets:
            </span>
            {datasets?.map((datasetPath: string) => {
              const datasetName = datasetPath.split("/").pop();
              if (!datasetName) return null;
              return (
                <label key={datasetName} className="flex items-center gap-2">
                  <input
                    type="checkbox"
                    checked={enabledDatasets.has(datasetName)}
                    onChange={() => toggleDataset(datasetName)}
                    className="rounded border-gray-300 dark:border-gray-600 text-blue-600 focus:ring-blue-500"
                  />
                  <span className="text-sm text-gray-700 dark:text-gray-300">
                    {datasetName}
                  </span>
                </label>
              );
            })}
          </div>
        </div>

        {/* Batch Actions */}
        {selectedFiles.size > 0 && (
          <div className="mb-4 flex items-center gap-2">
            <span className="text-sm text-gray-700 dark:text-gray-300">
              {selectedFiles.size} file{selectedFiles.size !== 1 ? "s" : ""}{" "}
              selected
            </span>
            <button
              onClick={handleBatchRequeueClick}
              className="inline-flex items-center px-3 py-2 border border-transparent text-sm font-medium rounded-md text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
            >
              Requeue Selected
            </button>
            <button
              onClick={handleBatchDeleteClick}
              className="inline-flex items-center px-3 py-2 border border-transparent text-sm font-medium rounded-md text-white bg-red-600 hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500"
            >
              <TrashIcon className="h-4 w-4 mr-2" />
              Delete Selected
            </button>
            <button
              onClick={() => setSelectedFiles(new Set())}
              className="inline-flex items-center px-3 py-2 border border-gray-300 dark:border-gray-600 text-sm font-medium rounded-md text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-800 hover:bg-gray-50 dark:hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
            >
              Clear Selection
            </button>
          </div>
        )}

        <div className="overflow-x-auto rounded-lg border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 shadow-sm">
          <table className="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
            <thead className="bg-gray-50 dark:bg-gray-800">
              <tr>
                <th
                  scope="col"
                  className="px-4 py-3 text-left text-xs font-semibold text-gray-700 dark:text-gray-200 uppercase tracking-wider w-8"
                >
                  {/* Expand toggle column */}
                </th>
                <th
                  scope="col"
                  className="px-4 py-3 text-left text-xs font-semibold text-gray-700 dark:text-gray-200 uppercase tracking-wider"
                >
                  <input
                    type="checkbox"
                    checked={
                      selectedFiles.size === displayFiles.length &&
                      displayFiles.length > 0
                    }
                    onChange={handleSelectAll}
                    className="rounded border-gray-300 dark:border-gray-600 text-blue-600 focus:ring-blue-500"
                  />
                </th>
                <th
                  scope="col"
                  className="px-4 py-3 text-left text-xs font-semibold text-gray-700 dark:text-gray-200 uppercase tracking-wider"
                >
                  Dataset
                </th>
                <th
                  scope="col"
                  className="px-4 py-3 text-left text-xs font-semibold text-gray-700 dark:text-gray-200 uppercase tracking-wider cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-700"
                  onClick={() => handleSort("input")}
                >
                  Input{" "}
                  {sortField === "input" &&
                    (sortDirection === "asc" ? "↑" : "↓")}
                </th>
                <th
                  scope="col"
                  className="px-4 py-3 text-left text-xs font-semibold text-gray-700 dark:text-gray-200 uppercase tracking-wider cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-700"
                  onClick={() => handleSort("date")}
                >
                  Date{" "}
                  {sortField === "date" &&
                    (sortDirection === "asc" ? "↑" : "↓")}
                </th>
                <th
                  scope="col"
                  className="px-4 py-3 text-right text-xs font-semibold text-gray-700 dark:text-gray-200 uppercase tracking-wider"
                >
                  Actions
                </th>
              </tr>
            </thead>
            <tbody className="divide-y divide-gray-200 dark:divide-gray-800">
              {displayFiles.length > 0 ? (
                displayFiles.map((file: any) => {
                  const fileId = `${file.dataset}-${file.input}`;
                  const isExpanded = expandedRows.has(fileId);
                  return (
                    <>
                      <tr
                        key={fileId}
                        className="hover:bg-gray-50 dark:hover:bg-gray-700"
                      >
                        <td className="px-4 py-2 whitespace-nowrap">
                          <button
                            onClick={() => handleToggleExpanded(fileId)}
                            className="text-gray-400 hover:text-gray-600 dark:hover:text-gray-300"
                          >
                            {isExpanded ? (
                              <ChevronDownIcon className="h-4 w-4" />
                            ) : (
                              <ChevronRightIcon className="h-4 w-4" />
                            )}
                          </button>
                        </td>
                        <td className="px-4 py-2 whitespace-nowrap">
                          <input
                            type="checkbox"
                            checked={selectedFiles.has(fileId)}
                            onChange={() => handleSelectFile(file)}
                            className="rounded border-gray-300 dark:border-gray-600 text-blue-600 focus:ring-blue-500"
                          />
                        </td>
                        <td className="px-4 py-2 whitespace-nowrap text-sm text-gray-900 dark:text-gray-100">
                          <span className="px-2 py-1 bg-blue-100 dark:bg-blue-900 text-blue-800 dark:text-blue-200 rounded text-xs font-medium">
                            {file.dataset}
                          </span>
                        </td>
                        <td className="px-4 py-2 text-sm text-gray-900 dark:text-gray-100 max-w-xs">
                          <div className="truncate" title={file.input}>
                            {file.input}
                          </div>
                        </td>
                        <td className="px-4 py-2 whitespace-nowrap text-sm text-gray-900 dark:text-gray-100">
                          {formatDate(file.date)}
                        </td>
                        <td className="px-4 py-2 whitespace-nowrap text-sm text-right">
                          <div className="flex items-center justify-end space-x-1">
                            <button
                              onClick={() =>
                                requeueMutation.mutate({
                                  dataset: file.dataset,
                                  file: file.input
                                })
                              }
                              className="inline-flex items-center px-3 py-1 text-xs font-medium text-white bg-blue-500 hover:bg-blue-600 rounded-l-md border border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
                            >
                              Requeue
                            </button>
                            <div className="relative">
                              <button
                                onClick={() => handleToggleDropdown(fileId)}
                                className="inline-flex items-center px-2 py-1 text-xs font-medium text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-800 border border-l-0 border-gray-300 dark:border-gray-600 hover:bg-gray-50 dark:hover:bg-gray-700 rounded-r-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
                              >
                                <ChevronDownIcon className="h-4 w-4" />
                              </button>
                              {openDropdown === fileId && (
                                <div className="dropdown-container absolute right-0 mt-1 w-32 bg-white dark:bg-gray-800 rounded-md shadow-lg border border-gray-200 dark:border-gray-700 z-10">
                                  <div className="py-1">
                                    <button
                                      onClick={() =>
                                        handleDropdownAction("edit", file)
                                      }
                                      className="block w-full text-left px-3 py-2 text-xs text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700"
                                    >
                                      Edit
                                    </button>
                                    <button
                                      onClick={() =>
                                        handleDropdownAction("delete", file)
                                      }
                                      className="block w-full text-left px-3 py-2 text-xs text-red-600 dark:text-red-400 hover:bg-gray-100 dark:hover:bg-gray-700"
                                    >
                                      Delete
                                    </button>
                                  </div>
                                </div>
                              )}
                            </div>
                          </div>
                        </td>
                      </tr>
                      {isExpanded && (
                        <tr
                          key={`${fileId}-expanded`}
                          className="bg-gray-50 dark:bg-gray-800"
                        >
                          <td colSpan={5} className="px-4 py-3">
                            <div className="text-sm">
                              <div className="font-medium text-gray-900 dark:text-gray-100 mb-2">
                                Output
                              </div>
                              <div className="text-gray-700 dark:text-gray-300 font-mono text-xs bg-white dark:bg-gray-900 p-2 rounded border">
                                {file.output || "No output available"}
                              </div>
                            </div>
                          </td>
                        </tr>
                      )}
                    </>
                  );
                })
              ) : (
                <tr>
                  <td
                    colSpan={5}
                    className="px-4 py-4 text-center text-gray-500 dark:text-gray-400"
                  >
                    No files found matching your filters.
                  </td>
                </tr>
              )}
            </tbody>
          </table>
        </div>
      </div>

      <Pagination
        currentPage={currentPage}
        totalItems={filteredAndSortedData.length}
        pageSize={pageSize}
        onPageChange={setCurrentPage}
        onPageSizeChange={(newPageSize) => {
          setPageSize(newPageSize);
          setCurrentPage(1);
        }}
      />

      {editFile && (
        <FileCrud editFile={editFile} onEditClose={handleEditClose} />
      )}

      <ConfirmationDialog
        isOpen={deleteConfirm.isOpen}
        title={deleteConfirm.isBatch ? "Delete Selected Files" : "Delete File"}
        message={
          deleteConfirm.isBatch
            ? `Are you sure you want to delete ${deleteConfirm.selectedFiles?.length} selected file(s)? This action cannot be undone.`
            : `Are you sure you want to delete "${deleteConfirm.file?.input}"? This action cannot be undone.`
        }
        confirmText="Delete"
        cancelText="Cancel"
        type="danger"
        onConfirm={handleDeleteConfirm}
        onClose={handleDeleteCancel}
        isLoading={deleteMutation.isPending}
      />
    </>
  );
}
