"use client";

import Spinner from "@/app/components/Spinner/Spinner";
import DeleteModal from "@/app/components/DeleteModal/DeleteModal";
import { TDeleteModalResource } from "@/app/components/DeleteModal/types";
import AddModal from "@/app/components/AddModal/AddModal";
import { IAddModalField } from "@/app/components/AddModal/types";
import { DataRowBase } from "@/app/features/DataTable/types";
import {
  selectFilters,
  selectPagination,
  selectSort,
} from "@/app/redux/advanedSearch/selectors";
import {
  Alert,
  Button,
  Chip,
  IconButton,
  Switch,
  TextField,
  Tooltip,
  Typography,
} from "@mui/material";
import DeleteOutlineIcon from "@mui/icons-material/DeleteOutline";
import EditIcon from "@mui/icons-material/Edit";
import CheckIcon from "@mui/icons-material/Check";
import CloseIcon from "@mui/icons-material/Close";
import { useEffect, useMemo, useState } from "react";
import { useSelector } from "react-redux";

import {
  createResourceApi,
  deleteResourceApi,
  updateResourceApi,
} from "./AdminResourceList.utils";
import "./AdminResourceList.scss";

type ResourceRow = DataRowBase & {
  identifier?: string | number;
} & Record<string, unknown>;

type FilterValue =
  | string
  | {
      operator?: string;
      value: string;
    };

interface AdminResourceListProps {
  title: string;
  endpoint: string;
  responseCollectionKeys?: string[];
  primaryLabelKeys: string[];
  chipKeys?: string[];
  excludeKeys?: string[];
  filterOverrides?: Record<string, FilterValue>;
  addModalFields?: IAddModalField[];
  showEnabledToggle?: boolean;
  idField?: string;
  initialData?: Record<string, unknown>;
}

const DEFAULT_COLLECTION_KEYS = ["data", "items"];

const ensureRowId = (
  row: Record<string, unknown>,
  fallbackId: number
): ResourceRow => {
  const currentId = row.id;

  if (typeof currentId === "number") {
    return row as ResourceRow;
  }

  const identifier = currentId;
  const numericId = Number(currentId);

  if (!Number.isNaN(numericId) && numericId !== 0) {
    return { ...row, id: numericId, identifier } as ResourceRow;
  }

  return { ...row, id: fallbackId, identifier } as ResourceRow;
};

const resolveCollection = (
  payload: Record<string, unknown>,
  preferredKeys: string[] = []
) => {
  for (const key of [...preferredKeys, ...DEFAULT_COLLECTION_KEYS]) {
    const maybeCollection = payload?.[key];
    if (Array.isArray(maybeCollection)) {
      return maybeCollection as Record<string, unknown>[];
    }
  }

  if (Array.isArray(payload)) {
    return payload as Record<string, unknown>[];
  }

  return [];
};

