import { useMemo } from 'react';
import {
  Box, Paper, Typography, Chip, Avatar,
} from '@mui/material';
import {
  BugReport, FiberNew, HelpOutline,
  AccessTime as AccessTimeIcon,
} from '@mui/icons-material';
import {
  DndContext,
  DragOverlay,
  PointerSensor,
  useSensor,
  useSensors,
  closestCorners,
  useDroppable,
} from '@dnd-kit/core';
import type { DragStartEvent, DragEndEvent } from '@dnd-kit/core';
import {
  SortableContext,
  verticalListSortingStrategy,
  useSortable,
} from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';
import { useState } from 'react';
import type { Issue, IssueStatusDef, IssuePriorityDef } from '../../types/issue.types';

// ── Helpers ──

const PRIO_COLORS: Record<string, string> = {
  hoch: '#d32f2f', mittel: '#ed6c02', niedrig: '#9e9e9e',
};
const MUI_THEME_COLORS: Record<string, string> = {
  default: '#9e9e9e', primary: '#1976d2', secondary: '#9c27b0',
  error: '#d32f2f', info: '#0288d1', success: '#2e7d32', warning: '#ed6c02',
};
const ICON_MAP: Record<string, JSX.Element> = {
  BugReport: <BugReport fontSize="small" />,
  FiberNew: <FiberNew fontSize="small" />,
  HelpOutline: <HelpOutline fontSize="small" />,
};

function getPrioColor(priorities: IssuePriorityDef[], key: string) {
  return priorities.find(p => p.schluessel === key)?.farbe ?? PRIO_COLORS[key] ?? '#9e9e9e';
}

function isOverdue(issue: Issue): boolean {
  if (!issue.faellig_am) return false;
  return new Date(issue.faellig_am) < new Date();
}

// ── Kanban Card ──

function KanbanCard({
  issue,
  priorities,
  onClick,
  isDragging,
}: {
  issue: Issue;
  priorities: IssuePriorityDef[];
  onClick: (id: number) => void;
  isDragging?: boolean;
}) {
  const prioColor = getPrioColor(priorities, issue.prioritaet);
  const icon = ICON_MAP[issue.typ_icon || ''] || <HelpOutline fontSize="small" />;
  const overdue = isOverdue(issue);

  return (
    <Paper
      variant="outlined"
      onClick={() => onClick(issue.id)}
      sx={{
        p: 1.5,
        cursor: 'pointer',
        borderLeft: `3px solid ${prioColor}`,
        opacity: isDragging ? 0.5 : 1,
        '&:hover': { bgcolor: 'action.hover' },
        display: 'flex',
        flexDirection: 'column',
        gap: 0.5,
      }}
    >
      {/* Title row with type icon */}
      <Box sx={{ display: 'flex', alignItems: 'flex-start', gap: 0.5 }}>
        <Box sx={{ display: 'inline-flex', mt: 0.25, color: `${issue.typ_farbe || 'action'}.main` }}>
          {icon}
        </Box>
        <Typography variant="body2" sx={{ fontWeight: 500, flex: 1, lineHeight: 1.3 }}>
          {issue.titel}
        </Typography>
      </Box>

      {/* Bottom row: assignee + overdue */}
      <Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', mt: 0.5 }}>
        <Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>
          {issue.zugewiesen_an_name && (
            <Avatar sx={{ width: 20, height: 20, fontSize: 10 }}>
              {issue.zugewiesen_an_name.charAt(0).toUpperCase()}
            </Avatar>
          )}
          <Typography variant="caption" color="text.secondary">
            {issue.zugewiesen_an_name || ''}
          </Typography>
        </Box>
        {overdue && (
          <Chip
            icon={<AccessTimeIcon sx={{ fontSize: 14 }} />}
            label="Überfällig"
            size="small"
            color="error"
            variant="outlined"
            sx={{ height: 20, '& .MuiChip-label': { px: 0.5, fontSize: 11 } }}
          />
        )}
      </Box>
    </Paper>
  );
}

// ── Sortable wrapper ──

function SortableCard({
  issue,
  priorities,
  onClick,
}: {
  issue: Issue;
  priorities: IssuePriorityDef[];
  onClick: (id: number) => void;
}) {
  const {
    attributes,
    listeners,
    setNodeRef,
    transform,
    transition,
    isDragging,
  } = useSortable({ id: issue.id });

  const style = {
    transform: CSS.Transform.toString(transform),
    transition,
  };

  return (
    <Box ref={setNodeRef} style={style} {...attributes} {...listeners}>
      <KanbanCard issue={issue} priorities={priorities} onClick={onClick} isDragging={isDragging} />
    </Box>
  );
}

// ── Column ──

