import { useState, useMemo } from 'react';
import {
  Title, Table, Group, Button, Stack, Text, NumberInput,
  Select, Loader, Center, Card, SimpleGrid, Badge, Alert, Modal,
} from '@mantine/core';
import { useDisclosure } from '@mantine/hooks';
import { notifications } from '@mantine/notifications';
import {
  IconDeviceFloppy, IconInfoCircle, IconCalendarMonth, IconEdit,
} from '@tabler/icons-react';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import api from '../../services/api';
import { useCanEdit, CAPABILITIES } from '../../permissions';
import { usePreferencesStore } from '../../stores/preferencesStore';
import { AttachmentPanel } from '../../components/attachments/AttachmentPanel';

interface ActualLine {
  account_id: string;
  account_number: string;
  account_name: string;
  account_type: string;
  fund_type: string;
  budget_amount: number;
  actual_amount: number;
}

interface ActualsGrid {
  year: number;
  month: number;
  month_label: string;
  existing_journal_entry_id: string | null;
  lines: ActualLine[];
}

const monthOptions = [
  { value: '1', label: 'January' },
  { value: '2', label: 'February' },
  { value: '3', label: 'March' },
  { value: '4', label: 'April' },
  { value: '5', label: 'May' },
  { value: '6', label: 'June' },
  { value: '7', label: 'July' },
  { value: '8', label: 'August' },
  { value: '9', label: 'September' },
  { value: '10', label: 'October' },
  { value: '11', label: 'November' },
  { value: '12', label: 'December' },
];

function getDefaultMonth(): { year: string; month: string } {
  const now = new Date();
  // Default to previous completed month
  const prev = new Date(now.getFullYear(), now.getMonth() - 1, 1);
  return {
    year: String(prev.getFullYear()),
    month: String(prev.getMonth() + 1),
  };
}

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

