import { useState, useMemo } from 'react';
import {
  Title, Table, Group, Button, Stack, Text, NumberInput,
  Select, Loader, Center, Badge, Card, Alert,
} from '@mantine/core';
import { notifications } from '@mantine/notifications';
import { IconDeviceFloppy, IconInfoCircle, IconPencil, IconX, IconArrowRight } from '@tabler/icons-react';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { useNavigate } from 'react-router-dom';
import api from '../../services/api';
import { useCanEdit, CAPABILITIES } from '../../permissions';
import { usePreferencesStore } from '../../stores/preferencesStore';

interface BudgetLine {
  account_id: string;
  account_number: string;
  account_name: string;
  account_type: string;
  fund_type: string;
  jan: number; feb: number; mar: number; apr: number;
  may: number; jun: number; jul: number; aug: number;
  sep: number; oct: number; nov: number; dec_amt: number;
  annual_total: number;
}

const months = ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec_amt'];
const monthLabels = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];

function hydrateBudgetLine(row: any): BudgetLine {
  const line: any = { ...row };
  for (const m of months) {
    line[m] = Number(line[m]) || 0;
  }
  line.annual_total = months.reduce((sum, m) => sum + (line[m] || 0), 0);
  return line as BudgetLine;
}

export function BudgetsPage() {
  const [year, setYear] = useState(new Date().getFullYear().toString());
  const [editData, setEditData] = useState<BudgetLine[] | null>(null); // null = not editing
  const queryClient = useQueryClient();
  const navigate = useNavigate();
  const isReadOnly = !useCanEdit(CAPABILITIES.FINANCIALS_BUDGETS_EDIT);
  const isDark = usePreferencesStore((s) => s.colorScheme) === 'dark';
  const stickyBg = isDark ? 'var(--mantine-color-dark-7)' : 'white';
  const stickyBorder = isDark ? 'var(--mantine-color-dark-4)' : '#e9ecef';
  const incomeSectionBg = isDark ? 'var(--mantine-color-green-9)' : '#e6f9e6';
  const expenseSectionBg = isDark ? 'var(--mantine-color-red-9)' : '#fde8e8';

  // Query is the single source of truth for budget data
  const { data: queryData, isLoading, isFetching } = useQuery<BudgetLine[]>({
    queryKey: ['budgets', year],
    queryFn: async () => {
      const { data } = await api.get(`/budgets/${year}`);
      return (data as any[]).map(hydrateBudgetLine);
    },
  });

  // Use edit data when editing, otherwise use query data
  const isEditing = editData !== null;
  const budgetData = isEditing ? editData : (queryData || []);
  const hasBudget = budgetData.length > 0;
  const cellsEditable = !isReadOnly && isEditing;

  const handleStartEdit = () => {
    setEditData(queryData ? [...queryData] : []);
  };

  const handleCancelEdit = () => {
    setEditData(null);
  };

  const handleYearChange = (v: string | null) => {
    if (v) {
      setYear(v);
      setEditData(null); // Cancel any in-progress edit when switching years
    }
  };

  const saveMutation = useMutation({
    mutationFn: async () => {
      const payload = budgetData
        .filter((b) => months.some((m) => (b as any)[m] > 0))
        .map((b) => ({
          accountId: b.account_id,
          fundType: b.fund_type,
          jan: b.jan, feb: b.feb, mar: b.mar, apr: b.apr,
          may: b.may, jun: b.jun, jul: b.jul, aug: b.aug,
          sep: b.sep, oct: b.oct, nov: b.nov, dec: b.dec_amt,
        }));
      return api.put(`/budgets/${year}`, payload);
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['budgets', year] });
      setEditData(null);
      notifications.show({ message: 'Budget saved', color: 'green' });
    },
    onError: (err: any) => {
      notifications.show({ message: err.response?.data?.message || 'Save failed', color: 'red' });
    },
  });

  const updateCell = (idx: number, month: string, value: number) => {
    if (!editData) return;
    const updated = [...editData];
    (updated[idx] as any)[month] = value || 0;
    updated[idx].annual_total = months.reduce((s, m) => s + ((updated[idx] as any)[m] || 0), 0);
    setEditData(updated);
  };

  const yearOptions = useMemo(() => Array.from({ length: 5 }, (_, i) => {
    const y = new Date().getFullYear() - 1 + i;
    return { value: String(y), label: String(y) };
  }), []);

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

  // Show loader on initial load or when switching years with no cached data
  if (isLoading) return <Center h={300}><Loader /></Center>;

  const incomeLines = budgetData.filter((b) => b.account_type === 'income');
  const operatingIncomeLines = incomeLines.filter((b) => b.fund_type === 'operating');
  const reserveIncomeLines = incomeLines.filter((b) => b.fund_type === 'reserve');
  const expenseLines = budgetData.filter((b) => b.account_type === 'expense');
  const totalOperatingIncome = operatingIncomeLines.reduce((sum, line) => sum + (line.annual_total || 0), 0);
  const totalReserveIncome = reserveIncomeLines.reduce((sum, line) => sum + (line.annual_total || 0), 0);
  const totalExpense = expenseLines.reduce((sum, line) => sum + (line.annual_total || 0), 0);

  return (
    <Stack>
      <Group justify="space-between">
        <Title order={2}>Budget Manager</Title>
        <Group>
          <Select data={yearOptions} value={year} onChange={handleYearChange} w={120} />
          {isFetching && !isLoading && <Loader size="xs" />}
          {!isReadOnly && hasBudget && (
            <>
              {!isEditing ? (
                <Button
                  variant="outline"
                  leftSection={<IconPencil size={16} />}
                  onClick={handleStartEdit}
                >
                  Edit Budget
                </Button>
              ) : (
                <>
                  <Button
                    variant="outline"
                    color="gray"
                    leftSection={<IconX size={16} />}
                    onClick={handleCancelEdit}
                  >
                    Cancel
                  </Button>
                  <Button
                    leftSection={<IconDeviceFloppy size={16} />}
                    onClick={() => saveMutation.mutate()}
                    loading={saveMutation.isPending}
                  >
                    Save Budget
                  </Button>
                </>
              )}
            </>
          )}
        </Group>
      </Group>

      {!hasBudget && !isLoading && (
        <Alert icon={<IconInfoCircle size={16} />} color="blue" variant="light">
          <Stack gap="sm">
            <Text>No budget data for {year}.</Text>
            <Text size="sm">
              To create or import a budget, use the <Text span fw={600}>Budget Planner</Text> to build,
              review, and ratify a budget for this year. Once ratified, it will appear here.
            </Text>
            <Button
              variant="light"
              leftSection={<IconArrowRight size={16} />}
              w="fit-content"
              onClick={() => navigate('/board-planning/budgets')}
            >
              Go to Budget Planner
            </Button>
          </Stack>
        </Alert>
      )}

      <Group>
        <Card withBorder p="sm">
          <Text size="xs" c="dimmed">Operating Income</Text>
          <Text fw={700} c="green">{fmt(totalOperatingIncome)}</Text>
        </Card>
        {totalReserveIncome > 0 && (
          <Card withBorder p="sm">
            <Text size="xs" c="dimmed">Reserve Income</Text>
            <Text fw={700} c="violet">{fmt(totalReserveIncome)}</Text>
          </Card>
        )}
        <Card withBorder p="sm">
          <Text size="xs" c="dimmed">Total Expenses</Text>
          <Text fw={700} c="red">{fmt(totalExpense)}</Text>
        </Card>
        <Card withBorder p="sm">
          <Text size="xs" c="dimmed">Net (Operating)</Text>
          <Text fw={700} c={totalOperatingIncome - totalExpense >= 0 ? 'green' : 'red'}>
            {fmt(totalOperatingIncome - totalExpense)}
          </Text>
        </Card>
      </Group>

      <div style={{ overflowX: 'auto' }}>
        <Table striped highlightOnHover style={{ minWidth: 1600 }}>
          <Table.Thead>
            <Table.Tr>
              <Table.Th style={{ position: 'sticky', left: 0, background: stickyBg, zIndex: 2, minWidth: 120 }}>Acct #</Table.Th>
              <Table.Th style={{ position: 'sticky', left: 120, background: stickyBg, zIndex: 2, minWidth: 220 }}>Account Name</Table.Th>
              {monthLabels.map((m) => (
                <Table.Th key={m} ta="right" style={{ minWidth: 90 }}>{m}</Table.Th>
              ))}
              <Table.Th ta="right" style={{ minWidth: 110 }}>Annual</Table.Th>
            </Table.Tr>
          </Table.Thead>
          <Table.Tbody>
            {budgetData.length === 0 && (
              <Table.Tr>
                <Table.Td colSpan={15}>
                  <Text ta="center" c="dimmed" py="lg">No budget data for this year.</Text>
                </Table.Td>
              </Table.Tr>
            )}
            {['income', 'expense'].map((type) => {
              const lines = budgetData.filter((b) => b.account_type === type);
              if (lines.length === 0) return null;

              const sectionBg = type === 'income' ? incomeSectionBg : expenseSectionBg;
              const sectionTotal = lines.reduce((sum, line) => sum + (line.annual_total || 0), 0);

              return [
                <Table.Tr key={`header-${type}`} style={{ background: sectionBg }}>
                  <Table.Td
                    colSpan={2}
                    fw={700}
                    tt="capitalize"
                    style={{
                      position: 'sticky',
                      left: 0,
                      background: sectionBg,
                      zIndex: 2,
                    }}
                  >
                    {type}
                  </Table.Td>
                  {monthLabels.map((m) => (
                    <Table.Td key={m} />
                  ))}
                  <Table.Td ta="right" fw={700} ff="monospace">{fmt(sectionTotal)}</Table.Td>
                </Table.Tr>,
                ...lines.map((line) => {
                  const idx = budgetData.indexOf(line);
                  return (
                    <Table.Tr key={line.account_id}>
                      <Table.Td
                        style={{
                          position: 'sticky',
                          left: 0,
                          background: stickyBg,
                          zIndex: 1,
                          borderRight: `1px solid ${stickyBorder}`,
                        }}
                      >
                        <Text size="sm" c="dimmed" ff="monospace">{line.account_number}</Text>
                      </Table.Td>
                      <Table.Td
                        style={{
                          position: 'sticky',
                          left: 120,
                          background: stickyBg,
                          zIndex: 1,
                          borderRight: `1px solid ${stickyBorder}`,
                        }}
                      >
                        <Group gap={6} wrap="nowrap">
                          <Text size="sm" style={{ whiteSpace: 'nowrap' }}>{line.account_name}</Text>
                          {line.fund_type === 'reserve' && <Badge size="xs" color="violet">R</Badge>}
                        </Group>
                      </Table.Td>
                      {months.map((m) => (
                        <Table.Td key={m} p={2}>
                          {cellsEditable ? (
                            <NumberInput
                              value={(line as any)[m] || 0}
                              onChange={(v) => updateCell(idx, m, Number(v) || 0)}
                              size="xs"
                              hideControls
                              decimalScale={2}
                              min={0}
                              styles={{ input: { textAlign: 'right', fontFamily: 'monospace' } }}
                            />
                          ) : (
                            <Text size="sm" ta="right" ff="monospace">
                              {fmt((line as any)[m] || 0)}
                            </Text>
                          )}
                        </Table.Td>
                      ))}
                      <Table.Td ta="right" fw={500} ff="monospace">
                        {fmt(line.annual_total || 0)}
                      </Table.Td>
                    </Table.Tr>
                  );
                }),
              ];
            })}
          </Table.Tbody>
        </Table>
      </div>
    </Stack>
  );
}
