import { useState, useEffect } from "react";
import {
  Stack,
  Typography,
  FormControl,
  Accordion,
  AccordionSummary,
  AccordionDetails,
  useTheme,
  TextField,
  Autocomplete,
  TableCell,
  TableContainer,
  Table,
  TableHead,
  TableRow,
  Paper,
  TableBody,
  IconButton,
  Checkbox,
  FormControlLabel,
  Tabs,
  Tab,
  Box,
} from "@mui/material";
import { observer } from "mobx-react-lite";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import DragIndicatorIcon from "@mui/icons-material/DragIndicator";
import {
  DragDropContext,
  Droppable,
  Draggable,
  DropResult,
} from "@hello-pangea/dnd";

import {
  AnimatedCircleButton,
  authInstance,
  languageStore,
  routeStore,
  selectedCityStore,
  stationsStore,
} from "@shared";
import { EditStationModal } from "../../widgets/modals/EditStationModal";

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

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

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

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

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

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

        <AccordionDetails
          sx={{ background: theme.palette.background.paper, width: "100%" }}
        >
          <Stack gap={2} width="100%">
            <LinkedItemsContents {...props} />
          </Stack>
        </AccordionDetails>
      </Accordion>
    </>
  );
};

const LinkedItemsContentsInner = <
  T extends { id: number; name: string; [key: string]: any }