export function MonthlyActualsPage() {
  const defaults = getDefaultMonth();
  const [year, setYear] = useState(defaults.year);
  const [month, setMonth] = useState(defaults.month);
  const [editedAmounts, setEditedAmounts] = useState<Record<string, number>>({});
  const [savedJEId, setSavedJEId] = useState<string | null>(null);
  const [isEditing, setIsEditing] = useState(false);
  const [confirmOpened, { open: openConfirm, close: closeConfirm }] = useDisclosure(false);
  const queryClient = useQueryClient();
  const isReadOnly = !useCanEdit(CAPABILITIES.FINANCIALS_ACTUALS_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 incomeBg = isDark ? 'var(--mantine-color-green-9)' : '#e6f9e6';
  const expenseBg = isDark ? 'var(--mantine-color-red-9)' : '#fde8e8';

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

  const { data: grid, isLoading } = useQuery<ActualsGrid>({
    queryKey: ['monthly-actuals', year, month],
    queryFn: async () => {
      const { data } = await api.get(`/monthly-actuals/${year}/${month}`);
      setEditedAmounts({});
      setSavedJEId(data.existing_journal_entry_id || null);
      // Default to read mode if actuals already exist, edit mode if new
      setIsEditing(!data.existing_journal_entry_id);
      return data;
    },
  });

  // Whether actuals have been previously saved (reconciled)
  const hasExistingActuals = !!savedJEId;

  const saveMutation = useMutation({
    mutationFn: async () => {
      const lines = (grid?.lines || [])
        .map((line) => ({
          accountId: line.account_id,
          amount: editedAmounts[line.account_id] !== undefined
            ? editedAmounts[line.account_id]
            : line.actual_amount,
        }))
        .filter((l) => l.amount !== 0);
      const { data } = await api.post(`/monthly-actuals/${year}/${month}`, { lines });
      return data;
    },
    onSuccess: (data) => {
      queryClient.invalidateQueries({ queryKey: ['monthly-actuals'] });
      queryClient.invalidateQueries({ queryKey: ['journal-entries'] });
      queryClient.invalidateQueries({ queryKey: ['accounts'] });
      queryClient.invalidateQueries({ queryKey: ['budget-vs-actual'] });
      setSavedJEId(data.journal_entry_id);
      setIsEditing(false);
      setEditedAmounts({});
      notifications.show({
        message: data.message || 'Actuals saved and reconciled',
        color: 'green',
        autoClose: 5000,
      });
    },
    onError: (err: any) => {
      notifications.show({
        message: err.response?.data?.message || 'Failed to save actuals',
        color: 'red',
      });
    },
  });

  const getAmount = (line: ActualLine): number => {
    return editedAmounts[line.account_id] !== undefined
      ? editedAmounts[line.account_id]
      : line.actual_amount;
  };

  const updateAmount = (accountId: string, value: number) => {
    setEditedAmounts((prev) => ({ ...prev, [accountId]: value }));
  };

  const handleEditClick = () => {
    if (hasExistingActuals) {
      openConfirm();
    } else {
      setIsEditing(true);
    }
  };

  const handleConfirmEdit = () => {
    closeConfirm();
    setIsEditing(true);
  };

  const lines = grid?.lines || [];
  const incomeLines = lines.filter((l) => l.account_type === 'income');
  const expenseLines = lines.filter((l) => l.account_type === 'expense');

  const totals = useMemo(() => {
    const incomeBudget = incomeLines.reduce((s, l) => s + l.budget_amount, 0);
    const incomeActual = incomeLines.reduce((s, l) => s + getAmount(l), 0);
    const expenseBudget = expenseLines.reduce((s, l) => s + l.budget_amount, 0);
    const expenseActual = expenseLines.reduce((s, l) => s + getAmount(l), 0);
    return { incomeBudget, incomeActual, expenseBudget, expenseActual };
  }, [lines, editedAmounts]);

  const monthLabel = monthOptions.find((m) => m.value === month)?.label || '';

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

  const renderSection = (
    title: string,
    sectionLines: ActualLine[],
    bgColor: string,
    budgetTotal: number,
    actualTotal: number,
  ) => {
    if (sectionLines.length === 0) return null;
    const variance = actualTotal - budgetTotal;
    const isExpense = title === 'Expenses';

    return [
      <Table.Tr key={`header-${title}`} style={{ background: bgColor }}>
        <Table.Td
          colSpan={2}
          fw={700}
          style={{ position: 'sticky', left: 0, background: bgColor, zIndex: 2 }}
        >
          {title}
        </Table.Td>
        <Table.Td ta="right" fw={700} ff="monospace">{fmt(budgetTotal)}</Table.Td>
        <Table.Td ta="right" fw={700} ff="monospace">{fmt(actualTotal)}</Table.Td>
        <Table.Td ta="right" fw={700} ff="monospace"
          c={variance === 0 ? 'gray' : (isExpense ? (variance > 0 ? 'red' : 'green') : (variance > 0 ? 'green' : 'red'))}
        >
          {variance > 0 ? '+' : ''}{fmt(variance)}
        </Table.Td>
      </Table.Tr>,
      ...sectionLines.map((line) => {
        const amount = getAmount(line);
        const lineVariance = amount - line.budget_amount;

        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>
            <Table.Td ta="right" ff="monospace" c="dimmed" style={{ minWidth: 110 }}>
              {fmt(line.budget_amount)}
            </Table.Td>
            <Table.Td p={isEditing ? 2 : undefined} style={{ minWidth: 130 }}>
              {isEditing ? (
                <NumberInput
                  value={amount}
                  onChange={(v) => updateAmount(line.account_id, Number(v) || 0)}
                  size="xs"
                  hideControls
                  decimalScale={2}
                  allowNegative
                  disabled={isReadOnly}
                  styles={{ input: { textAlign: 'right', fontFamily: 'monospace' } }}
                />
              ) : (
                <Text size="sm" ff="monospace" ta="right">{fmt(amount)}</Text>
              )}
            </Table.Td>
            <Table.Td
              ta="right" ff="monospace" style={{ minWidth: 110 }}
              c={lineVariance === 0 ? 'gray' : (isExpense ? (lineVariance > 0 ? 'red' : 'green') : (lineVariance > 0 ? 'green' : 'red'))}
            >
              {lineVariance > 0 ? '+' : ''}{fmt(lineVariance)}
            </Table.Td>
          </Table.Tr>
        );
      }),
    ];
  };

  return (
    <Stack>
      <Group justify="space-between">
        <Group>
          <IconCalendarMonth size={28} />
          <Title order={2}>Monthly Actuals</Title>
        </Group>
        <Group>
          <Select data={yearOptions} value={year} onChange={(v) => v && setYear(v)} w={100} />
          <Select data={monthOptions} value={month} onChange={(v) => v && setMonth(v)} w={150} />
          {!isReadOnly && !isEditing && (
            <Button
              leftSection={<IconEdit size={16} />}
              variant="light"
              onClick={handleEditClick}
              disabled={lines.length === 0}
            >
              Edit Actuals
            </Button>
          )}
          {!isReadOnly && isEditing && (
            <Button
              leftSection={<IconDeviceFloppy size={16} />}
              onClick={() => saveMutation.mutate()}
              loading={saveMutation.isPending}
              disabled={lines.length === 0}
            >
              Save Actuals
            </Button>
          )}
        </Group>
      </Group>

      <SimpleGrid cols={{ base: 1, sm: 4 }}>
        <Card withBorder p="md">
          <Text size="xs" c="dimmed" tt="uppercase" fw={700}>Income Budget</Text>
          <Text fw={700} size="lg">{fmt(totals.incomeBudget)}</Text>
          <Text size="xs" c="dimmed">Actual: {fmt(totals.incomeActual)}</Text>
        </Card>
        <Card withBorder p="md">
          <Text size="xs" c="dimmed" tt="uppercase" fw={700}>Expense Budget</Text>
          <Text fw={700} size="lg">{fmt(totals.expenseBudget)}</Text>
          <Text size="xs" c="dimmed">Actual: {fmt(totals.expenseActual)}</Text>
        </Card>
        <Card withBorder p="md">
          <Text size="xs" c="dimmed" tt="uppercase" fw={700}>Net Budget</Text>
          <Text fw={700} size="lg" c={totals.incomeBudget - totals.expenseBudget >= 0 ? 'green' : 'red'}>
            {fmt(totals.incomeBudget - totals.expenseBudget)}
          </Text>
        </Card>
        <Card withBorder p="md">
          <Text size="xs" c="dimmed" tt="uppercase" fw={700}>Net Actual</Text>
          <Text fw={700} size="lg" c={totals.incomeActual - totals.expenseActual >= 0 ? 'green' : 'red'}>
            {fmt(totals.incomeActual - totals.expenseActual)}
          </Text>
        </Card>
      </SimpleGrid>

      {lines.length === 0 && (
        <Alert icon={<IconInfoCircle size={16} />} color="blue" variant="light">
          No income or expense accounts found for {monthLabel} {year}. Import a budget first to create accounts.
        </Alert>
      )}

      {hasExistingActuals && !isEditing && (
        <Alert icon={<IconInfoCircle size={16} />} color="green" variant="light">
          <Group justify="space-between" align="flex-start">
            <Text size="sm">
              Actuals for {monthLabel} {year} have been reconciled.
              Journal entry created and auto-posted.
            </Text>
            <Badge color="green" variant="light">Reconciled</Badge>
          </Group>
        </Alert>
      )}

      <div style={{ overflowX: 'auto' }}>
        <Table striped highlightOnHover style={{ minWidth: 700 }}>
          <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>
              <Table.Th ta="right" style={{ minWidth: 110 }}>Budget</Table.Th>
              <Table.Th ta="right" style={{ minWidth: 130 }}>Actual</Table.Th>
              <Table.Th ta="right" style={{ minWidth: 110 }}>Variance</Table.Th>
            </Table.Tr>
          </Table.Thead>
          <Table.Tbody>
            {renderSection('Income', incomeLines, incomeBg, totals.incomeBudget, totals.incomeActual)}
            {renderSection('Expenses', expenseLines, expenseBg, totals.expenseBudget, totals.expenseActual)}
          </Table.Tbody>
        </Table>
      </div>

      {/* Attachment panel - show when we have a saved journal entry for this month */}
      {savedJEId && (
        <Card withBorder>
          <Text fw={600} mb="sm">Attachments (Receipts & Invoices)</Text>
          <AttachmentPanel journalEntryId={savedJEId} />
        </Card>
      )}

      {/* Confirmation modal for editing reconciled actuals */}
      <Modal opened={confirmOpened} onClose={closeConfirm} title="Edit Reconciled Actuals" centered>
        <Stack>
          <Text size="sm">
            Actuals for <Text span fw={700}>{monthLabel} {year}</Text> have already been
            reconciled. Editing will void the existing journal entry and create a new one
            when you save.
          </Text>
          <Text size="sm" c="dimmed">
            Press Edit to proceed, or Cancel to keep the current values.
          </Text>
          <Group justify="flex-end">
            <Button variant="default" onClick={closeConfirm}>Cancel</Button>
            <Button color="orange" leftSection={<IconEdit size={16} />} onClick={handleConfirmEdit}>
              Edit
            </Button>
          </Group>
        </Stack>
      </Modal>
    </Stack>
  );
}