function KanbanColumn({
  statusDef,
  issues,
  priorities,
  onClick,
}: {
  statusDef: IssueStatusDef;
  issues: Issue[];
  priorities: IssuePriorityDef[];
  onClick: (id: number) => void;
}) {
  const chipColor = MUI_THEME_COLORS[statusDef.farbe] ?? statusDef.farbe ?? '#9e9e9e';
  const { setNodeRef, isOver } = useDroppable({ id: statusDef.schluessel });

  return (
    <Box
      ref={setNodeRef}
      sx={{
        minWidth: 260,
        maxWidth: 320,
        flex: '1 1 260px',
        display: 'flex',
        flexDirection: 'column',
        bgcolor: isOver ? 'action.hover' : 'background.default',
        borderRadius: 1,
        overflow: 'hidden',
        transition: 'background-color 0.15s',
      }}
    >
      {/* Column header */}
      <Box sx={{ px: 1.5, py: 1, display: 'flex', alignItems: 'center', gap: 1, borderBottom: 1, borderColor: 'divider' }}>
        <Box sx={{ width: 10, height: 10, borderRadius: '50%', bgcolor: chipColor, flexShrink: 0 }} />
        <Typography variant="subtitle2" sx={{ flex: 1 }}>{statusDef.bezeichnung}</Typography>
        <Typography variant="caption" color="text.secondary">{issues.length}</Typography>
      </Box>

      {/* Card list */}
      <SortableContext items={issues.map(i => i.id)} strategy={verticalListSortingStrategy}>
        <Box
          sx={{
            p: 1,
            display: 'flex',
            flexDirection: 'column',
            gap: 1,
            minHeight: 100,
            overflowY: 'auto',
            flex: 1,
          }}
        >
          {issues.length === 0 && (
            <Typography variant="caption" color="text.secondary" sx={{ textAlign: 'center', py: 2 }}>
              Keine Issues
            </Typography>
          )}
          {issues.map((issue) => (
            <SortableCard key={issue.id} issue={issue} priorities={priorities} onClick={onClick} />
          ))}
        </Box>
      </SortableContext>
    </Box>
  );
}

// ── Main Board ──

interface KanbanBoardProps {
  issues: Issue[];
  statuses: IssueStatusDef[];
  priorities: IssuePriorityDef[];
  onNavigate: (issueId: number) => void;
  onStatusChange: (issueId: number, newStatus: string) => void;
}

export default function KanbanBoard({
  issues,
  statuses,
  priorities,
  onNavigate,
  onStatusChange,
}: KanbanBoardProps) {
  const [activeId, setActiveId] = useState<number | null>(null);

  const sensors = useSensors(
    useSensor(PointerSensor, { activationConstraint: { distance: 5 } }),
  );

  // Active statuses sorted by sort_order
  const activeStatuses = useMemo(
    () => statuses.filter(s => s.aktiv).sort((a, b) => a.sort_order - b.sort_order),
    [statuses],
  );

  // Group issues by status
  const issuesByStatus = useMemo(() => {
    const map: Record<string, Issue[]> = {};
    for (const s of activeStatuses) map[s.schluessel] = [];
    for (const issue of issues) {
      if (map[issue.status]) map[issue.status].push(issue);
    }
    return map;
  }, [issues, activeStatuses]);

  const activeIssue = activeId ? issues.find(i => i.id === activeId) : null;

  // Find which column (status) an issue id belongs to
  function findStatusForIssue(id: number): string | undefined {
    for (const [status, items] of Object.entries(issuesByStatus)) {
      if (items.some(i => i.id === id)) return status;
    }
    return undefined;
  }

  function handleDragStart(event: DragStartEvent) {
    setActiveId(event.active.id as number);
  }

  function handleDragEnd(event: DragEndEvent) {
    setActiveId(null);
    const { active, over } = event;
    if (!over) return;

    const activeIssueId = active.id as number;
    const overId = over.id;

    // Determine target status: if dropped over a column (status key) or over another card
    let targetStatus: string | undefined;

    // Check if overId is a status key (column droppable)
    if (typeof overId === 'string' && activeStatuses.some(s => s.schluessel === overId)) {
      targetStatus = overId;
    } else {
      // Dropped over another card — find that card's status
      targetStatus = findStatusForIssue(overId as number);
    }

    if (!targetStatus) return;

    const currentStatus = findStatusForIssue(activeIssueId);
    if (currentStatus === targetStatus) return;

    onStatusChange(activeIssueId, targetStatus);
  }

  return (
    <DndContext
      sensors={sensors}
      collisionDetection={closestCorners}
      onDragStart={handleDragStart}
      onDragEnd={handleDragEnd}
    >
      <Box
        sx={{
          display: 'flex',
          gap: 1.5,
          overflowX: 'auto',
          pb: 1,
          minHeight: 400,
        }}
      >
        {activeStatuses.map((s) => (
          <KanbanColumn
            key={s.schluessel}
            statusDef={s}
            issues={issuesByStatus[s.schluessel] || []}
            priorities={priorities}
            onClick={onNavigate}
          />
        ))}
      </Box>

      <DragOverlay>
        {activeIssue ? (
          <KanbanCard issue={activeIssue} priorities={priorities} onClick={() => {}} />
        ) : null}
      </DragOverlay>
    </DndContext>
  );
}
