import { useMemo, useState, Fragment, useCallback } from 'react';
import {
  useReactTable,
  getCoreRowModel,
  flexRender,
} from '@tanstack/react-table';
import {
  DndContext,
  closestCenter,
  KeyboardSensor,
  PointerSensor,
  useSensor,
  useSensors,
  DragOverlay,
} from '@dnd-kit/core';
import type { DragEndEvent, DragStartEvent } from '@dnd-kit/core';
import {
  SortableContext,
  sortableKeyboardCoordinates,
  verticalListSortingStrategy,
} from '@dnd-kit/sortable';
import { restrictToVerticalAxis } from '@dnd-kit/modifiers';
import {
  Table,
  TableBody,
  TableCell,
  TableContainer,
  TableHead,
  TableRow,
  Paper,
  TableSortLabel,
  Skeleton,
  Box,
  Typography,
  TablePagination,
  Collapse,
} from '@mui/material';
import { Inbox } from '@mui/icons-material';
import { ColumnVisibility } from './ColumnVisibility';
import {
  useIdeasQuery,
  useDeleteIdea,
  useReorderIdeas,
  useUpdateIdea,
} from '../../hooks/useIdeas';
import {
  useEstimateIdea,
  useGenerateSpecification,
  useSpecificationHistory,
  useDeleteSpecificationHistoryItem,
  useRestoreSpecificationFromHistory,
} from '../../hooks/useAi';
import { useIdeasStore } from '../../store/ideas';
import { createColumns } from './columns';
import { DraggableRow } from './DraggableRow';
import { CommentsPanel } from '../CommentsPanel';
import { AiEstimateModal } from '../AiEstimateModal';
import { SpecificationModal } from '../SpecificationModal';
import { IdeaDetailModal } from '../IdeaDetailModal';
import type { EstimateResult } from '../../services/ai';
import type { Idea, UpdateIdeaDto } from '../../types/idea';

const SKELETON_COLUMNS_COUNT = 13;

