import { useState, useCallback, useEffect, useRef, DragEvent } from 'react';
import {
  Title, Table, Group, Button, Stack, Text, Modal, TextInput,
  NumberInput, Select, Textarea, Badge, ActionIcon, Loader, Center,
  SegmentedControl, Card, Paper, ScrollArea, Box, Tooltip,
} from '@mantine/core';
import { useForm } from '@mantine/form';
import { useDisclosure } from '@mantine/hooks';
import { notifications } from '@mantine/notifications';
import {
  IconEdit, IconTable, IconLayoutKanban, IconFileTypePdf,
  IconGripVertical, IconCalendar, IconClipboardList,
} from '@tabler/icons-react';
import { useNavigate } from 'react-router-dom';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import api from '../../services/api';
import { useIsReadOnly } from '../../stores/authStore';

// ---------------------------------------------------------------------------
// Types & constants
// ---------------------------------------------------------------------------

interface Project {
  id: string;
  name: string;
  description: string;
  category: string;
  estimated_cost: string;
  actual_cost: string;
  fund_source: string;
  funded_percentage: string;
  planned_date: string;
  target_year: number | null;
  target_month: number;
  status: string;
  priority: number;
  notes: string;
}

const FUTURE_YEAR = 9999;
const UNSCHEDULED = -1;  // sentinel for projects with no target_year

const statusColors: Record<string, string> = {
  planned: 'blue', approved: 'green', in_progress: 'yellow',
  completed: 'teal', deferred: 'gray', cancelled: 'red',
};

const priorityColor = (p: number) => (p <= 2 ? 'red' : p <= 3 ? 'yellow' : 'gray');

const fmt = (v: string | number) =>
  parseFloat(String(v || '0')).toLocaleString('en-US', { style: 'currency', currency: 'USD' });

const yearLabel = (year: number) =>
  year === FUTURE_YEAR ? 'Future' : year === UNSCHEDULED ? 'Unscheduled' : String(year);

const formatPlannedDate = (d: string | null | undefined) => {
  if (!d) return null;
  try {
    const date = new Date(d);
    if (isNaN(date.getTime())) return null;
    return date.toLocaleDateString('en-US', { month: 'short', year: 'numeric' });
  } catch {
    return null;
  }
};

// ---------------------------------------------------------------------------
// Kanban card
// ---------------------------------------------------------------------------

interface KanbanCardProps {
  project: Project;
  onEdit: (p: Project) => void;
  onDragStart: (e: DragEvent<HTMLDivElement>, project: Project) => void;
  isReadOnly?: boolean;
}

function KanbanCard({ project, onEdit, onDragStart, isReadOnly }: KanbanCardProps) {
  const plannedLabel = formatPlannedDate(project.planned_date);
  // For projects in the Future bucket with a specific year, show the year
  const currentYear = new Date().getFullYear();
  const isBeyondWindow = project.target_year !== null && project.target_year > currentYear + 4 && project.target_year !== FUTURE_YEAR;

  return (
    <Card
      shadow="sm"
      padding="sm"
      radius="md"
      withBorder
      draggable={!isReadOnly}
      onDragStart={!isReadOnly ? (e) => onDragStart(e, project) : undefined}
      style={{ cursor: isReadOnly ? 'default' : 'grab', userSelect: 'none' }}
      mb="xs"
    >
      <Group justify="space-between" wrap="nowrap" mb={4}>
        <Group gap={6} wrap="nowrap" style={{ overflow: 'hidden' }}>
          {!isReadOnly && <IconGripVertical size={14} style={{ flexShrink: 0, color: 'var(--mantine-color-dimmed)' }} />}
          <Text fw={600} size="sm" truncate>
            {project.name}
          </Text>
        </Group>
        {!isReadOnly && (
          <ActionIcon variant="subtle" size="sm" onClick={() => onEdit(project)}>
            <IconEdit size={14} />
          </ActionIcon>
        )}
      </Group>

      <Group gap={6} mb={6}>
        <Badge size="xs" color={statusColors[project.status] || 'gray'}>
          {project.status.replace('_', ' ')}
        </Badge>
        <Badge size="xs" color={priorityColor(project.priority)} variant="outline">
          P{project.priority}
        </Badge>
        {isBeyondWindow && (
          <Badge size="xs" variant="light" color="gray">
            {project.target_year}
          </Badge>
        )}
      </Group>

      <Text size="xs" ff="monospace" fw={500} mb={4}>
        {fmt(project.estimated_cost)}
      </Text>

      <Group gap={6} wrap="wrap">
        <Badge size="xs" variant="light" color="violet">
          {project.fund_source?.replace('_', ' ') || 'reserve'}
        </Badge>
        {plannedLabel && (
          <Badge size="xs" variant="light" color="cyan" leftSection={<IconCalendar size={10} />}>
            {plannedLabel}
          </Badge>
        )}
      </Group>
    </Card>
  );
}