const AdminResourceList = ({
  title,
  endpoint,
  responseCollectionKeys = [],
  primaryLabelKeys,
  chipKeys = [],
  excludeKeys = [],
  addModalFields,
  showEnabledToggle = false,
  idField,
  initialData,
}: AdminResourceListProps) => {
  // Keep Redux for shared state (filters, pagination, sort)
  const filters = useSelector(selectFilters);
  const pagination = useSelector(selectPagination);
  const sort = useSelector(selectSort);

  // Use local state for component-specific status/error
  const [localStatus, setLocalStatus] = useState<
    "idle" | "loading" | "succeeded" | "failed"
  >(initialData ? "succeeded" : "idle");
  const [localError, setLocalError] = useState<string | null>(null);

  const [refreshCounter, setRefreshCounter] = useState(0);
  const [deleteModalOpen, setDeleteModalOpen] = useState(false);
  const [resourceToDelete, setResourceToDelete] =
    useState<TDeleteModalResource | null>(null);
  const [isDeleting, setIsDeleting] = useState(false);
  const [deleteError, setDeleteError] = useState<string | null>(null);
  const [addModalOpen, setAddModalOpen] = useState(false);
  const [isAdding, setIsAdding] = useState(false);
  const [addError, setAddError] = useState<string | null>(null);
  const [editingRowId, setEditingRowId] = useState<number | string | null>(
    null
  );
  const [editingName, setEditingName] = useState<string>("");
  const [editingRate, setEditingRate] = useState<string>("");
  const [isSavingName, setIsSavingName] = useState(false);
  const [updatingEnabled, setUpdatingEnabled] = useState<Set<number | string>>(
    new Set()
  );

  const normalizedTitle = title.toLowerCase();

  const getRowIdentifier = (row: ResourceRow): number | string => {
    if (idField && row[idField] !== undefined) {
      return row[idField] as number | string;
    }
    return (row.identifier as string | number | undefined) ?? row.id;
  };

  const excludedKeys = useMemo(() => {
    const baseExcluded = new Set(["id", ...primaryLabelKeys, ...chipKeys]);
    excludeKeys.forEach(key => baseExcluded.add(key));
    return Array.from(baseExcluded);
  }, [primaryLabelKeys, chipKeys, excludeKeys]);

  const getPrimaryLabel = (row: ResourceRow) => {
    for (const key of primaryLabelKeys) {
      if (row[key]) {
        return String(row[key]);
      }
    }
    return `${title} #${row.id}`;
  };

  const getMetaChips = (row: ResourceRow) =>
    chipKeys
      .filter(key => row[key])
      .map(key => ({
        key,
        value: String(row[key]),
      }));

  const getSecondaryDetails = (row: ResourceRow) =>
    Object.entries(row).filter(([key]) => !excludedKeys.includes(key));

  const resolvedCollectionKeys = useMemo(
    () => [...responseCollectionKeys],
    [responseCollectionKeys]
  );

  // Initialize rows synchronously from initialData if available
  const getInitialRows = (): ResourceRow[] => {
    if (initialData) {
      const collection = resolveCollection(initialData, resolvedCollectionKeys);
      return collection.map((item, index) => {
        const row = ensureRowId(item, index + 1);
        // If idField is specified, use that field as identifier
        if (idField && row[idField] !== undefined) {
          return { ...row, identifier: row[idField] } as ResourceRow;
        }
        return row;
      });
    }
    return [];
  };

  const [rows, setRows] = useState<ResourceRow[]>(() => getInitialRows());

  useEffect(() => {
    // Skip initial fetch if we have server-rendered data and no filters/pagination/sort changes
    // Always fetch when filters/pagination/sort change or after mutations (refreshCounter > 0)
    const hasFilters = Object.keys(filters).length > 0;
    const hasSort = sort?.field && sort?.order;

    // Only skip if we have initialData AND it's the first render (refreshCounter === 0) AND no filters/sort
    // Also check if pagination is at default values (page 1, limit 100)
    const isDefaultPagination =
      pagination.page === 1 && pagination.limit === 100;
    const shouldSkipInitialFetch =
      initialData &&
      refreshCounter === 0 &&
      !hasFilters &&
      !hasSort &&
      isDefaultPagination;

    if (shouldSkipInitialFetch) {
      return;
    }

    const fetchResources = async () => {
      setLocalStatus("loading");
      setLocalError(null);

      try {
        const response = await fetch(endpoint, {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({
            filters,
            pagination,
            sort,
          }),
        });

        if (!response.ok) {
          setLocalError(`Failed to fetch ${normalizedTitle}`);
          setRows([]);
          setLocalStatus("failed");
          return;
        }

        const backendData = await response.json();
        const collection = resolveCollection(
          backendData,
          resolvedCollectionKeys
        );

        const nextRows = collection.map((item, index) => {
          const row = ensureRowId(item, index + 1);
          // If idField is specified, use that field as identifier
          if (idField && row[idField] !== undefined) {
            return { ...row, identifier: row[idField] } as ResourceRow;
          }
          return row;
        });

        setRows(nextRows);
        setLocalStatus("succeeded");
      } catch (error) {
        setLocalError(error instanceof Error ? error.message : "Unknown error");
        setRows([]);
        setLocalStatus("failed");
      }
    };

    fetchResources();
  }, [
    endpoint,
    filters,
    pagination,
    sort,
    resolvedCollectionKeys,
    normalizedTitle,
    refreshCounter,
    idField,
    initialData,
  ]);

  const handleAddClick = () => {
    if (!addModalFields) {
      return;
    }
    setAddModalOpen(true);
    setAddError(null);
  };

  const handleAddConfirm = async (data: Record<string, unknown>) => {
    if (!addModalFields) {
      return;
    }

    setIsAdding(true);
    setAddError(null);

    try {
      await createResourceApi(endpoint, data, normalizedTitle);
      setAddModalOpen(false);
      setRefreshCounter(current => current + 1);
    } catch (error) {
      const errorMessage =
        error instanceof Error
          ? error.message
          : `Failed to create ${normalizedTitle}`;
      setAddError(errorMessage);
      setLocalError(errorMessage);
    } finally {
      setIsAdding(false);
    }
  };

  const handleAddModalClose = () => {
    if (!isAdding) {
      setAddModalOpen(false);
      setAddError(null);
    }
  };

  const handleEditClick = (row: ResourceRow) => {
    if (!addModalFields || !row.id) {
      return;
    }
    const currentName = getPrimaryLabel(row);
    const currentRate = row.rate !== undefined ? String(row.rate) : "";
    setEditingRowId(row.id);
    setEditingName(currentName);
    setEditingRate(currentRate);
  };

  const handleEditCancel = () => {
    setEditingRowId(null);
    setEditingName("");
    setEditingRate("");
  };

  const handleEditSave = async (row: ResourceRow) => {
    if (!addModalFields || !editingName.trim()) {
      handleEditCancel();
      return;
    }

    const identifier = getRowIdentifier(row);

    setIsSavingName(true);

    try {
      const updatePayload: Record<string, unknown> = {
        name: editingName.trim(),
      };

      // Include rate if it exists and has been modified
      if (row.rate !== undefined && editingRate !== "") {
        const rateValue = parseFloat(editingRate);
        if (!Number.isNaN(rateValue)) {
          updatePayload.rate = rateValue;
        }
      }

      await updateResourceApi(
        endpoint,
        identifier,
        updatePayload,
        normalizedTitle
      );
      setEditingRowId(null);
      setEditingName("");
      setEditingRate("");
      setRefreshCounter(current => current + 1);
    } catch (error) {
      const errorMessage =
        error instanceof Error
          ? error.message
          : `Failed to update ${normalizedTitle}`;
      setLocalError(errorMessage);
    } finally {
      setIsSavingName(false);
    }
  };

  const handleEditKeyDown = (e: React.KeyboardEvent, row: ResourceRow) => {
    if (e.key === "Enter") {
      e.preventDefault();
      handleEditSave(row);
    } else if (e.key === "Escape") {
      e.preventDefault();
      handleEditCancel();
    }
  };

  const handleDeleteClick = (row: ResourceRow) => {
    if (!addModalFields) {
      return;
    }

    const identifier = getRowIdentifier(row);
    if (!identifier) {
      return;
    }

    setResourceToDelete({
      id: identifier,
      label: getPrimaryLabel(row),
    });
    setDeleteModalOpen(true);
    setDeleteError(null);
  };

  const handleDeleteConfirm = async (id: number | string) => {
    if (!addModalFields) {
      return;
    }

    setIsDeleting(true);
    setDeleteError(null);

    try {
      await deleteResourceApi(endpoint, id, normalizedTitle);
      setDeleteModalOpen(false);
      setResourceToDelete(null);
      setRefreshCounter(current => current + 1);
    } catch (error) {
      const errorMessage =
        error instanceof Error
          ? error.message
          : `Failed to delete ${normalizedTitle}`;
      setDeleteError(errorMessage);
      setLocalError(errorMessage);
    } finally {
      setIsDeleting(false);
    }
  };

  const handleDeleteModalClose = () => {
    if (!isDeleting) {
      setDeleteModalOpen(false);
      setResourceToDelete(null);
      setDeleteError(null);
    }
  };

  const handleEnabledToggle = async (row: ResourceRow, newEnabled: boolean) => {
    if (!showEnabledToggle) {
      return;
    }

    const identifier = getRowIdentifier(row);

    setUpdatingEnabled(prev => new Set(prev).add(identifier));

    try {
      await updateResourceApi(
        endpoint,
        identifier,
        { enabled: newEnabled },
        normalizedTitle
      );
      setRefreshCounter(current => current + 1);
    } catch (error) {
      const errorMessage =
        error instanceof Error
          ? error.message
          : `Failed to update ${normalizedTitle}`;
      setLocalError(errorMessage);
    } finally {
      setUpdatingEnabled(prev => {
        const next = new Set(prev);
        next.delete(identifier);
        return next;
      });
    }
  };

  return (
    <div className="admin-resource-list">
      <div className="admin-resource-list__header">
        <Typography variant="h5" className="admin-resource-list__title">
          {title}
        </Typography>

        {addModalFields && (
          <Button
            variant="contained"
            size="small"
            onClick={handleAddClick}
            className="admin-resource-list__button--add"
          >
            Add {title}
          </Button>
        )}
      </div>

      {localStatus === "loading" && (
        <div className="admin-resource-list__loading">
          <Spinner size="small" color="#000" />
          <Typography variant="body2">
            {`Loading ${normalizedTitle}...`}
          </Typography>
        </div>
      )}

      {localStatus === "failed" && (
        <Alert severity="error" className="admin-resource-list__error">
          {localError || `Failed to load ${normalizedTitle}`}
        </Alert>
      )}

      {!rows.length && localStatus === "succeeded" && (
        <Typography variant="body2" className="admin-resource-list__empty">
          {`No ${normalizedTitle} found.`}
        </Typography>
      )}

      {rows.length > 0 && (
        <div className="admin-resource-list__list">
          {rows.map(row => {
            const chips = getMetaChips(row);
            const secondary = getSecondaryDetails(row);

            return (
              <div key={row.id} className="admin-resource-list__row">
                <div className="admin-resource-list__row-content">
                  <div className="admin-resource-list__row-container">
                    <div className="admin-resource-list__row-header">
                      {editingRowId === row.id ? (
                        <div
                          style={{
                            display: "flex",
                            flexDirection: "column",
                            gap: "8px",
                            width: "100%",
                          }}
                        >
                          <TextField
                            value={editingName}
                            onChange={e => setEditingName(e.target.value)}
                            onKeyDown={e => handleEditKeyDown(e, row)}
                            autoFocus
                            disabled={isSavingName}
                            size="small"
                            className="admin-resource-list__edit-field"
                            variant="standard"
                            label="Name"
                          />
                          {row.rate !== undefined && (
                            <TextField
                              value={editingRate}
                              onChange={e => setEditingRate(e.target.value)}
                              onKeyDown={e => handleEditKeyDown(e, row)}
                              disabled={isSavingName}
                              size="small"
                              className="admin-resource-list__edit-field"
                              variant="standard"
                              label="Rate"
                              type="number"
                            />
                          )}
                        </div>
                      ) : (
                        <Typography
                          variant="subtitle1"
                          className="admin-resource-list__row-title"
                        >
                          {getPrimaryLabel(row)}
                        </Typography>
                      )}

                      <Typography
                        variant="caption"
                        className="admin-resource-list__row-id"
                      >
                        ID: {row.id}
                      </Typography>
                    </div>

                    {chips.length > 0 && editingRowId !== row.id && (
                      <div className="admin-resource-list__row-chips">
                        {chips.map(chip => (
                          <Chip
                            key={`${row.id}-${chip.key}`}
                            label={`${chip.key}: ${chip.value}`}
                            size="small"
                            color="primary"
                            variant="outlined"
                          />
                        ))}
                      </div>
                    )}

                    {secondary.length > 0 && (
                      <Typography
                        variant="body2"
                        className="admin-resource-list__row-secondary"
                      >
                        {secondary
                          .map(([key, value]) => `${key}: ${String(value)}`)
                          .join(" • ")}
                      </Typography>
                    )}
                  </div>

                  {(addModalFields || showEnabledToggle) && (
                    <div className="admin-resource-list__secondary-actions">
                      {showEnabledToggle && (
                        <>
                          <Typography
                            variant="body2"
                            className="admin-resource-list__enabled-label"
                          >
                            Enabled
                          </Typography>
                          <Switch
                            checked={Boolean(row.enabled)}
                            onChange={e =>
                              handleEnabledToggle(row, e.target.checked)
                            }
                            disabled={updatingEnabled.has(
                              (row.identifier as string | number | undefined) ??
                                row.id
                            )}
                            size="small"
                          />
                        </>
                      )}
                      {addModalFields && (
                        <>
                          {editingRowId === row.id ? (
                            <>
                              <Tooltip title="Save">
                                <IconButton
                                  edge="end"
                                  aria-label={`save ${normalizedTitle} name`}
                                  onClick={() => handleEditSave(row)}
                                  disabled={isSavingName}
                                  size="small"
                                  color="primary"
                                >
                                  {isSavingName ? (
                                    <Spinner size="small" color="#1976d2" />
                                  ) : (
                                    <CheckIcon />
                                  )}
                                </IconButton>
                              </Tooltip>
                              <Tooltip title="Cancel">
                                <IconButton
                                  edge="end"
                                  aria-label="cancel edit"
                                  onClick={handleEditCancel}
                                  disabled={isSavingName}
                                  size="small"
                                >
                                  <CloseIcon />
                                </IconButton>
                              </Tooltip>
                            </>
                          ) : (
                            <Tooltip title="Edit">
                              <IconButton
                                edge="end"
                                aria-label={`edit ${normalizedTitle}`}
                                onClick={() => handleEditClick(row)}
                                size="small"
                              >
                                <EditIcon />
                              </IconButton>
                            </Tooltip>
                          )}
                          <Tooltip title="Delete">
                            <IconButton
                              edge="end"
                              aria-label={`delete ${normalizedTitle}`}
                              onClick={() => handleDeleteClick(row)}
                              size="small"
                            >
                              <DeleteOutlineIcon />
                            </IconButton>
                          </Tooltip>
                        </>
                      )}
                    </div>
                  )}
                </div>
                <div className="admin-resource-list__divider" />
              </div>
            );
          })}
        </div>
      )}

      {addModalFields && (
        <>
          <AddModal
            open={addModalOpen}
            onClose={handleAddModalClose}
            onConfirm={handleAddConfirm}
            resourceType={normalizedTitle}
            fields={addModalFields}
            isLoading={isAdding}
            error={addError}
          />
          <DeleteModal
            open={deleteModalOpen}
            onClose={handleDeleteModalClose}
            onConfirm={handleDeleteConfirm}
            resource={resourceToDelete}
            resourceType={normalizedTitle}
            isLoading={isDeleting}
            error={deleteError}
          />
        </>
      )}
    </div>
  );
};

export default AdminResourceList;
