import { useState, useEffect } from "react";
import { languageStore } from "../store/LanguageStore";
import {
  Stack,
  Typography,
  Button,
  FormControl,
  Accordion,
  AccordionSummary,
  AccordionDetails,
  useTheme,
  TextField,
  Autocomplete,
  TableCell,
  TableContainer,
  Table,
  TableHead,
  TableRow,
  Paper,
  TableBody,
  IconButton,
} from "@mui/material";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import DragIndicatorIcon from "@mui/icons-material/DragIndicator";
import { axiosInstance } from "../providers/data";

import { DragDropContext, Droppable, Draggable } from "@hello-pangea/dnd";

import { articleStore } from "../store/ArticleStore";
import { ArticleEditModal } from "./modals/ArticleEditModal";
import { StationEditModal } from "./modals/StationEditModal";
import { stationStore } from "../store/StationStore";

function insertAtPosition<T>(arr: T[], pos: number, value: T): T[] {
  const index = pos - 1;
  if (index >= arr.length) {
    arr.push(value);
  } else {
    arr.splice(index, 0, value);
  }
  return arr;
}

type Field<T> = {
  label: string;
  data: keyof T;
  render?: (value: any) => React.ReactNode;
};

type ExtraFieldConfig = {
  type: "number";
  label: string;
  minValue: number;
  maxValue: (linkedItems: any[]) => number;
};

type LinkedItemsProps<T> = {
  parentId: string | number;
  parentResource: string;
  childResource: string;
  fields: Field<T>[];
  setItemsParent?: (items: T[]) => void;
  title: string;
  type: "show" | "edit";
  extraField?: ExtraFieldConfig;
  dragAllowed?: boolean;
  onSave?: (items: T[]) => void;
  onUpdate?: () => void;
  dontRecurse?: boolean;
  disableCreation?: boolean;
  updatedLinkedItems?: T[];
  refresh?: number;
};

const reorder = (list: any[], startIndex: number, endIndex: number) => {
  const result = Array.from(list);
  const [removed] = result.splice(startIndex, 1);
  result.splice(endIndex, 0, removed);
  return result;
};

export const LinkedItems = <T extends { id: number; [key: string]: any }>(
  props: LinkedItemsProps<T>
) => {
  const theme = useTheme();

  return (
    <>
      <Accordion>
        <AccordionSummary
          expandIcon={<ExpandMoreIcon />}
          sx={{
            background: theme.palette.background.paper,
            borderBottom: `1px solid ${theme.palette.divider}`,
          }}
        >
          <Typography variant="subtitle1" fontWeight="bold">
            Привязанные {props.title}
          </Typography>
        </AccordionSummary>

        <AccordionDetails sx={{ background: theme.palette.background.paper }}>
          <Stack gap={2}>
            <LinkedItemsContents {...props} />
          </Stack>
        </AccordionDetails>
      </Accordion>

      {!props.dontRecurse && (
        <>
          <ArticleEditModal />
          <StationEditModal />
        </>
      )}
    </>
  );
};

export const LinkedItemsContents = <
  T extends { id: number; [key: string]: any }
