"use client";

import Spinner from "@/app/components/Spinner/Spinner";
import { DataRowBase } from "@/app/features/DataTable/types";
import {
  setError as setAdvancedSearchError,
  setStatus,
} from "@/app/redux/advanedSearch/advancedSearchSlice";
import {
  selectError,
  selectFilters,
  selectPagination,
  selectSort,
  selectStatus,
} from "@/app/redux/advanedSearch/selectors";
import { AppDispatch } from "@/app/redux/store";
import {
  Alert,
  Box,
  Chip,
  Divider,
  List,
  ListItem,
  Typography,
} from "@mui/material";
import { useEffect, useMemo, useState } from "react";
import { useDispatch, useSelector } from "react-redux";

type ResourceRow = DataRowBase & 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>;
}

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 numericId = Number(currentId);

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

  return { ...row, id: fallbackId } 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 = [],
}: AdminResourceListProps) => {
  const dispatch = useDispatch<AppDispatch>();
  const filters = useSelector(selectFilters);
  const pagination = useSelector(selectPagination);
  const sort = useSelector(selectSort);
  const status = useSelector(selectStatus);
  const errorMessage = useSelector(selectError);

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

  const normalizedTitle = title.toLowerCase();

  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]
  );

  useEffect(() => {
    const fetchResources = async () => {
      dispatch(setStatus("loading"));
      dispatch(setAdvancedSearchError(null));

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

        if (!response.ok) {
          dispatch(
            setAdvancedSearchError(`Failed to fetch ${normalizedTitle}`)
          );
          setRows([]);
          return;
        }

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

        const nextRows = collection.map((item, index) =>
          ensureRowId(item, index + 1)
        );

        setRows(nextRows);
        dispatch(setStatus("succeeded"));
      } catch (error) {
        dispatch(
          setAdvancedSearchError(
            error instanceof Error ? error.message : "Unknown error"
          )
        );
        setRows([]);
      }
    };

    fetchResources();
  }, [
    dispatch,
    endpoint,
    filters,
    pagination,
    sort,
    resolvedCollectionKeys,
    normalizedTitle,
  ]);

  return (
    <Box sx={{ p: 3, width: "100%", maxWidth: 900 }}>
      <Typography variant="h5" sx={{ mb: 2 }}>
        {title}
      </Typography>

      {status === "loading" && (
        <Box sx={{ display: "flex", gap: 1, alignItems: "center", mb: 2 }}>
          <Spinner size="small" color="#000" />
          <Typography variant="body2">
            {`Loading ${normalizedTitle}...`}
          </Typography>
        </Box>
      )}

      {status === "failed" && (
        <Alert severity="error" sx={{ mb: 2 }}>
          {errorMessage || `Failed to load ${normalizedTitle}`}
        </Alert>
      )}

      {!rows.length && status === "succeeded" && (
        <Typography variant="body2" color="text.secondary">
          {`No ${normalizedTitle} found.`}
        </Typography>
      )}

      {rows.length > 0 && (
        <List
          sx={{ bgcolor: "background.paper", borderRadius: 2, boxShadow: 1 }}
        >
          {rows.map(row => {
            const chips = getMetaChips(row);
            const secondary = getSecondaryDetails(row);

            return (
              <Box key={row.id}>
                <ListItem alignItems="flex-start">
                  <Box sx={{ width: "100%" }}>
                    <Box
                      sx={{
                        display: "flex",
                        justifyContent: "space-between",
                        flexWrap: "wrap",
                        gap: 1,
                      }}
                    >
                      <Typography variant="subtitle1" fontWeight={600}>
                        {getPrimaryLabel(row)}
                      </Typography>

                      <Typography variant="caption" color="text.secondary">
                        ID: {row.id}
                      </Typography>
                    </Box>

                    {chips.length > 0 && (
                      <Box
                        sx={{
                          display: "flex",
                          gap: 1,
                          flexWrap: "wrap",
                          my: 1,
                        }}
                      >
                        {chips.map(chip => (
                          <Chip
                            key={`${row.id}-${chip.key}`}
                            label={`${chip.key}: ${chip.value}`}
                            size="small"
                            color="primary"
                            variant="outlined"
                          />
                        ))}
                      </Box>
                    )}

                    {secondary.length > 0 && (
                      <Typography variant="body2" color="text.secondary">
                        {secondary
                          .map(([key, value]) => `${key}: ${String(value)}`)
                          .join(" • ")}
                      </Typography>
                    )}
                  </Box>
                </ListItem>
                <Divider component="li" />
              </Box>
            );
          })}
        </List>
      )}
    </Box>
  );
};

export default AdminResourceList;