// ---------------------------------------------------------------------------
// Kanban column (year)
// ---------------------------------------------------------------------------

interface KanbanColumnProps {
  year: number;
  projects: Project[];
  onEdit: (p: Project) => void;
  onDragStart: (e: DragEvent<HTMLDivElement>, project: Project) => void;
  onDrop: (e: DragEvent<HTMLDivElement>, targetYear: number) => void;
  isDragOver: boolean;
  onDragOverHandler: (e: DragEvent<HTMLDivElement>, year: number) => void;
  onDragLeave: () => void;
  isReadOnly?: boolean;
}

function KanbanColumn({
  year, projects, onEdit, onDragStart, onDrop,
  isDragOver, onDragOverHandler, onDragLeave, isReadOnly,
}: KanbanColumnProps) {
  const totalEst = projects.reduce((s, p) => s + parseFloat(p.estimated_cost || '0'), 0);
  const isFuture = year === FUTURE_YEAR;
  const isUnscheduled = year === UNSCHEDULED;
  const useWideLayout = (isFuture || isUnscheduled) && projects.length > 3;

  return (
    <Paper
      withBorder
      radius="md"
      p="sm"
      miw={useWideLayout ? 580 : 280}
      maw={useWideLayout ? 640 : 320}
      style={{
        flexShrink: 0,
        display: 'flex',
        flexDirection: 'column',
        backgroundColor: isDragOver
          ? 'var(--mantine-color-blue-0)'
          : isUnscheduled
            ? 'var(--mantine-color-orange-0)'
            : undefined,
        border: isDragOver ? '2px dashed var(--mantine-color-blue-4)' : undefined,
        transition: 'background-color 150ms ease, border 150ms ease',
      }}
      onDragOver={!isReadOnly ? (e) => onDragOverHandler(e, year) : undefined}
      onDragLeave={!isReadOnly ? onDragLeave : undefined}
      onDrop={!isReadOnly ? (e) => onDrop(e, year) : undefined}
    >
      <Group justify="space-between" mb="sm">
        <Title order={5}>{yearLabel(year)}</Title>
        <Group gap={6}>
          {isUnscheduled && projects.length > 0 && (
            <Badge size="xs" variant="light" color="orange">needs scheduling</Badge>
          )}
          <Badge size="sm" variant="light">{fmt(totalEst)}</Badge>
        </Group>
      </Group>

      <Text size="xs" c="dimmed" mb="xs">
        {projects.length} project{projects.length !== 1 ? 's' : ''}
      </Text>

      <Box style={{ flex: 1, minHeight: 60 }}>
        {projects.length === 0 ? (
          <Text size="xs" c="dimmed" ta="center" py="lg">
            {isReadOnly ? 'No projects' : 'Drop projects here'}
          </Text>
        ) : useWideLayout ? (
          <div style={{
            display: 'grid',
            gridTemplateColumns: '1fr 1fr',
            gap: 'var(--mantine-spacing-xs)',
          }}>
            {projects.map((p) => (
              <KanbanCard key={p.id} project={p} onEdit={onEdit} onDragStart={onDragStart} isReadOnly={isReadOnly} />
            ))}
          </div>
        ) : (
          projects.map((p) => (
            <KanbanCard key={p.id} project={p} onEdit={onEdit} onDragStart={onDragStart} isReadOnly={isReadOnly} />
          ))
        )}
      </Box>
    </Paper>
  );
}

