import { useState, useRef } 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, IconUpload, IconDownload, IconInfoCircle } from '@tabler/icons-react';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import api from '../../services/api';

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'];

/**
 * Parse a currency-formatted value: "$48,065.21", "$(13,000.00)", " $-   "
 */
function parseCurrencyValue(val: string): number {
  if (!val) return 0;
  let s = val.trim();
  if (!s || s === '-' || s === '$-' || s === '$ -') return 0;

  const isNegative = s.includes('(') && s.includes(')');
  s = s.replace(/[$,\s()]/g, '');
  if (!s || s === '-') return 0;

  const num = parseFloat(s);
  if (isNaN(num)) return 0;
  return isNegative ? -num : num;
}

function parseCSV(text: string): Record<string, string>[] {
  const lines = text.trim().split('\n');
  if (lines.length < 2) return [];

  const headers = lines[0].split(',').map((h) => h.trim().toLowerCase());
  const rows: Record<string, string>[] = [];

  for (let i = 1; i < lines.length; i++) {
    const line = lines[i].trim();
    if (!line) continue;

    // Handle quoted fields containing commas
    const values: string[] = [];
    let current = '';
    let inQuotes = false;
    for (let j = 0; j < line.length; j++) {
      const ch = line[j];
      if (ch === '"') {
        inQuotes = !inQuotes;
      } else if (ch === ',' && !inQuotes) {
        values.push(current.trim());
        current = '';
      } else {
        current += ch;
      }
    }
    values.push(current.trim());

    const row: Record<string, string> = {};
    headers.forEach((h, idx) => {
      row[h] = values[idx] || '';
    });
    rows.push(row);
  }

  return rows;
}