>({
  parentId,
  setItemsParent,
  fields,
  dragAllowed = false,
  type,
  onUpdate,
  disableCreation = false,
  updatedLinkedItems,
  refresh,
}: LinkedItemsProps<T>) => {
  const { language } = languageStore;

  const [position, setPosition] = useState<number>(1);
  const [allItems, setAllItems] = useState<T[]>([]);
  const [linkedItems, setLinkedItems] = useState<T[]>([]);
  const [selectedItemId, setSelectedItemId] = useState<number | null>(null);
  const [isLoading, setIsLoading] = useState<boolean>(true);
  const [error, setError] = useState<string | null>(null);
  const [isModalOpen, setIsModalOpen] = useState(false);
  const [selectedItems, setSelectedItems] = useState<Set<number>>(new Set());
  const [activeTab, setActiveTab] = useState(0);
  const [searchQuery, setSearchQuery] = useState("");
  const [isLinkingSingle, setIsLinkingSingle] = useState(false);
  const [isLinkingBulk, setIsLinkingBulk] = useState(false);
  const [detachingIds, setDetachingIds] = useState<Set<number>>(new Set());

  useEffect(() => {}, [error]);

  const parentResource = "route";
  const childResource = "station";

  const availableItems = allItems
    .filter((item) => !linkedItems.some((linked) => linked.id === item.id))
    .filter((item) => {
      const selectedCityId = selectedCityStore.selectedCityId;
      if (selectedCityId && "city_id" in item) {
        return item.city_id === selectedCityId;
      }
      return true;
    })
    .sort((a, b) => a.name.localeCompare(b.name));

  const filteredAvailableItems = availableItems.filter((item) => {
    if (!searchQuery.trim()) return true;
    const query = searchQuery.toLowerCase();
    const name = String(item.name || "").toLowerCase();
    const description = String(item.description || "").toLowerCase();
    return name.includes(query) || description.includes(query);
  });

  useEffect(() => {
    if (updatedLinkedItems) {
      setLinkedItems(updatedLinkedItems);
    }
  }, [updatedLinkedItems]);

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

  useEffect(() => {
    setPosition(linkedItems.length + 1);
  }, [linkedItems.length]);

  const getStationTransfers = (stationId: number, fallbackTransfers?: any) => {
    const { stationLists } = stationsStore;
    for (const lang of ["ru", "en", "zh"] as const) {
      const station = stationLists[lang].data.find(
        (s: any) => s.id === stationId
      );
      if (station?.transfers) {
        return station.transfers;
      }
    }
    return fallbackTransfers;
  };

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

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

    setLinkedItems(reorderedItems);

    authInstance
      .post(`/${parentResource}/${parentId}/${childResource}`, {
        stations: reorderedItems.map((item) => {
          const transfers = getStationTransfers(item.id, item.transfers);
          return {
            ...item,
            transfers: transfers || item.transfers,
          };
        }),
      })
      .catch((error) => {
        console.error("Error updating station order:", error);
        setError("Failed to update station order");
      });
  };

  useEffect(() => {
    if (parentId) {
      setIsLoading(true);
      setError(null);
      authInstance
        .get(`/${parentResource}/${parentId}/${childResource}`)
        .then((response) => {
          setLinkedItems(response?.data || []);
        })
        .catch((error) => {
          console.error("Error fetching linked items:", error);
          setError("Failed to load linked stations");
          setLinkedItems([]);
        })
        .finally(() => {
          setIsLoading(false);
        });
    }
  }, [parentId, language, refresh]);

  useEffect(() => {
    if (type === "edit") {
      setError(null);
      authInstance
        .get(`/${childResource}`)
        .then((response) => {
          setAllItems(response?.data || []);
        })
        .catch((error) => {
          console.error("Error fetching all items:", error);
          setError(null);
          setAllItems([]);
        });
    }
  }, [type]);

  const linkItem = () => {
    if (selectedItemId !== null) {
      setError(null);
      const selectedItem = allItems.find((item) => item.id === selectedItemId);
      const requestData = {
        stations: insertAtPosition(
          linkedItems.map((item) => {
            const transfers = getStationTransfers(item.id, item.transfers);
            return {
              ...item,
              transfers: transfers || item.transfers,
            };
          }),
          position,
          (() => {
            if (!selectedItem) return { id: selectedItemId };
            const transfers = getStationTransfers(
              selectedItemId,
              selectedItem.transfers
            );
            return {
              ...selectedItem,
              transfers: transfers || selectedItem.transfers,
            };
          })()
        ),
      };

      setIsLinkingSingle(true);
      authInstance
        .post(`/${parentResource}/${parentId}/${childResource}`, requestData)
        .then(() => {
          const newItem = allItems.find((item) => item.id === selectedItemId);
          if (newItem) {
            const updatedList = insertAtPosition(
              [...linkedItems],
              position,
              newItem
            );
            setLinkedItems(updatedList);
          }
          setSelectedItemId(null);
          onUpdate?.();
        })
        .catch((error) => {
          console.error("Error linking item:", error);
          setError("Failed to link station");
        })
        .finally(() => {
          setIsLinkingSingle(false);
        });
    }
  };

  const deleteItem = (itemId: number) => {
    setError(null);
    setDetachingIds((prev) => {
      const next = new Set(prev);
      next.add(itemId);
      return next;
    });
    authInstance
      .delete(`/${parentResource}/${parentId}/${childResource}`, {
        data: { [`${childResource}_id`]: itemId },
      })
      .then(() => {
        setLinkedItems(linkedItems.filter((item) => item.id !== itemId));
        onUpdate?.();
      })
      .catch((error) => {
        console.error("Error deleting item:", error);
        setError("Failed to delete station");
      })
      .finally(() => {
        setDetachingIds((prev) => {
          const next = new Set(prev);
          next.delete(itemId);
          return next;
        });
      });
  };

  const handleStationClick = (item: T) => {
    routeStore.setSelectedStationId(item.id);
    setIsModalOpen(true);
  };

  const handleCloseModal = () => {
    setIsModalOpen(false);
  };

  const handleCheckboxChange = (itemId: number) => {
    const newSelected = new Set(selectedItems);
    if (newSelected.has(itemId)) {
      newSelected.delete(itemId);
    } else {
      newSelected.add(itemId);
    }
    setSelectedItems(newSelected);
  };

  const handleBulkLink = () => {
    if (selectedItems.size === 0) return;

    setError(null);
    setIsLinkingBulk(true);
    const selectedStations = Array.from(selectedItems).map((id) => {
      const item = allItems.find((item) => item.id === id);
      if (!item) return { id };
      const transfers = getStationTransfers(id, item.transfers);
      return {
        ...item,
        transfers: transfers || item.transfers,
      };
    });
    const requestData = {
      stations: [
        ...linkedItems.map((item) => {
          const transfers = getStationTransfers(item.id, item.transfers);
          return {
            ...item,
            transfers: transfers || item.transfers,
          };
        }),
        ...selectedStations,
      ],
    };

    authInstance
      .post(`/${parentResource}/${parentId}/${childResource}`, requestData)
      .then(() => {
        const newItems = allItems.filter((item) => selectedItems.has(item.id));
        setLinkedItems([...linkedItems, ...newItems]);
        setSelectedItems(new Set());
        onUpdate?.();
      })
      .catch((error) => {
        console.error("Error linking items:", error);
        setError("Failed to link stations");
      })
      .finally(() => {
        setIsLinkingBulk(false);
      });
  };

  return (
    <>
      {linkedItems?.length > 0 && (
        <DragDropContext onDragEnd={onDragEnd}>
          <TableContainer component={Paper} sx={{ width: "100%" }}>
            <Table sx={{ width: "100%" }}>
              <TableHead>
                <TableRow>
                  {type === "edit" && dragAllowed && (
                    <TableCell width="40px"></TableCell>
                  )}
                  <TableCell key="id" width="60px">
                    №
                  </TableCell>
                  {fields.map((field) => (
                    <TableCell key={String(field.data)}>
                      {field.label}
                    </TableCell>
                  ))}
                  {type === "edit" && (
                    <TableCell width="120px">Действие</TableCell>
                  )}
                </TableRow>
              </TableHead>

              <Droppable
                droppableId="droppable-stations"
                isDropDisabled={type !== "edit" || !dragAllowed}
              >
                {(provided) => (
                  <TableBody
                    ref={provided.innerRef}
                    {...provided.droppableProps}
                  >
                    {linkedItems.map((item, index) => (
                      <Draggable
                        key={item.id}
                        draggableId={"station-" + String(item.id)}
                        index={index}
                        isDragDisabled={type !== "edit" || !dragAllowed}
                      >
                        {(provided) => (
                          <TableRow
                            sx={{ cursor: "pointer" }}
                            ref={provided.innerRef}
                            {...provided.draggableProps}
                            hover
                            onClick={() => handleStationClick(item)}
                          >
                            {type === "edit" && dragAllowed && (
                              <TableCell {...provided.dragHandleProps}>
                                <IconButton size="small">
                                  <DragIndicatorIcon />
                                </IconButton>
                              </TableCell>
                            )}
                            <TableCell>{index + 1}</TableCell>
                            {fields.map((field, idx) => (
                              <TableCell key={String(field.data) + String(idx)}>
                                {field.render
                                  ? field.render(item[field.data])
                                  : item[field.data]}
                              </TableCell>
                            ))}
                            {type === "edit" && (
                              <TableCell>
                                <AnimatedCircleButton
                                  variant="outlined"
                                  color="error"
                                  size="small"
                                  onClick={(e) => {
                                    e.stopPropagation();
                                    deleteItem(item.id);
                                  }}
                                  disabled={detachingIds.has(item.id)}
                                  loading={detachingIds.has(item.id)}
                                >
                                  Отвязать
                                </AnimatedCircleButton>
                              </TableCell>
                            )}
                          </TableRow>
                        )}
                      </Draggable>
                    ))}
                    {provided.placeholder}
                  </TableBody>
                )}
              </Droppable>
            </Table>
          </TableContainer>
        </DragDropContext>
      )}

      {linkedItems.length === 0 && !isLoading && (
        <Typography color="textSecondary" textAlign="center" py={2}>
          Остановки не найдены
        </Typography>
      )}

      {type === "edit" && !disableCreation && (
        <Stack gap={2} mt={2}>
          <Typography variant="subtitle1">Добавить остановки</Typography>

          <Tabs
            value={activeTab}
            onChange={(_, newValue) => setActiveTab(newValue)}
          >
            <Tab label="По одной" />
            <Tab label="Массово" />
          </Tabs>

          <Box sx={{ mt: 2 }}>
            {activeTab === 0 && (
              <Stack gap={2}>
                <Autocomplete
                  fullWidth
                  value={
                    availableItems?.find(
                      (item) => item.id === selectedItemId
                    ) || null
                  }
                  onChange={(_, newValue) =>
                    setSelectedItemId(newValue?.id || null)
                  }
                  options={availableItems}
                  getOptionLabel={(item) => String(item.name)}
                  renderInput={(params) => (
                    <TextField
                      {...params}
                      label="Выберите остановку"
                      placeholder="Введите название или описание остановки..."
                      fullWidth
                    />
                  )}
                  isOptionEqualToValue={(option, value) =>
                    option.id === value?.id
                  }
                  filterOptions={(options, { inputValue }) => {
                    if (!inputValue.trim()) return options;
                    const query = inputValue.toLowerCase();
                    return options.filter((option) => {
                      const name = String(option.name || "").toLowerCase();
                      const description = String(
                        option.description || ""
                      ).toLowerCase();
                      return (
                        name.includes(query) || description.includes(query)
                      );
                    });
                  }}
                  renderOption={(props, option) => (
                    <li {...props} key={option.id}>
                      <div className="flex justify-between items-center w-full">
                        <p>{String(option.name)}</p>
                        <p className="text-xs text-gray-500 max-w-[300px] mr-4 truncate">
                          {String(option.description)}
                        </p>
                      </div>
                    </li>
                  )}
                />

                <FormControl fullWidth>
                  <TextField
                    type="number"
                    label="Позиция добавляемой остановки"
                    value={position}
                    onChange={(e) => {
                      const newValue = Math.max(1, Number(e.target.value));
                      setPosition(
                        newValue > linkedItems.length + 1
                          ? linkedItems.length + 1
                          : newValue
                      );
                    }}
                    InputProps={{
                      inputProps: { min: 1, max: linkedItems.length + 1 },
                    }}
                    fullWidth
                  />
                </FormControl>

                <AnimatedCircleButton
                  variant="contained"
                  onClick={linkItem}
                  disabled={!selectedItemId || isLinkingSingle}
                  loading={isLinkingSingle}
                  sx={{ alignSelf: "flex-start" }}
                >
                  Добавить
                </AnimatedCircleButton>
              </Stack>
            )}

            {activeTab === 1 && (
              <Stack gap={2}>
                {/* Поле поиска */}
                <TextField
                  fullWidth
                  label="Поиск остановок"
                  value={searchQuery}
                  onChange={(e) => setSearchQuery(e.target.value)}
                  placeholder="Введите название остановки..."
                  size="small"
                  sx={{ mb: 1 }}
                />

                {/* Список доступных остановок с чекбоксами */}
                <Paper sx={{ maxHeight: 300, overflow: "auto", p: 2 }}>
                  <Stack gap={1}>
                    {filteredAvailableItems.map((item) => (
                      <FormControlLabel
                        key={item.id}
                        control={
                          <Checkbox
                            checked={selectedItems.has(item.id)}
                            onChange={() => handleCheckboxChange(item.id)}
                            size="small"
                          />
                        }
                        label={
                          <div className="flex justify-between items-center w-full gap-10">
                            <p>{String(item.name)}</p>
                            <p className="text-xs text-gray-500 max-w-[300px] truncate text-ellipsis">
                              {String(item.description)}
                            </p>
                          </div>
                        }
                        sx={{
                          margin: 0,
                          "& .MuiFormControlLabel-label": {
                            fontSize: "0.875rem",
                          },
                        }}
                      />
                    ))}
                    {filteredAvailableItems.length === 0 && (
                      <Typography
                        color="textSecondary"
                        textAlign="center"
                        py={1}
                      >
                        {searchQuery.trim()
                          ? "Остановки не найдены"
                          : "Нет доступных остановок"}
                      </Typography>
                    )}
                  </Stack>
                </Paper>

                <AnimatedCircleButton
                  variant="contained"
                  onClick={handleBulkLink}
                  disabled={selectedItems.size === 0 || isLinkingBulk}
                  loading={isLinkingBulk}
                  sx={{ alignSelf: "flex-start" }}
                >
                  Добавить выбранные ({selectedItems.size})
                </AnimatedCircleButton>
              </Stack>
            )}
          </Box>
        </Stack>
      )}
      <EditStationModal open={isModalOpen} onClose={handleCloseModal} />
    </>
  );
};

export const LinkedItemsContents = observer(
  LinkedItemsContentsInner
) as typeof LinkedItemsContentsInner;