// ---------------------------------------------------------------------------
// Print styles - hides kanban and shows the table view when printing
// ---------------------------------------------------------------------------

const printStyles = `
@media print {
  .capital-projects-kanban-view {
    display: none !important;
  }
  .capital-projects-table-view {
    display: block !important;
  }
}
`;

// ---------------------------------------------------------------------------
// Main page component
// ---------------------------------------------------------------------------

export function CapitalProjectsPage() {
  const [opened, { open, close }] = useDisclosure(false);
  const [editing, setEditing] = useState<Project | null>(null);
  const [viewMode, setViewMode] = useState<string>('kanban');
  const [printMode, setPrintMode] = useState(false);
  const [dragOverYear, setDragOverYear] = useState<number | null>(null);
  const printModeRef = useRef(false);
  const queryClient = useQueryClient();
  const isReadOnly = useIsReadOnly();

  // ---- Data fetching ----

  const { data: projects = [], isLoading } = useQuery<Project[]>({
    queryKey: ['projects-planning'],
    queryFn: async () => { const { data } = await api.get('/projects/planning'); return data; },
  });

  // ---- Form (simplified edit modal) ----

  const currentYear = new Date().getFullYear();

  const targetYearOptions = [
    ...Array.from({ length: 6 }, (_, i) => ({
      value: String(currentYear + i),
      label: String(currentYear + i),
    })),
    { value: String(FUTURE_YEAR), label: 'Future (Beyond 5-Year)' },
  ];

  const form = useForm({
    initialValues: {
      status: 'planned',
      priority: 3,
      target_year: currentYear,
      target_month: 6,
      planned_date: '',
      notes: '',
    },
  });

  // ---- Mutations ----

  const saveMutation = useMutation({
    mutationFn: (values: {
      status: string;
      priority: number;
      target_year: number;
      target_month: number;
      planned_date: string;
      notes: string;
    }) => {
      if (!editing) return Promise.reject(new Error('No project selected'));
      const payload: Record<string, unknown> = {
        status: values.status,
        priority: values.priority,
        target_year: values.target_year,
        target_month: values.target_month,
        notes: values.notes,
      };
      // Derive planned_date from target_year/target_month if not explicitly set
      if (values.planned_date) {
        payload.planned_date = values.planned_date;
      } else if (values.target_year !== FUTURE_YEAR) {
        payload.planned_date = `${values.target_year}-${String(values.target_month || 6).padStart(2, '0')}-01`;
      } else {
        payload.planned_date = null;
      }
      return api.put(`/projects/${editing.id}`, payload);
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['projects-planning'] });
      queryClient.invalidateQueries({ queryKey: ['projects'] });
      notifications.show({ message: 'Project updated', color: 'green' });
      close(); setEditing(null); form.reset();
    },
    onError: (err: any) => {
      notifications.show({ message: err.response?.data?.message || 'Error', color: 'red' });
    },
  });

  const moveProjectMutation = useMutation({
    mutationFn: ({ id, target_year, target_month }: { id: string; target_year: number | null; target_month: number }) => {
      const payload: Record<string, unknown> = { target_year };
      // Derive planned_date based on the new year
      if (target_year === null || target_year === FUTURE_YEAR) {
        payload.planned_date = null;
      } else {
        payload.planned_date = `${target_year}-${String(target_month || 6).padStart(2, '0')}-01`;
      }
      return api.put(`/projects/${id}`, payload);
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['projects-planning'] });
      queryClient.invalidateQueries({ queryKey: ['projects'] });
      notifications.show({ message: 'Project moved successfully', color: 'green' });
    },
    onError: (err: any) => {
      notifications.show({ message: err.response?.data?.message || 'Failed to move project', color: 'red' });
    },
  });

  // ---- Print mode effect ----

  useEffect(() => {
    if (printMode) {
      printModeRef.current = true;
      // Wait for the table to render before printing
      const timer = setTimeout(() => {
        window.print();
        setPrintMode(false);
        printModeRef.current = false;
      }, 300);
      return () => clearTimeout(timer);
    }
  }, [printMode]);

  // ---- Handlers ----

  const handleEdit = (p: Project) => {
    setEditing(p);
    form.setValues({
      status: p.status || 'planned',
      priority: p.priority || 3,
      target_year: p.target_year ?? currentYear,
      target_month: p.target_month || 6,
      planned_date: p.planned_date || '',
      notes: p.notes || '',
    });
    open();
  };

  const handlePdfExport = () => {
    // If already in table view, just print directly
    if (viewMode === 'table') {
      window.print();
      return;
    }
    // Otherwise, trigger printMode which renders the table for printing
    setPrintMode(true);
  };

  // ---- Drag & Drop ----

  const handleDragStart = useCallback((e: DragEvent<HTMLDivElement>, project: Project) => {
    e.dataTransfer.setData('application/json', JSON.stringify({
      id: project.id,
      source_year: project.target_year ?? UNSCHEDULED,
      target_month: project.target_month,
    }));
    e.dataTransfer.effectAllowed = 'move';
  }, []);

  const handleDragOver = useCallback((e: DragEvent<HTMLDivElement>, year: number) => {
    e.preventDefault();
    e.dataTransfer.dropEffect = 'move';
    setDragOverYear(year);
  }, []);

  const handleDragLeave = useCallback(() => {
    setDragOverYear(null);
  }, []);

  const handleDrop = useCallback((e: DragEvent<HTMLDivElement>, targetYear: number) => {
    e.preventDefault();
    setDragOverYear(null);
    try {
      const payload = JSON.parse(e.dataTransfer.getData('application/json'));
      if (payload.source_year !== targetYear) {
        moveProjectMutation.mutate({
          id: payload.id,
          target_year: targetYear === UNSCHEDULED ? null : targetYear,
          target_month: payload.target_month || 6,
        });
      }
    } catch {
      // ignore malformed drag data
    }
  }, [moveProjectMutation]);

  // ---- Derived data ----

  // Always show current year through current+4, plus FUTURE_YEAR if any projects have it
  const baseYears = Array.from({ length: 5 }, (_, i) => currentYear + i);
  const projectYears = [...new Set(projects.map((p) => p.target_year).filter((y): y is number => y !== null))];
  const hasFutureProjects = projectYears.includes(FUTURE_YEAR);
  const hasUnscheduledProjects = projects.some((p) => p.target_year === null);

  // Merge base years with any extra years from projects (excluding FUTURE_YEAR for now)
  const regularYears = [...new Set([...baseYears, ...projectYears.filter((y) => y !== FUTURE_YEAR)])].sort();
  const years = [
    ...regularYears,
    ...(hasFutureProjects ? [FUTURE_YEAR] : []),
    ...(hasUnscheduledProjects ? [UNSCHEDULED] : []),
  ];

  // Kanban columns: current..current+4 + Future + Unscheduled (rightmost)
  const kanbanYears = [...baseYears, FUTURE_YEAR, UNSCHEDULED];

  // ---- Loading state ----

  const navigate = useNavigate();

  if (isLoading) return <Center h={300}><Loader /></Center>;

  // ---- Empty state when no planning projects exist ----

  if (projects.length === 0) {
    return (
      <Stack>
        <Group justify="space-between">
          <Title order={2}>Capital Planning</Title>
        </Group>
        <Center py={80}>
          <Stack align="center" gap="md" maw={420}>
            <IconClipboardList size={64} color="var(--mantine-color-dimmed)" stroke={1.2} />
            <Title order={3} c="dimmed" ta="center">
              No projects yet
            </Title>
            <Text c="dimmed" ta="center" size="sm">
              Head over to the Projects page to define your reserve and operating
              projects. They'll appear here for capital planning and scheduling.
            </Text>
            <Button
              variant="light"
              size="md"
              leftSection={<IconClipboardList size={18} />}
              onClick={() => navigate('/projects')}
            >
              Go to Projects
            </Button>
          </Stack>
        </Center>
      </Stack>
    );
  }

  // ---- Render: Table view ----

  const renderTableView = () => (
    <>
      {years.length === 0 ? (
        <Text c="dimmed" ta="center" py="xl">
          No projects in the capital plan. Assign a target year to projects in the Projects page.
        </Text>
      ) : (
        years.map((year) => {
          const yearProjects = year === UNSCHEDULED
            ? projects.filter((p) => p.target_year === null)
            : projects.filter((p) => p.target_year === year);
          if (yearProjects.length === 0) return null;
          const totalEst = yearProjects.reduce((s, p) => s + parseFloat(p.estimated_cost || '0'), 0);
          return (
            <Stack key={year} gap="xs">
              <Group>
                <Title order={4}>{yearLabel(year)}</Title>
                <Badge size="lg" variant="light">{fmt(totalEst)} estimated</Badge>
              </Group>
              <Table striped highlightOnHover>
                <Table.Thead>
                  <Table.Tr>
                    <Table.Th>Project</Table.Th>
                    <Table.Th>Category</Table.Th>
                    <Table.Th>Target</Table.Th>
                    <Table.Th>Priority</Table.Th>
                    <Table.Th ta="right">Estimated</Table.Th>
                    <Table.Th ta="right">Actual</Table.Th>
                    <Table.Th>Source</Table.Th>
                    <Table.Th>Funded</Table.Th>
                    <Table.Th>Status</Table.Th>
                    <Table.Th>Planned Date</Table.Th>
                    <Table.Th></Table.Th>
                  </Table.Tr>
                </Table.Thead>
                <Table.Tbody>
                  {yearProjects.map((p) => (
                    <Table.Tr key={p.id}>
                      <Table.Td fw={500}>{p.name}</Table.Td>
                      <Table.Td>{p.category || '-'}</Table.Td>
                      <Table.Td>
                        {p.target_year === null
                          ? <Text size="sm" c="dimmed" fs="italic">Unscheduled</Text>
                          : p.target_year === FUTURE_YEAR
                            ? 'Future'
                            : (
                              <>
                                {p.target_month
                                  ? new Date(2000, p.target_month - 1).toLocaleString('default', { month: 'short' })
                                  : ''}{' '}
                                {p.target_year}
                              </>
                            )
                        }
                      </Table.Td>
                      <Table.Td>
                        <Badge size="sm" color={priorityColor(p.priority)}>P{p.priority}</Badge>
                      </Table.Td>
                      <Table.Td ta="right" ff="monospace">{fmt(p.estimated_cost)}</Table.Td>
                      <Table.Td ta="right" ff="monospace">
                        {parseFloat(p.actual_cost || '0') > 0 ? fmt(p.actual_cost) : '-'}
                      </Table.Td>
                      <Table.Td>
                        <Badge size="sm" variant="light">{p.fund_source?.replace('_', ' ') || 'reserve'}</Badge>
                      </Table.Td>
                      <Table.Td>
                        {parseFloat(p.funded_percentage || '0') > 0
                          ? `${parseFloat(p.funded_percentage).toFixed(0)}%`
                          : '-'}
                      </Table.Td>
                      <Table.Td>
                        <Badge size="sm" color={statusColors[p.status] || 'gray'}>{p.status?.replace('_', ' ')}</Badge>
                      </Table.Td>
                      <Table.Td>{formatPlannedDate(p.planned_date) || '-'}</Table.Td>
                      <Table.Td>
                        {!isReadOnly && <ActionIcon variant="subtle" onClick={() => handleEdit(p)}>
                          <IconEdit size={16} />
                        </ActionIcon>}
                      </Table.Td>
                    </Table.Tr>
                  ))}
                </Table.Tbody>
              </Table>
            </Stack>
          );
        })
      )}
    </>
  );

  // ---- Render: Kanban view ----

  const maxPlannedYear = currentYear + 4; // last year in the 5-year window

  const renderKanbanView = () => (
    <ScrollArea type="auto" offsetScrollbars>
      <Group align="flex-start" wrap="nowrap" gap="md" py="sm" style={{ minWidth: kanbanYears.length * 300 }}>
        {kanbanYears.map((year) => {
          // Unscheduled: projects with no target_year
          // Future: projects with target_year === 9999 OR beyond the 5-year window
          // Otherwise: exact year match
          const yearProjects = year === UNSCHEDULED
            ? projects.filter((p) => p.target_year === null)
            : year === FUTURE_YEAR
              ? projects.filter((p) => p.target_year === FUTURE_YEAR || (p.target_year !== null && p.target_year > maxPlannedYear))
              : projects.filter((p) => p.target_year === year);
          return (
            <KanbanColumn
              key={year}
              year={year}
              projects={yearProjects}
              onEdit={handleEdit}
              onDragStart={handleDragStart}
              onDrop={handleDrop}
              isDragOver={dragOverYear === year}
              onDragOverHandler={handleDragOver}
              onDragLeave={handleDragLeave}
              isReadOnly={isReadOnly}
            />
          );
        })}
      </Group>
    </ScrollArea>
  );

  // ---- Render ----

  return (
    <Stack>
      {/* Print-specific styles */}
      <style>{printStyles}</style>

      <Group justify="space-between">
        <Title order={2}>Capital Planning</Title>
        <Group gap="sm">
          <SegmentedControl
            value={viewMode}
            onChange={setViewMode}
            data={[
              {
                value: 'table',
                label: (
                  <Group gap={6} wrap="nowrap">
                    <IconTable size={16} />
                    <Text size="sm">Table</Text>
                  </Group>
                ),
              },
              {
                value: 'kanban',
                label: (
                  <Group gap={6} wrap="nowrap">
                    <IconLayoutKanban size={16} />
                    <Text size="sm">Kanban</Text>
                  </Group>
                ),
              },
            ]}
          />
          <Tooltip label="Export as PDF (browser print)">
            <Button variant="light" leftSection={<IconFileTypePdf size={16} />} onClick={handlePdfExport}>
              PDF
            </Button>
          </Tooltip>
        </Group>
      </Group>

      {/* Main visible view */}
      {viewMode === 'table' ? (
        <div className="capital-projects-table-view">
          {renderTableView()}
        </div>
      ) : (
        <>
          <div className="capital-projects-kanban-view">
            {renderKanbanView()}
          </div>
          {/* Hidden table view for print mode - rendered when printMode is true */}
          {printMode && (
            <div className="capital-projects-table-view" style={{ display: 'none' }}>
              {renderTableView()}
            </div>
          )}
        </>
      )}

      {/* Simplified edit modal - full project editing is done in ProjectsPage */}
      <Modal opened={opened} onClose={close} title="Edit Capital Plan Details" size="md">
        <form onSubmit={form.onSubmit((v) => saveMutation.mutate(v))}>
          <Stack>
            {editing && (
              <Text size="sm" fw={600} c="dimmed">
                {editing.name}
              </Text>
            )}
            <Group grow>
              <Select
                label="Status"
                data={Object.keys(statusColors).map((s) => ({ value: s, label: s.replace('_', ' ') }))}
                {...form.getInputProps('status')}
              />
              <NumberInput label="Priority (1=High, 5=Low)" min={1} max={5} {...form.getInputProps('priority')} />
            </Group>
            <Group grow>
              <Select
                label="Target Year"
                required
                data={targetYearOptions}
                value={String(form.values.target_year)}
                onChange={(v) => form.setFieldValue('target_year', Number(v))}
              />
              <Select
                label="Target Month"
                data={Array.from({ length: 12 }, (_, i) => ({
                  value: String(i + 1),
                  label: new Date(2026, i).toLocaleString('default', { month: 'long' }),
                }))}
                value={String(form.values.target_month)}
                onChange={(v) => form.setFieldValue('target_month', Number(v))}
              />
            </Group>
            <TextInput
              label="Planned Date"
              placeholder="YYYY-MM-DD"
              description="Leave blank to auto-derive from target year/month"
              {...form.getInputProps('planned_date')}
            />
            <Textarea label="Notes" autosize minRows={2} maxRows={6} {...form.getInputProps('notes')} />
            <Button type="submit" loading={saveMutation.isPending}>Update</Button>
          </Stack>
        </form>
      </Modal>
    </Stack>
  );
}