export function IdeasTable() {
  const { data, isLoading, isError } = useIdeasQuery();
  const deleteIdea = useDeleteIdea();
  const reorderIdeas = useReorderIdeas();
  const updateIdea = useUpdateIdea();
  const estimateIdea = useEstimateIdea();
  const generateSpecification = useGenerateSpecification();
  const deleteSpecificationHistoryItem = useDeleteSpecificationHistoryItem();
  const restoreSpecificationFromHistory = useRestoreSpecificationFromHistory();
  const { sorting, setSorting, pagination, setPage, setLimit } =
    useIdeasStore();

  // ID активно перетаскиваемого элемента
  const [activeId, setActiveId] = useState<string | null>(null);
  // ID идеи с раскрытыми комментариями
  const [expandedId, setExpandedId] = useState<string | null>(null);
  // AI-оценка
  const [estimatingId, setEstimatingId] = useState<string | null>(null);
  const [estimateModalOpen, setEstimateModalOpen] = useState(false);
  const [estimateResult, setEstimateResult] = useState<EstimateResult | null>(
    null,
  );
  // ТЗ (спецификация)
  const [specificationModalOpen, setSpecificationModalOpen] = useState(false);
  const [specificationIdea, setSpecificationIdea] = useState<Idea | null>(null);
  const [generatedSpecification, setGeneratedSpecification] = useState<
    string | null
  >(null);
  const [generatingSpecificationId, setGeneratingSpecificationId] = useState<
    string | null
  >(null);
  // Детальный просмотр идеи
  const [detailModalOpen, setDetailModalOpen] = useState(false);
  const [detailIdea, setDetailIdea] = useState<Idea | null>(null);

  // История ТЗ
  const specificationHistory = useSpecificationHistory(
    specificationIdea?.id ?? null,
  );

  const handleToggleComments = (id: string) => {
    setExpandedId((prev) => (prev === id ? null : id));
  };

  const handleEstimate = useCallback(
    (id: string) => {
      setEstimatingId(id);
      setEstimateModalOpen(true);
      setEstimateResult(null);
      estimateIdea.mutate(id, {
        onSuccess: (result) => {
          setEstimateResult(result);
          setEstimatingId(null);
        },
        onError: () => {
          setEstimatingId(null);
        },
      });
    },
    [estimateIdea],
  );

  const handleCloseEstimateModal = () => {
    setEstimateModalOpen(false);
    setEstimateResult(null);
  };

  const handleViewEstimate = (idea: Idea) => {
    if (!idea.estimatedHours || !idea.estimateDetails) return;

    // Показываем сохранённые результаты оценки
    setEstimateResult({
      ideaId: idea.id,
      ideaTitle: idea.title,
      totalHours: idea.estimatedHours,
      complexity: idea.complexity ?? 'medium',
      breakdown: idea.estimateDetails.breakdown,
      recommendations: idea.estimateDetails.recommendations,
      estimatedAt: idea.estimatedAt ?? new Date().toISOString(),
    });
    setEstimateModalOpen(true);
  };

  const handleSpecification = useCallback(
    (idea: Idea) => {
      setSpecificationIdea(idea);
      setSpecificationModalOpen(true);

      // Если ТЗ уже есть — показываем его
      if (idea.specification) {
        setGeneratedSpecification(idea.specification);
        return;
      }

      // Иначе генерируем
      setGeneratedSpecification(null);
      setGeneratingSpecificationId(idea.id);
      generateSpecification.mutate(idea.id, {
        onSuccess: (result) => {
          setGeneratedSpecification(result.specification);
          setGeneratingSpecificationId(null);
        },
        onError: () => {
          setGeneratingSpecificationId(null);
        },
      });
    },
    [generateSpecification],
  );

  const handleCloseSpecificationModal = () => {
    setSpecificationModalOpen(false);
    setSpecificationIdea(null);
    setGeneratedSpecification(null);
  };

  const handleSaveSpecification = (specification: string) => {
    if (!specificationIdea) return;
    updateIdea.mutate(
      { id: specificationIdea.id, dto: { specification } },
      {
        onSuccess: () => {
          setGeneratedSpecification(specification);
        },
      },
    );
  };

  const handleRegenerateSpecification = () => {
    if (!specificationIdea) return;
    setGeneratingSpecificationId(specificationIdea.id);
    generateSpecification.mutate(specificationIdea.id, {
      onSuccess: (result) => {
        setGeneratedSpecification(result.specification);
        setGeneratingSpecificationId(null);
      },
      onError: () => {
        setGeneratingSpecificationId(null);
      },
    });
  };

  const handleDeleteHistoryItem = (historyId: string) => {
    deleteSpecificationHistoryItem.mutate(historyId);
  };

  const handleRestoreFromHistory = (historyId: string) => {
    restoreSpecificationFromHistory.mutate(historyId, {
      onSuccess: (result) => {
        setGeneratedSpecification(result.specification);
      },
    });
  };

  const handleViewDetails = useCallback((idea: Idea) => {
    setDetailIdea(idea);
    setDetailModalOpen(true);
  }, []);

  const handleCloseDetailModal = () => {
    setDetailModalOpen(false);
    setDetailIdea(null);
  };

  const handleSaveDetail = (id: string, dto: UpdateIdeaDto) => {
    updateIdea.mutate(
      { id, dto },
      {
        onSuccess: () => {
          // Обновляем только те поля, которые были отправлены в dto
          // Это сохраняет specification и другие поля которые не редактировались
          setDetailIdea((prev) => {
            if (!prev) return prev;
            const updates: Partial<Idea> = {};
            (Object.keys(dto) as (keyof UpdateIdeaDto)[]).forEach((key) => {
              if (dto[key] !== undefined) {
                (updates as Record<string, unknown>)[key] = dto[key];
              }
            });
            return { ...prev, ...updates };
          });
        },
      },
    );
  };

  const handleOpenSpecificationFromDetail = (idea: Idea) => {
    handleCloseDetailModal();
    handleSpecification(idea);
  };

  const handleOpenEstimateFromDetail = (idea: Idea) => {
    handleCloseDetailModal();
    if (idea.estimatedHours) {
      handleViewEstimate(idea);
    } else {
      handleEstimate(idea.id);
    }
  };

  const columns = useMemo(
    () =>
      createColumns({
        onDelete: (id) => deleteIdea.mutate(id),
        onToggleComments: handleToggleComments,
        onEstimate: handleEstimate,
        onViewEstimate: handleViewEstimate,
        onSpecification: handleSpecification,
        onViewDetails: handleViewDetails,
        expandedId,
        estimatingId,
        generatingSpecificationId,
      }),
    [
      deleteIdea,
      expandedId,
      estimatingId,
      generatingSpecificationId,
      handleEstimate,
      handleSpecification,
      handleViewDetails,
    ],
  );

  // eslint-disable-next-line react-hooks/incompatible-library
  const table = useReactTable({
    data: data?.data ?? [],
    columns,
    getCoreRowModel: getCoreRowModel(),
    manualSorting: true,
    manualPagination: true,
    getRowId: (row) => row.id,
  });

  const sensors = useSensors(
    useSensor(PointerSensor, {
      activationConstraint: {
        distance: 8,
      },
    }),
    useSensor(KeyboardSensor, {
      coordinateGetter: sortableKeyboardCoordinates,
    }),
  );

  const handleDragStart = (event: DragStartEvent) => {
    setActiveId(event.active.id as string);
  };

  const handleDragEnd = (event: DragEndEvent) => {
    const { active, over } = event;
    setActiveId(null);

    if (over && active.id !== over.id && data?.data) {
      const oldIndex = data.data.findIndex((item) => item.id === active.id);
      const newIndex = data.data.findIndex((item) => item.id === over.id);

      if (oldIndex !== -1 && newIndex !== -1) {
        // Создаём новый порядок
        const items = [...data.data];
        const [movedItem] = items.splice(oldIndex, 1);
        items.splice(newIndex, 0, movedItem);

        // Отправляем на сервер новый порядок
        const reorderItems = items.map((item, index) => ({
          id: item.id,
          order: index,
        }));

        reorderIdeas.mutate(reorderItems);
      }
    }
  };

  const handleSort = (columnId: string) => {
    setSorting(columnId);
  };

  const handleChangePage = (_: unknown, newPage: number) => {
    setPage(newPage + 1);
  };

  const handleChangeRowsPerPage = (
    event: React.ChangeEvent<HTMLInputElement>,
  ) => {
    setLimit(parseInt(event.target.value, 10));
  };

  if (isError) {
    return (
      <Box sx={{ p: 4, textAlign: 'center' }}>
        <Typography color="error">Не удалось загрузить идеи</Typography>
      </Box>
    );
  }

  const rows = table.getRowModel().rows;
  const rowIds = rows.map((row) => row.original.id);
  const activeRow = activeId
    ? rows.find((row) => row.original.id === activeId)
    : null;

  return (
    <Paper
      sx={{ width: '100%', overflow: 'hidden' }}
      data-testid="ideas-table-container"
    >
      <Box
        sx={{
          display: 'flex',
          justifyContent: 'flex-end',
          alignItems: 'center',
          px: 2,
          py: 1,
          borderBottom: 1,
          borderColor: 'divider',
        }}
      >
        <ColumnVisibility table={table} />
      </Box>
      <DndContext
        sensors={sensors}
        collisionDetection={closestCenter}
        modifiers={[restrictToVerticalAxis]}
        onDragStart={handleDragStart}
        onDragEnd={handleDragEnd}
      >
        <TableContainer>
          <Table stickyHeader size="small" data-testid="ideas-table">
            <TableHead>
              {table.getHeaderGroups().map((headerGroup) => (
                <TableRow key={headerGroup.id}>
                  {headerGroup.headers.map((header) => (
                    <TableCell
                      key={header.id}
                      sx={{
                        fontWeight: 600,
                        backgroundColor: 'grey.100',
                        width: header.getSize(),
                      }}
                    >
                      {header.column.getCanSort() ? (
                        <TableSortLabel
                          active={sorting.sortBy === header.id}
                          direction={
                            sorting.sortBy === header.id
                              ? (sorting.sortOrder.toLowerCase() as
                                  | 'asc'
                                  | 'desc')
                              : 'asc'
                          }
                          onClick={() => handleSort(header.id)}
                        >
                          {flexRender(
                            header.column.columnDef.header,
                            header.getContext(),
                          )}
                        </TableSortLabel>
                      ) : (
                        flexRender(
                          header.column.columnDef.header,
                          header.getContext(),
                        )
                      )}
                    </TableCell>
                  ))}
                </TableRow>
              ))}
            </TableHead>
            <TableBody>
              {isLoading ? (
                Array.from({ length: 5 }).map((_, index) => (
                  <TableRow key={index}>
                    {Array.from({ length: SKELETON_COLUMNS_COUNT }).map(
                      (_, colIndex) => (
                        <TableCell key={colIndex}>
                          <Skeleton variant="text" />
                        </TableCell>
                      ),
                    )}
                  </TableRow>
                ))
              ) : rows.length === 0 ? (
                <TableRow>
                  <TableCell colSpan={SKELETON_COLUMNS_COUNT}>
                    <Box
                      sx={{
                        py: 8,
                        display: 'flex',
                        flexDirection: 'column',
                        alignItems: 'center',
                        color: 'text.secondary',
                      }}
                      data-testid="ideas-empty-state"
                    >
                      <Inbox sx={{ fontSize: 48, mb: 2, opacity: 0.5 }} />
                      <Typography variant="h6">Идей пока нет</Typography>
                      <Typography variant="body2">
                        Создайте первую идею, чтобы начать
                      </Typography>
                    </Box>
                  </TableCell>
                </TableRow>
              ) : (
                <SortableContext
                  items={rowIds}
                  strategy={verticalListSortingStrategy}
                >
                  {rows.map((row) => (
                    <Fragment key={row.id}>
                      <DraggableRow row={row} />
                      <TableRow>
                        <TableCell
                          colSpan={SKELETON_COLUMNS_COUNT}
                          sx={{
                            p: 0,
                            borderBottom:
                              expandedId === row.original.id ? 1 : 0,
                            borderColor: 'divider',
                          }}
                        >
                          <Collapse
                            in={expandedId === row.original.id}
                            unmountOnExit
                          >
                            <CommentsPanel ideaId={row.original.id} />
                          </Collapse>
                        </TableCell>
                      </TableRow>
                    </Fragment>
                  ))}
                </SortableContext>
              )}
            </TableBody>
          </Table>
        </TableContainer>
        <DragOverlay dropAnimation={null}>
          {activeRow ? (
            <Table
              size="small"
              sx={{
                backgroundColor: 'background.paper',
                boxShadow: 6,
                borderRadius: 1,
                '& td': {
                  backgroundColor: activeRow.original.color
                    ? `${activeRow.original.color}30`
                    : 'action.selected',
                },
              }}
            >
              <TableBody>
                <TableRow>
                  {activeRow.getVisibleCells().map((cell) => (
                    <TableCell
                      key={cell.id}
                      sx={{ width: cell.column.getSize() }}
                    >
                      {flexRender(
                        cell.column.columnDef.cell,
                        cell.getContext(),
                      )}
                    </TableCell>
                  ))}
                </TableRow>
              </TableBody>
            </Table>
          ) : null}
        </DragOverlay>
      </DndContext>
      {data && (
        <TablePagination
          component="div"
          count={data.meta.total}
          page={pagination.page - 1}
          rowsPerPage={pagination.limit}
          onPageChange={handleChangePage}
          onRowsPerPageChange={handleChangeRowsPerPage}
          rowsPerPageOptions={[10, 20, 50, 100]}
        />
      )}
      <AiEstimateModal
        open={estimateModalOpen}
        onClose={handleCloseEstimateModal}
        result={estimateResult}
        isLoading={estimateIdea.isPending && !estimateResult}
        error={estimateIdea.error}
      />
      <SpecificationModal
        open={specificationModalOpen}
        onClose={handleCloseSpecificationModal}
        idea={specificationIdea}
        specification={generatedSpecification}
        isLoading={generateSpecification.isPending && !generatedSpecification}
        error={generateSpecification.error}
        onSave={handleSaveSpecification}
        isSaving={updateIdea.isPending}
        onRegenerate={handleRegenerateSpecification}
        history={specificationHistory.data ?? []}
        isHistoryLoading={specificationHistory.isLoading}
        onDeleteHistoryItem={handleDeleteHistoryItem}
        onRestoreFromHistory={handleRestoreFromHistory}
        isRestoring={restoreSpecificationFromHistory.isPending}
      />
      <IdeaDetailModal
        open={detailModalOpen}
        onClose={handleCloseDetailModal}
        idea={detailIdea}
        onSave={handleSaveDetail}
        isSaving={updateIdea.isPending}
        onOpenSpecification={handleOpenSpecificationFromDetail}
        onOpenEstimate={handleOpenEstimateFromDetail}
      />
    </Paper>
  );
}