>({
  parentId,
  parentResource,
  childResource,
  setItemsParent,
  fields,
  title,
  dragAllowed = false,
  type,
  onUpdate,
  disableCreation = false,
  updatedLinkedItems,
  refresh,
}: LinkedItemsProps<T>) => {
  const { language } = languageStore;
  const { setArticleModalOpenAction, setArticleIdAction } = articleStore;
  const { setStationModalOpenAction, setStationIdAction, setRouteIdAction } =
    stationStore;
  const [position, setPosition] = useState<number>(1);
  const [items, setItems] = useState<T[]>([]);
  const [linkedItems, setLinkedItems] = useState<T[]>([]);
  const [selectedItemId, setSelectedItemId] = useState<number | null>(null);
  const [pageNum, setPageNum] = useState<number>(1);
  const [isLoading, setIsLoading] = useState<boolean>(true);
  const [mediaOrder, setMediaOrder] = useState<number>(1);

  let availableItems = items.filter(
    (item) => !linkedItems.some((linked) => linked.id === item.id)
  );
  useEffect(() => {
    if (childResource == "station") {
      availableItems = availableItems.sort((a, b) =>
        a.name.localeCompare(b.name)
      );
    }
  }, [childResource, availableItems]);

  useEffect(() => {
    if (!updatedLinkedItems?.length) return;
    setLinkedItems(updatedLinkedItems);
  }, [updatedLinkedItems]);

  useEffect(() => {
    setItemsParent?.(linkedItems);
  }, [linkedItems, setItemsParent]);

  const onDragEnd = (result: any) => {
    if (!result.destination) return;

    const reorderedItems = reorder(
      linkedItems,
      result.source.index,
      result.destination.index
    );

    setLinkedItems(reorderedItems);

    if (parentResource === "sight" && childResource === "article") {
      axiosInstance.post(
        `${import.meta.env.VITE_KRBL_API}/sight/${parentId}/article/order`,
        {
          articles: reorderedItems.map((item) => ({
            id: item.id,
          })),
        }
      );
    } else {
      axiosInstance.post(
        `${import.meta.env.VITE_KRBL_API}/route/${parentId}/station`,
        {
          stations: reorderedItems.map((item) => ({
            id: item.id,
          })),
        }
      );
    }
  };

  useEffect(() => {
    if (parentId) {
      axiosInstance
        .get(
          `${
            import.meta.env.VITE_KRBL_API
          }/${parentResource}/${parentId}/${childResource}`
        )
        .then((response) => {
          setLinkedItems(response?.data || []);
        })
        .catch(() => {
          setLinkedItems([]);
        });
    }
  }, [parentId, parentResource, childResource, language, refresh]);

  useEffect(() => {
    if (type === "edit") {
      axiosInstance
        .get(`${import.meta.env.VITE_KRBL_API}/${childResource}/`)
        .then((response) => {
          setItems(response?.data || []);
          setIsLoading(false);
        })
        .catch(() => {
          setItems([]);
          setIsLoading(false);
        });
    } else {
      setIsLoading(false);
    }
  }, [childResource, type]);

  useEffect(() => {
    if (childResource === "article" && parentResource === "sight") {
      setPageNum(linkedItems.length + 1);
    }
  }, [linkedItems, childResource, parentResource]);

  const linkItem = () => {
    if (selectedItemId !== null) {
      const requestData =
        childResource === "article"
          ? {
              [`${childResource}_id`]: selectedItemId,
              page_num: pageNum,
            }
          : childResource === "media"
          ? {
              [`${childResource}_id`]: selectedItemId,
              media_order: mediaOrder,
            }
          : childResource === "station"
          ? {
              stations: insertAtPosition(
                linkedItems.map((item) => ({
                  id: item.id,
                })),
                position,
                {
                  id: selectedItemId,
                }
              ),
            }
          : { [`${childResource}_id`]: selectedItemId };

      axiosInstance
        .post(
          `${
            import.meta.env.VITE_KRBL_API
          }/${parentResource}/${parentId}/${childResource}`,
          requestData
        )
        .then(() => {
          axiosInstance
            .get(
              `${
                import.meta.env.VITE_KRBL_API
              }/${parentResource}/${parentId}/${childResource}`
            )
            .then((response) => {
              setLinkedItems(response?.data || []);
              setSelectedItemId(null);
              if (childResource === "article") {
                setPageNum(pageNum + 1);
              }
              onUpdate?.();
            });
        })
        .catch((error) => {
          console.error("Error linking item:", error);
        });
    }
  };

  const deleteItem = (itemId: number) => {
    axiosInstance
      .delete(
        `${
          import.meta.env.VITE_KRBL_API
        }/${parentResource}/${parentId}/${childResource}`,
        {
          data: { [`${childResource}_id`]: itemId },
        }
      )
      .then(() => {
        setLinkedItems((prev) => prev.filter((item) => item.id !== itemId));
        onUpdate?.();
      })
      .catch((error) => {
        console.error("Error unlinking item:", error);
      });
  };

  return (
    <>
      {linkedItems?.length > 0 && (
        <DragDropContext onDragEnd={onDragEnd}>
          <TableContainer component={Paper}>
            <Table>
              <TableHead>
                <TableRow>
                  {type === "edit" && dragAllowed && (
                    <TableCell width="40px"></TableCell>
                  )}
                  <TableCell key="id">№</TableCell>
                  {fields.map((field) => (
                    <TableCell key={String(field.data)}>
                      {field.label}
                    </TableCell>
                  ))}

                  {type === "edit" && (
                    <TableCell width="120px">Действие</TableCell>
                  )}
                </TableRow>
              </TableHead>

              <Droppable
                droppableId="droppable"
                isDropDisabled={type !== "edit" || !dragAllowed}
              >
                {(provided) => (
                  <TableBody
                    ref={provided.innerRef}
                    {...provided.droppableProps}
                  >
                    {linkedItems.map((item, index) => (
                      <Draggable
                        key={item.id}
                        draggableId={"q" + String(item.id)}
                        index={index}
                        isDragDisabled={type !== "edit" || !dragAllowed}
                      >
                        {(provided) => (
                          <TableRow
                            sx={{
                              cursor:
                                childResource === "article"
                                  ? "pointer"
                                  : "default",
                            }}
                            onClick={() => {
                              if (
                                childResource === "article" &&
                                type === "edit"
                              ) {
                                setArticleModalOpenAction(true);
                                setArticleIdAction(item.id);
                              }
                              if (
                                childResource === "station" &&
                                type === "edit"
                              ) {
                                setStationModalOpenAction(true);
                                setStationIdAction(item.id);
                                setRouteIdAction(Number(parentId));
                              }
                            }}
                            ref={provided.innerRef}
                            {...provided.draggableProps}
                            {...provided.dragHandleProps}
                            hover
                          >
                            {type === "edit" && dragAllowed && (
                              <TableCell {...provided.dragHandleProps}>
                                <IconButton size="small">
                                  <DragIndicatorIcon />
                                </IconButton>
                              </TableCell>
                            )}
                            <TableCell key={String(item.id)}>
                              {index + 1}
                            </TableCell>
                            {fields.map((field, index) => (
                              <TableCell
                                key={String(field.data) + String(index)}
                              >
                                {field.render
                                  ? field.render(item[field.data])
                                  : item[field.data]}
                              </TableCell>
                            ))}

                            {type === "edit" && (
                              <TableCell>
                                <Button
                                  variant="outlined"
                                  color="error"
                                  size="small"
                                  onClick={(e) => {
                                    e.stopPropagation();
                                    deleteItem(item.id);
                                  }}
                                >
                                  Отвязать
                                </Button>
                              </TableCell>
                            )}
                          </TableRow>
                        )}
                      </Draggable>
                    ))}

                    {provided.placeholder}
                  </TableBody>
                )}
              </Droppable>
            </Table>
          </TableContainer>
        </DragDropContext>
      )}

      {linkedItems.length === 0 && !isLoading && (
        <Typography color="textSecondary" textAlign="center" py={2}>
          {title} не найдены
        </Typography>
      )}

      {type === "edit" && !disableCreation && (
        <Stack gap={2} mt={2}>
          <Typography variant="subtitle1">Добавить {title}</Typography>
          <Autocomplete
            fullWidth
            value={
              availableItems?.find((item) => item.id === selectedItemId) || null
            }
            onChange={(_, newValue) => setSelectedItemId(newValue?.id || null)}
            options={availableItems}
            getOptionLabel={(item) => String(item[fields[0].data])}
            renderInput={(params) => (
              <TextField {...params} label={`Выберите ${title}`} fullWidth />
            )}
            isOptionEqualToValue={(option, value) => option.id === value?.id}
            filterOptions={(options, { inputValue }) => {
              const searchWords = inputValue
                .toLowerCase()
                .split(" ")
                .filter((word) => word.length > 0);
              return options.filter((option) => {
                const optionWords = String(option[fields[0].data])
                  .toLowerCase()
                  .split(" ");
                return searchWords.every((searchWord) =>
                  optionWords.some((word) => word.startsWith(searchWord))
                );
              });
            }}
            renderOption={(props, option) => (
              <li {...props} key={option.id}>
                {String(option[fields[0].data])}
              </li>
            )}
          />

          {/* {childResource === "article" && (
            <FormControl fullWidth>
              <TextField
                type="number"
                label="Позиция добавляемой статьи"
                name="page_num"
                value={pageNum}
                onChange={(e) => {
                  const newValue = Number(e.target.value);
                  const minValue = linkedItems.length + 1;
                  setPageNum(newValue < minValue ? minValue : newValue);
                }}
                fullWidth
                InputLabelProps={{ shrink: true }}
              />
            </FormControl>
          )} */}

          {childResource === "media" && (
            <FormControl fullWidth>
              <TextField
                type="text"
                label="Порядок отображения медиа"
                value={mediaOrder}
                onChange={(e) => {
                  const rawValue = e.target.value;
                  const numericValue = Number(rawValue);
                  const maxValue = linkedItems.length + 1;

                  if (isNaN(numericValue)) {
                    return;
                  } else {
                    let newValue = numericValue;

                    if (newValue < 10 && newValue > 0) {
                      setMediaOrder(numericValue);
                    }

                    if (newValue > maxValue) {
                      newValue = maxValue;
                    }

                    setMediaOrder(newValue);
                  }
                }}
                fullWidth
                InputLabelProps={{ shrink: true }}
              />
            </FormControl>
          )}

          <Button
            variant="contained"
            onClick={linkItem}
            disabled={
              !selectedItemId || (childResource == "media" && mediaOrder == 0)
            }
            sx={{ alignSelf: "flex-start" }}
          >
            Добавить
          </Button>
          {childResource == "station" && (
            <TextField
              type="text"
              label="Позиция добавляемой остановки к маршруту"
              value={position}
              onChange={(e) => {
                const newValue = Number(e.target.value);
                setPosition(
                  newValue > linkedItems.length + 1
                    ? linkedItems.length + 1
                    : newValue
                );
              }}
            ></TextField>
          )}
        </Stack>
      )}
    </>
  );
};
