import React, { useEffect, useMemo, useState } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import styled from 'styled-components';
import toast from 'react-hot-toast';
import {
  DndContext,
  DragOverlay,
  PointerSensor,
  useSensor,
  useSensors,
  type DragEndEvent,
} from '@dnd-kit/core';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { Button, Input, Select } from '@/shared/components/ui';
import { PanelLoadingState, PanelEmpty } from '@/shared/components/ui/PageState';
import { ContentPanel } from '@/shared/components/layout/ContentPanel';
import { ROUTES } from '@/shared/constants/routes';
import { useLocale } from '@/app/providers/LocaleProvider';
import { ProjectPageShell } from '@/features/projects/components/ProjectPageShell';
import { useProject } from '@/features/projects/hooks/useProject';
import { useProjectPermissions } from '@/features/projects/hooks/useProjectPermissions';
import { ProjectFilterPanel } from '@/features/projects/components/ProjectFilterPanel';
import { BoardColumn } from '@/features/projects/components/BoardColumn';
import { BoardCard } from '@/features/projects/components/BoardCard';
import { BoardScroll } from '@/features/projects/components/projectsLayout';
import {
  BoardDependencyOverrideModal,
  type DependencyBlocker,
} from '@/features/projects/components/BoardDependencyOverrideModal';
import { boardQueryKey, useProjectBoard } from '@/features/projects/hooks/useProjectBoard';
import { useProjectRealtime } from '@/features/projects/hooks/useProjectRealtime';
import { moveBoardTicket } from '@/features/projects/services/projectService';
import type { BoardTicket, SprintBoardColumnKey } from '@/features/projects/types/project.types';
import {
  extractApiErrorContext,
  extractApiErrorMessage,
  isAxiosErrorWithResponse,
} from '@/shared/utils/apiErrors';

const BoardTitle = styled.h2`
  margin: 0 0 ${({ theme }) => theme.spacing[1]};
  font-size: ${({ theme }) => theme.typography.fontSize.lg};
  font-weight: ${({ theme }) => theme.typography.fontWeight.semibold};
  color: ${({ theme }) => theme.colors.text.primary};
`;

const BoardHint = styled.p`
  margin: 0;
  font-size: ${({ theme }) => theme.typography.fontSize.sm};
  color: ${({ theme }) => theme.colors.text.secondary};
`;

type PendingMove = {
  ticketId: string;
  kanban_column: SprintBoardColumnKey;
  ticket_status_id?: string;
};

const columnLabel = (
  key: SprintBoardColumnKey,
  apiLabel: string,
  t: (key: string) => string,
): string => t(`projects:board.columns.${key}`) || apiLabel;

const EmptyActions = styled.div`
  display: flex;
  flex-wrap: wrap;
  gap: ${({ theme }) => theme.spacing[3]};
  margin-top: ${({ theme }) => theme.spacing[4]};
`;