export function BudgetsPage() {
  const [year, setYear] = useState(new Date().getFullYear().toString());
  const [budgetData, setBudgetData] = useState<BudgetLine[]>([]);
  const queryClient = useQueryClient();
  const fileInputRef = useRef<HTMLInputElement>(null);

  const { isLoading } = useQuery<BudgetLine[]>({
    queryKey: ['budgets', year],
    queryFn: async () => {
      const { data } = await api.get(`/budgets/${year}`);
      setBudgetData(data);
      return data;
    },
  });

  const saveMutation = useMutation({
    mutationFn: async () => {
      const lines = budgetData
        .filter((b) => months.some((m) => (b as any)[m] > 0))
        .map((b) => ({
          account_id: b.account_id,
          fund_type: 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_amt: b.dec_amt,
        }));
      return api.put(`/budgets/${year}`, { lines });
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['budgets', year] });
      notifications.show({ message: 'Budget saved', color: 'green' });
    },
    onError: (err: any) => {
      notifications.show({ message: err.response?.data?.message || 'Save failed', color: 'red' });
    },
  });

  const importMutation = useMutation({
    mutationFn: async (lines: Record<string, string>[]) => {
      const parsed = lines.map((row) => ({
        account_number: row.account_number || row.accountnumber || '',
        account_name: row.account_name || row.accountname || '',
        jan: parseCurrencyValue(row.jan),
        feb: parseCurrencyValue(row.feb),
        mar: parseCurrencyValue(row.mar),
        apr: parseCurrencyValue(row.apr),
        may: parseCurrencyValue(row.may),
        jun: parseCurrencyValue(row.jun),
        jul: parseCurrencyValue(row.jul),
        aug: parseCurrencyValue(row.aug),
        sep: parseCurrencyValue(row.sep),
        oct: parseCurrencyValue(row.oct),
        nov: parseCurrencyValue(row.nov),
        dec_amt: parseCurrencyValue(row.dec_amt || row.dec || ''),
      }));
      const { data } = await api.post(`/budgets/${year}/import`, parsed);
      return data;
    },
    onSuccess: (data) => {
      queryClient.invalidateQueries({ queryKey: ['budgets', year] });
      queryClient.invalidateQueries({ queryKey: ['accounts'] });
      let msg = `Imported ${data.imported} budget line(s)`;
      if (data.created?.length) {
        msg += `. Created ${data.created.length} new account(s)`;
      }
      if (data.errors?.length) {
        msg += `. ${data.errors.length} error(s): ${data.errors.join('; ')}`;
      }
      notifications.show({
        message: msg,
        color: data.errors?.length ? 'yellow' : 'green',
        autoClose: 10000,
      });
    },
    onError: (err: any) => {
      notifications.show({ message: err.response?.data?.message || 'Import failed', color: 'red' });
    },
  });

  const handleDownloadTemplate = async () => {
    try {
      const response = await api.get(`/budgets/${year}/template`, {
        responseType: 'blob',
      });
      const blob = new Blob([response.data], { type: 'text/csv' });
      const url = window.URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url;
      a.download = `budget_template_${year}.csv`;
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);
      window.URL.revokeObjectURL(url);
    } catch (err: any) {
      notifications.show({ message: 'Failed to download template', color: 'red' });
    }
  };

  const handleImportCSV = () => {
    fileInputRef.current?.click();
  };

  const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    const file = event.target.files?.[0];
    if (!file) return;

    const reader = new FileReader();
    reader.onload = (e) => {
      const text = e.target?.result as string;
      if (!text) {
        notifications.show({ message: 'Could not read file', color: 'red' });
        return;
      }
      const rows = parseCSV(text);
      if (rows.length === 0) {
        notifications.show({ message: 'No data rows found in CSV', color: 'red' });
        return;
      }
      importMutation.mutate(rows);
    };
    reader.readAsText(file);

    // Reset input so the same file can be re-selected
    event.target.value = '';
  };

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

  const yearOptions = 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 });

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

  const incomeLines = budgetData.filter((b) => b.account_type === 'income');
  const expenseLines = budgetData.filter((b) => b.account_type === 'expense');
  const totalIncome = months.reduce((s, m) => s + incomeLines.reduce((a, b) => a + ((b as any)[m] || 0), 0), 0);
  const totalExpense = months.reduce((s, m) => s + expenseLines.reduce((a, b) => a + ((b as any)[m] || 0), 0), 0);

  return (
    <Stack>
      <Group justify="space-between">
        <Title order={2}>Budget Manager</Title>
        <Group>
          <Select data={yearOptions} value={year} onChange={(v) => v && setYear(v)} w={120} />
          <Button
            variant="outline"
            leftSection={<IconDownload size={16} />}
            onClick={handleDownloadTemplate}
          >
            Download Template
          </Button>
          <Button
            variant="outline"
            leftSection={<IconUpload size={16} />}
            onClick={handleImportCSV}
            loading={importMutation.isPending}
          >
            Import CSV
          </Button>
          <input
            type="file"
            ref={fileInputRef}
            style={{ display: 'none' }}
            accept=".csv,.txt"
            onChange={handleFileChange}
          />
          <Button leftSection={<IconDeviceFloppy size={16} />} onClick={() => saveMutation.mutate()} loading={saveMutation.isPending}>
            Save Budget
          </Button>
        </Group>
      </Group>

      {budgetData.length === 0 && !isLoading && (
        <Alert icon={<IconInfoCircle size={16} />} color="blue" variant="light">
          No budget data for {year}. Import a CSV to get started. Your CSV should have columns:{' '}
          <Text span ff="monospace" size="xs">account_number, account_name, jan, feb, ..., dec</Text>.
          Accounts will be auto-created if they don&apos;t exist yet.
        </Alert>
      )}

      <Group>
        <Card withBorder p="sm">
          <Text size="xs" c="dimmed">Total Income</Text>
          <Text fw={700} c="green">{fmt(totalIncome)}</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</Text>
          <Text fw={700} c={totalIncome - totalExpense >= 0 ? 'green' : 'red'}>
            {fmt(totalIncome - totalExpense)}
          </Text>
        </Card>
      </Group>

      <div style={{ overflowX: 'auto' }}>
        <Table striped highlightOnHover style={{ minWidth: 1400 }}>
          <Table.Thead>
            <Table.Tr>
              <Table.Th style={{ position: 'sticky', left: 0, background: 'white', zIndex: 1, minWidth: 280 }}>Account</Table.Th>
              {monthLabels.map((m) => (
                <Table.Th key={m} ta="right" style={{ minWidth: 90 }}>{m}</Table.Th>
              ))}
              <Table.Th ta="right" style={{ minWidth: 100 }}>Annual</Table.Th>
            </Table.Tr>
          </Table.Thead>
          <Table.Tbody>
            {budgetData.length === 0 && (
              <Table.Tr>
                <Table.Td colSpan={14}>
                  <Text ta="center" c="dimmed" py="lg">No budget data. Import a CSV or add income/expense accounts to get started.</Text>
                </Table.Td>
              </Table.Tr>
            )}
            {['income', 'expense'].map((type) => {
              const lines = budgetData.filter((b) => b.account_type === type);
              if (lines.length === 0) return null;
              return [
                <Table.Tr key={`header-${type}`} style={{ background: type === 'income' ? '#e6f9e6' : '#fde8e8' }}>
                  <Table.Td colSpan={14} fw={700} tt="capitalize">{type}</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: 'white', zIndex: 1 }}>
                        <Group gap="xs">
                          <Text size="sm" c="dimmed">{line.account_number}</Text>
                          <Text size="sm">{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}>
                          <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' } }}
                          />
                        </Table.Td>
                      ))}
                      <Table.Td ta="right" fw={500} ff="monospace">
                        {fmt(line.annual_total || 0)}
                      </Table.Td>
                    </Table.Tr>
                  );
                }),
              ];
            })}
          </Table.Tbody>
        </Table>
      </div>
    </Stack>
  );
}