const ProjectBoardPage: React.FC = () => {
  const { id, sprintId: sprintIdFromRoute } = useParams<{ id: string; sprintId?: string }>();
  const navigate = useNavigate();
  const { t } = useLocale();
  const { data: project } = useProject(id);
  const { readOnly } = useProjectPermissions(project);
  const boardDragEnabled = !readOnly;
  const [sprintId, setSprintId] = useState(sprintIdFromRoute ?? '');
  const [search, setSearch] = useState('');
  const [assigneeId, setAssigneeId] = useState('');
  const [statusId, setStatusId] = useState('');
  const [activeCard, setActiveCard] = useState<BoardTicket | null>(null);
  const [depBlockers, setDepBlockers] = useState<DependencyBlocker[]>([]);
  const [depModalOpen, setDepModalOpen] = useState(false);
  const [pendingMove, setPendingMove] = useState<PendingMove | null>(null);
  const queryClient = useQueryClient();

  const filters = useMemo(
    () => ({
      sprint_id: sprintId || undefined,
      search: search || undefined,
      assignee_id: assigneeId || undefined,
      ticket_status_id: statusId || undefined,
    }),
    [sprintId, search, assigneeId, statusId],
  );

  const { data: board, isLoading } = useProjectBoard(id, filters);
  useProjectRealtime(id, { ticketMoved: true });

  useEffect(() => {
    if (sprintIdFromRoute) {
      setSprintId(sprintIdFromRoute);
      return;
    }
    if (!sprintId && board?.active_sprint_id) {
      setSprintId(board.active_sprint_id);
    }
  }, [sprintIdFromRoute, board?.active_sprint_id, sprintId]);

  const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 6 } }));
  const depMode = board?.dependency_completion_mode ?? 'require_override';

  const moveMutation = useMutation({
    mutationFn: (payload: {
      ticketId: string;
      kanban_column?: string;
      ticket_status_id?: string;
      sprint_id?: string | null;
      dependency_override_reason?: string;
    }) =>
      moveBoardTicket(id!, payload.ticketId, {
        kanban_column: payload.kanban_column,
        ticket_status_id: payload.ticket_status_id,
        sprint_id: payload.sprint_id ?? undefined,
        dependency_override_reason: payload.dependency_override_reason,
      }),
    onSuccess: () => {
      setDepModalOpen(false);
      setPendingMove(null);
      setDepBlockers([]);
      void queryClient.invalidateQueries({ queryKey: boardQueryKey(id!, filters) });
    },
    onError: (error, variables) => {
      if (!isAxiosErrorWithResponse(error)) {
        toast.error(t('projects:states.error'));
        return;
      }
      const ctx = extractApiErrorContext(error.response.data);
      const isDone = variables.kanban_column === 'done';
      if (isDone && ctx?.requires_override && Array.isArray(ctx.blockers) && ctx.blockers.length > 0) {
        setDepBlockers(ctx.blockers);
        setPendingMove({
          ticketId: variables.ticketId,
          kanban_column: 'done',
          ticket_status_id: variables.ticket_status_id,
        });
        setDepModalOpen(true);
        return;
      }
      if (isDone && depMode === 'warn') {
        toast.error(
          extractApiErrorMessage(error.response.data, t('projects:board.depWarn')) ??
            t('projects:board.depWarn'),
        );
        return;
      }
      toast.error(
        extractApiErrorMessage(error.response.data, t('projects:states.error')) ??
          t('projects:states.error'),
      );
    },
  });

  const executeMove = (
    ticketId: string,
    columnKey: SprintBoardColumnKey,
    ticketStatusId?: string,
    overrideReason?: string,
  ) => {
    const ticket = board?.columns.flatMap((c) => c.tickets).find((item) => item.id === ticketId);
    if (
      columnKey === 'done' &&
      depMode === 'warn' &&
      !overrideReason &&
      (ticket?.dependency_count ?? 0) > 0
    ) {
      const proceed = window.confirm(t('projects:board.depWarnConfirm'));
      if (!proceed) {
        return;
      }
    }
    moveMutation.mutate({
      ticketId,
      kanban_column: columnKey,
      ticket_status_id: ticketStatusId,
      sprint_id: sprintId || undefined,
      dependency_override_reason: overrideReason,
    });
  };

  const onDragEnd = (event: DragEndEvent) => {
    if (!boardDragEnabled) return;
    setActiveCard(null);
    const { active, over } = event;
    if (!over || !id) return;

    const ticketId = String(active.id);
    const overId = String(over.id);
    if (overId.startsWith('col:')) {
      const columnKey = overId.replace('col:', '') as SprintBoardColumnKey;
      const column = board?.columns.find((c) => c.key === columnKey);
      executeMove(ticketId, columnKey, column?.ticket_status_id ?? undefined);
    }
  };

  const sprintOptions = [
    { value: '', label: t('projects:board.allSprints') },
    ...(board?.sprints ?? []).map((s) => ({
      value: s.id,
      label: s.status === 'active' ? `${s.name} (${t('projects:board.activeSprint')})` : s.name,
    })),
  ];

  const statusOptions = [
    { value: '', label: t('projects:board.statusFilter') },
    ...(board?.columns ?? []).map((c) => ({
      value: c.ticket_status_id ?? '',
      label: columnLabel(c.key, c.label, t),
    })),
  ];

  const displayColumns = (board?.columns ?? []).map((col) => ({
    ...col,
    label: columnLabel(col.key, col.label, t),
  }));

  const hasActiveSprint = Boolean(board?.active_sprint_id || sprintId);
  const showBoardEmpty = !isLoading && board && !hasActiveSprint;

  return (
    <ProjectPageShell projectId={id}>
      {() => (
        <>
          <div>
            <BoardTitle>{t('projects:nav.board')}</BoardTitle>
            <BoardHint>{t('projects:board.subtitleSimple')}</BoardHint>
          </div>

          {showBoardEmpty ? (
            <ContentPanel variant="inset" padding="lg">
              <PanelEmpty
                title={t('projects:board.noActiveSprint')}
                hint={t('projects:board.noActiveSprintHint')}
              />
              <EmptyActions>
                <Button
                  type="button"
                  variant="primary"
                  onClick={() => id && navigate(ROUTES.PROJECT_SPRINTS(id))}
                >
                  {t('projects:sprints.createAction')}
                </Button>
                <Button
                  type="button"
                  variant="secondary"
                  onClick={() => id && navigate(ROUTES.PROJECT_BACKLOG(id))}
                >
                  {t('projects:board.goToBacklog')}
                </Button>
              </EmptyActions>
            </ContentPanel>
          ) : (
            <>
          <ProjectFilterPanel>
            <Select
              label={t('projects:board.sprintFilter')}
              value={sprintId}
              onChange={(e) => setSprintId(e.target.value)}
              options={sprintOptions}
            />
            <Input
              label={t('projects:board.search')}
              value={search}
              onChange={(e) => setSearch(e.target.value)}
              placeholder={t('projects:board.search')}
            />
            <Input
              label={t('projects:board.assigneeFilter')}
              value={assigneeId}
              onChange={(e) => setAssigneeId(e.target.value)}
            />
            <Select
              label={t('projects:board.statusFilter')}
              value={statusId}
              onChange={(e) => setStatusId(e.target.value)}
              options={statusOptions}
            />
          </ProjectFilterPanel>

          {isLoading ? (
            <PanelLoadingState label={t('projects:states.loading')} />
          ) : boardDragEnabled ? (
            <DndContext
              sensors={sensors}
              onDragStart={(e) => {
                const ticket = board?.columns
                  .flatMap((c) => c.tickets)
                  .find((ticketItem) => ticketItem.id === e.active.id);
                setActiveCard(ticket ?? null);
              }}
              onDragEnd={onDragEnd}
            >
              <BoardScroll>
                {displayColumns.map((col) => (
                  <BoardColumn key={col.key} column={col} />
                ))}
              </BoardScroll>
              <DragOverlay>
                {activeCard ? <BoardCard ticket={activeCard} isDragging /> : null}
              </DragOverlay>
            </DndContext>
          ) : (
            <BoardScroll>
              {displayColumns.map((col) => (
                <BoardColumn key={col.key} column={col} />
              ))}
            </BoardScroll>
          )}

          <BoardDependencyOverrideModal
            open={depModalOpen}
            blockers={depBlockers}
            loading={moveMutation.isPending}
            onCancel={() => {
              setDepModalOpen(false);
              setPendingMove(null);
              setDepBlockers([]);
            }}
            onConfirm={(reason) => {
              if (!pendingMove) return;
              executeMove(
                pendingMove.ticketId,
                pendingMove.kanban_column,
                pendingMove.ticket_status_id,
                reason,
              );
            }}
          />
            </>
          )}
        </>
      )}
    </ProjectPageShell>
  );
};

export default ProjectBoardPage;
