import {
  Title, Text, SimpleGrid, Card, Group, ThemeIcon, Stack, Table,
  Badge, Loader, Center, Divider, RingProgress, Tooltip, Button,
  Popover, List, Anchor,
} from '@mantine/core';
import {
  IconCash,
  IconFileInvoice,
  IconShieldCheck,
  IconAlertTriangle,
  IconBuildingBank,
  IconTrendingUp,
  IconTrendingDown,
  IconMinus,
  IconHeartbeat,
  IconRefresh,
  IconInfoCircle,
} from '@tabler/icons-react';
import { useState, useCallback } from 'react';
import { useQuery, useQueryClient } from '@tanstack/react-query';
import { useNavigate } from 'react-router-dom';
import { useAuthStore, useIsReadOnly } from '../../stores/authStore';
import api from '../../services/api';

interface HealthScore {
  id: string;
  score_type: string;
  score: number;
  previous_score: number | null;
  trajectory: string | null;
  label: string;
  summary: string;
  factors: Array<{ name: string; impact: 'positive' | 'neutral' | 'negative'; detail: string }>;
  recommendations: Array<{ priority: string; text: string }>;
  missing_data: string[] | null;
  status: string;
  response_time_ms: number | null;
  calculated_at: string;
}

interface HealthScoresData {
  operating: HealthScore | null;
  reserve: HealthScore | null;
  operating_last_failed?: boolean;
  reserve_last_failed?: boolean;
}

function getScoreColor(score: number): string {
  if (score >= 75) return 'green';
  if (score >= 60) return 'yellow';
  if (score >= 40) return 'orange';
  return 'red';
}

function TrajectoryIcon({ trajectory }: { trajectory: string | null }) {
  if (trajectory === 'improving') return <IconTrendingUp size={16} color="var(--mantine-color-green-6)" />;
  if (trajectory === 'declining') return <IconTrendingDown size={16} color="var(--mantine-color-red-6)" />;
  if (trajectory === 'stable') return <IconMinus size={16} color="var(--mantine-color-gray-6)" />;
  return null;
}

// Map missing data items to navigation links
const missingDataLinks: Record<string, { label: string; path: string }> = {
  'reserve fund account': { label: 'Set up a reserve account', path: '/accounts' },
  'reserve account': { label: 'Set up a reserve account', path: '/accounts' },
  'reserve projects': { label: 'Add reserve projects', path: '/projects' },
  'capital projects': { label: 'Add capital projects', path: '/projects' },
  'projects': { label: 'Add projects', path: '/projects' },
  'budget': { label: 'Set up a budget', path: '/board-planning/budgets' },
  'operating budget': { label: 'Set up a budget', path: '/board-planning/budgets' },
  'reserve budget': { label: 'Set up a budget', path: '/board-planning/budgets' },
  'assessment groups': { label: 'Create assessment groups', path: '/assessment-groups' },
  'accounts': { label: 'Set up accounts', path: '/accounts' },
};

function getMissingDataLink(item: string): { label: string; path: string } | null {
  const lower = item.toLowerCase();
  for (const [key, value] of Object.entries(missingDataLinks)) {
    if (lower.includes(key)) return value;
  }
  return null;
}

function HealthScoreCard({
  score,
  title,
  icon,
  isRefreshing,
  onRefresh,
  lastFailed,
  onNavigate,
}: {
  score: HealthScore | null;
  title: string;
  icon: React.ReactNode;
  isRefreshing?: boolean;
  onRefresh?: () => void;
  lastFailed?: boolean;
  onNavigate?: (path: string) => void;
}) {
  // No score at all yet
  if (!score) {
    return (
      <Card withBorder padding="lg" radius="md">
        <Group justify="space-between" mb="xs">
          <Text size="xs" c="dimmed" tt="uppercase" fw={700}>{title} Health</Text>
          <Group gap={6}>
            {onRefresh && (
              <Tooltip label={`Recalculate ${title.toLowerCase()} score`}>
                <Button variant="subtle" size="compact-xs" leftSection={<IconRefresh size={14} />}
                  loading={isRefreshing} onClick={onRefresh}>Refresh</Button>
              </Tooltip>
            )}
            {icon}
          </Group>
        </Group>
        <Center h={100}>
          <Text c="dimmed" size="sm">No health score yet</Text>
        </Center>
      </Card>
    );
  }

  // Pending — missing data, can't calculate
  if (score.status === 'pending') {
    const missingItems = Array.isArray(score.missing_data) ? score.missing_data :
      (typeof score.missing_data === 'string' ? JSON.parse(score.missing_data) : []);
    return (
      <Card withBorder padding="lg" radius="md">
        <Group justify="space-between" mb="xs">
          <Text size="xs" c="dimmed" tt="uppercase" fw={700}>{title} Health</Text>
          <Group gap={6}>
            {onRefresh && (
              <Tooltip label={`Recalculate ${title.toLowerCase()} score`}>
                <Button variant="subtle" size="compact-xs" leftSection={<IconRefresh size={14} />}
                  loading={isRefreshing} onClick={onRefresh}>Refresh</Button>
              </Tooltip>
            )}
            {icon}
          </Group>
        </Group>
        <Center>
          <Stack align="center" gap="xs">
            <Badge color="gray" variant="light" size="lg">Pending</Badge>
            <Text size="xs" c="dimmed" ta="center">Missing data:</Text>
            {missingItems.map((item: string, i: number) => {
              const link = getMissingDataLink(item);
              return link ? (
                <Anchor key={i} size="xs" href={link.path} onClick={(e: React.MouseEvent) => {
                  e.preventDefault();
                  onNavigate?.(link.path);
                }}>
                  {item} &rarr; {link.label}
                </Anchor>
              ) : (
                <Text key={i} size="xs" c="dimmed" ta="center">{item}</Text>
              );
            })}
          </Stack>
        </Center>
      </Card>
    );
  }

  // For error status, we still render the score data (cached from the previous
  // successful run) rather than blanking the card with "Error calculating score".
  // A small watermark under the timestamp tells the user it's stale.
  const showAsError = score.status === 'error' && score.score === 0 && !score.summary;

  // Pure error with no cached data to fall back on
  if (showAsError) {
    return (
      <Card withBorder padding="lg" radius="md">
        <Group justify="space-between" mb="xs">
          <Text size="xs" c="dimmed" tt="uppercase" fw={700}>{title} Health</Text>
          <Group gap={6}>
            {onRefresh && (
              <Tooltip label={`Retry ${title.toLowerCase()} score`}>
                <Button variant="subtle" size="compact-xs" leftSection={<IconRefresh size={14} />}
                  loading={isRefreshing} onClick={onRefresh}>Retry</Button>
              </Tooltip>
            )}
            {icon}
          </Group>
        </Group>
        <Center h={100}>
          <Stack align="center" gap={4}>
            <Badge color="red" variant="light">Error calculating score</Badge>
            <Text size="xs" c="dimmed">Click Retry to try again</Text>
          </Stack>
        </Center>
      </Card>
    );
  }

  // Normal display — works for both 'complete' and 'error' (with cached data)
  const color = getScoreColor(score.score);
  const factors = Array.isArray(score.factors) ? score.factors :
    (typeof score.factors === 'string' ? JSON.parse(score.factors) : []);
  const recommendations = Array.isArray(score.recommendations) ? score.recommendations :
    (typeof score.recommendations === 'string' ? JSON.parse(score.recommendations) : []);

  return (
    <Card withBorder padding="lg" radius="md">
      <Group justify="space-between" mb="xs">
        <Text size="xs" c="dimmed" tt="uppercase" fw={700}>{title} Health</Text>
        <Group gap={6}>
          {onRefresh && (
            <Tooltip label={`Recalculate ${title.toLowerCase()} score`}>
              <Button variant="subtle" size="compact-xs" leftSection={<IconRefresh size={14} />}
                loading={isRefreshing} onClick={onRefresh}>Refresh</Button>
            </Tooltip>
          )}
          {icon}
        </Group>
      </Group>
      <Group align="flex-start" gap="lg">
        <RingProgress
          size={120}
          thickness={12}
          roundCaps
          sections={[{ value: score.score, color }]}
          label={
            <Stack align="center" gap={0}>
              <Text fw={700} size="xl" ta="center" lh={1}>{score.score}</Text>
              <Text size="xs" c="dimmed" ta="center">/100</Text>
            </Stack>
          }
        />
        <Stack gap={4} style={{ flex: 1, minWidth: 0 }}>
          <Group gap={6}>
            <Badge color={color} variant="light" size="sm">{score.label}</Badge>
            {score.trajectory && (
              <Tooltip label={`Trend: ${score.trajectory}`}>
                <Group gap={2}>
                  <TrajectoryIcon trajectory={score.trajectory} />
                  <Text size="xs" c="dimmed">{score.trajectory}</Text>
                </Group>
              </Tooltip>
            )}
            {score.previous_score !== null && (
              <Text size="xs" c="dimmed">(prev: {score.previous_score})</Text>
            )}
          </Group>
          <Text size="sm" lineClamp={2}>{score.summary}</Text>
          <Group gap={4} mt={2}>
            {factors.slice(0, 3).map((f: any, i: number) => (
              <Tooltip key={i} label={f.detail} multiline w={280}>
                <Badge
                  size="xs"
                  variant="dot"
                  color={f.impact === 'positive' ? 'green' : f.impact === 'negative' ? 'red' : 'gray'}
                >
                  {f.name}
                </Badge>
              </Tooltip>
            ))}
            {(factors.length > 3 || recommendations.length > 0) && (
              <Popover width={350} position="bottom" shadow="md">
                <Popover.Target>
                  <Badge size="xs" variant="light" color="blue" style={{ cursor: 'pointer' }}>
                    <IconInfoCircle size={10} /> Details
                  </Badge>
                </Popover.Target>
                <Popover.Dropdown>
                  <Stack gap="xs">
                    {factors.length > 0 && (
                      <>
                        <Text fw={600} size="xs">Factors</Text>
                        {factors.map((f: any, i: number) => (
                          <Group key={i} gap={6} wrap="nowrap">
                            <Badge
                              size="xs"
                              variant="dot"
                              color={f.impact === 'positive' ? 'green' : f.impact === 'negative' ? 'red' : 'gray'}
                              style={{ flexShrink: 0 }}
                            >
                              {f.name}
                            </Badge>
                            <Text size="xs" c="dimmed">{f.detail}</Text>
                          </Group>
                        ))}
                      </>
                    )}
                    {recommendations.length > 0 && (
                      <>
                        <Divider my={4} />
                        <Text fw={600} size="xs">Recommendations</Text>
                        <List size="xs" spacing={4}>
                          {recommendations.map((r: any, i: number) => (
                            <List.Item key={i}>
                              <Badge size="xs" color={r.priority === 'high' ? 'red' : r.priority === 'medium' ? 'yellow' : 'blue'} variant="light" mr={4}>
                                {r.priority}
                              </Badge>
                              {r.text}
                            </List.Item>
                          ))}
                        </List>
                      </>
                    )}
                    {score.calculated_at && (
                      <Text size="xs" c="dimmed" ta="right" mt={4}>
                        Updated: {new Date(score.calculated_at).toLocaleString()}
                      </Text>
                    )}
                  </Stack>
                </Popover.Dropdown>
              </Popover>
            )}
          </Group>
        </Stack>
      </Group>
      {score.calculated_at && (
        <Stack gap={0} mt={6} align="flex-end">
          <Text size="10px" c="dimmed" style={{ opacity: 0.7 }}>
            Last updated {new Date(score.calculated_at).toLocaleDateString()} at {new Date(score.calculated_at).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}
          </Text>
          {lastFailed && (
            <Text size="10px" c="orange" fw={500} style={{ opacity: 0.85 }}>
              last analysis failed — showing cached data
            </Text>
          )}
        </Stack>
      )}
    </Card>
  );
}

interface DashboardData {
  total_cash: string;
  total_receivables: string;
  reserve_fund_balance: string;
  delinquent_units: number;
  recent_transactions: {
    id: string; entry_date: string; description: string; entry_type: string; amount: string;
  }[];
  // Enhanced split data
  operating_cash: string;
  reserve_cash: string;
  operating_investments: string;
  reserve_investments: string;
  est_monthly_interest: string;
  interest_earned_ytd: string;
  interest_last_year: string;
  interest_projected: string;
  planned_capital_spend: string;
}

export function DashboardPage() {
  const currentOrg = useAuthStore((s) => s.currentOrg);
  const isReadOnly = useIsReadOnly();
  const queryClient = useQueryClient();
  const navigate = useNavigate();

  // Track whether a refresh is in progress (per score type) for async polling
  const [operatingRefreshing, setOperatingRefreshing] = useState(false);
  const [reserveRefreshing, setReserveRefreshing] = useState(false);

  const { data, isLoading } = useQuery<DashboardData>({
    queryKey: ['dashboard'],
    queryFn: async () => { const { data } = await api.get('/reports/dashboard'); return data; },
    enabled: !!currentOrg,
  });

  const { data: healthScores } = useQuery<HealthScoresData>({
    queryKey: ['health-scores'],
    queryFn: async () => { const { data } = await api.get('/health-scores/latest'); return data; },
    enabled: !!currentOrg,
    // Poll every 3 seconds while a refresh is in progress
    refetchInterval: (operatingRefreshing || reserveRefreshing) ? 3000 : false,
  });

  // Async refresh handlers — trigger the backend and poll for results
  const handleRefreshOperating = useCallback(async () => {
    const prevId = healthScores?.operating?.id;
    setOperatingRefreshing(true);
    try {
      await api.post('/health-scores/calculate/operating');
    } catch {
      // Trigger failed at network level — polling will pick up any backend-saved error
    }
    // Start polling — watch for the health score to change (new id or updated timestamp)
    const pollUntilDone = () => {
      const checkInterval = setInterval(async () => {
        try {
          const { data: latest } = await api.get('/health-scores/latest');
          const newScore = latest?.operating;
          if (newScore && newScore.id !== prevId) {
            setOperatingRefreshing(false);
            queryClient.setQueryData(['health-scores'], latest);
            clearInterval(checkInterval);
          }
        } catch {
          // Keep polling
        }
      }, 3000);
      // Safety timeout — stop polling after 11 minutes
      setTimeout(() => { clearInterval(checkInterval); setOperatingRefreshing(false); }, 660000);
    };
    pollUntilDone();
  }, [healthScores?.operating?.id, queryClient]);

  const handleRefreshReserve = useCallback(async () => {
    const prevId = healthScores?.reserve?.id;
    setReserveRefreshing(true);
    try {
      await api.post('/health-scores/calculate/reserve');
    } catch {
      // Trigger failed at network level
    }
    const pollUntilDone = () => {
      const checkInterval = setInterval(async () => {
        try {
          const { data: latest } = await api.get('/health-scores/latest');
          const newScore = latest?.reserve;
          if (newScore && newScore.id !== prevId) {
            setReserveRefreshing(false);
            queryClient.setQueryData(['health-scores'], latest);
            clearInterval(checkInterval);
          }
        } catch {
          // Keep polling
        }
      }, 3000);
      setTimeout(() => { clearInterval(checkInterval); setReserveRefreshing(false); }, 660000);
    };
    pollUntilDone();
  }, [healthScores?.reserve?.id, queryClient]);

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

  const opInv = parseFloat(data?.operating_investments || '0');
  const resInv = parseFloat(data?.reserve_investments || '0');

  const entryTypeColors: Record<string, string> = {
    manual: 'gray', assessment: 'blue', payment: 'green', late_fee: 'red',
    transfer: 'cyan', adjustment: 'yellow', closing: 'dark', opening_balance: 'indigo',
  };

  return (
    <Stack data-tour="dashboard-content">
      <Title order={2}>Dashboard</Title>

      {!currentOrg ? (
        <Card withBorder p="xl" ta="center">
          <Text size="lg" fw={500}>Welcome to HOA LedgerIQ</Text>
          <Text c="dimmed" mt="sm">
            Create or select an organization to get started.
          </Text>
        </Card>
      ) : isLoading ? (
        <Center h={200}><Loader /></Center>
      ) : (
        <>
          <SimpleGrid cols={{ base: 1, md: 2 }}>
            <HealthScoreCard
              score={healthScores?.operating || null}
              title="Operating Fund"
              icon={
                <ThemeIcon color="green" variant="light" size={36} radius="md">
                  <IconHeartbeat size={20} />
                </ThemeIcon>
              }
              isRefreshing={operatingRefreshing}
              onRefresh={!isReadOnly ? handleRefreshOperating : undefined}
              lastFailed={!!healthScores?.operating_last_failed}
              onNavigate={navigate}
            />
            <HealthScoreCard
              score={healthScores?.reserve || null}
              title="Reserve Fund"
              icon={
                <ThemeIcon color="violet" variant="light" size={36} radius="md">
                  <IconHeartbeat size={20} />
                </ThemeIcon>
              }
              isRefreshing={reserveRefreshing}
              onRefresh={!isReadOnly ? handleRefreshReserve : undefined}
              lastFailed={!!healthScores?.reserve_last_failed}
              onNavigate={navigate}
            />
          </SimpleGrid>

          <SimpleGrid cols={{ base: 1, sm: 2, lg: 4 }}>
            <Card withBorder padding="lg" radius="md">
              <Group justify="space-between">
                <div>
                  <Text size="xs" c="dimmed" tt="uppercase" fw={700}>Operating Fund</Text>
                  <Text fw={700} size="xl">{fmt(data?.operating_cash || '0')}</Text>
                  {opInv > 0 && <Text size="xs" c="teal">Investments: {fmt(opInv)}</Text>}
                </div>
                <ThemeIcon color="green" variant="light" size={48} radius="md">
                  <IconCash size={28} />
                </ThemeIcon>
              </Group>
            </Card>
            <Card withBorder padding="lg" radius="md">
              <Group justify="space-between">
                <div>
                  <Text size="xs" c="dimmed" tt="uppercase" fw={700}>Reserve Fund</Text>
                  <Text fw={700} size="xl">{fmt(data?.reserve_cash || '0')}</Text>
                  {resInv > 0 && <Text size="xs" c="teal">Investments: {fmt(resInv)}</Text>}
                </div>
                <ThemeIcon color="violet" variant="light" size={48} radius="md">
                  <IconShieldCheck size={28} />
                </ThemeIcon>
              </Group>
            </Card>
            <Card withBorder padding="lg" radius="md">
              <Group justify="space-between">
                <div>
                  <Text size="xs" c="dimmed" tt="uppercase" fw={700}>Total Receivables</Text>
                  <Text fw={700} size="xl">{fmt(data?.total_receivables || '0')}</Text>
                </div>
                <ThemeIcon color="blue" variant="light" size={48} radius="md">
                  <IconFileInvoice size={28} />
                </ThemeIcon>
              </Group>
            </Card>
            <Card withBorder padding="lg" radius="md">
              <Group justify="space-between">
                <div>
                  <Text size="xs" c="dimmed" tt="uppercase" fw={700}>Delinquent Accounts</Text>
                  <Text fw={700} size="xl">{String(data?.delinquent_units || 0)}</Text>
                </div>
                <ThemeIcon color="orange" variant="light" size={48} radius="md">
                  <IconAlertTriangle size={28} />
                </ThemeIcon>
              </Group>
            </Card>
          </SimpleGrid>

          <SimpleGrid cols={{ base: 1, md: 2 }}>
            <Card withBorder padding="lg" radius="md">
              <Title order={4}>Quick Stats</Title>
              <Stack mt="sm" gap="xs">
                <Group justify="space-between">
                  <Text size="sm" c="dimmed">Operating Cash</Text>
                  <Text size="sm" fw={500} c="green">{fmt(data?.operating_cash || '0')}</Text>
                </Group>
                <Group justify="space-between">
                  <Text size="sm" c="dimmed">Reserve Cash</Text>
                  <Text size="sm" fw={500} c="violet">{fmt(data?.reserve_cash || '0')}</Text>
                </Group>
                <Divider my={4} />
                <Group justify="space-between">
                  <Text size="sm" c="dimmed">Est. Monthly Interest</Text>
                  <Text size="sm" fw={500} c="blue">{fmt(data?.est_monthly_interest || '0')}</Text>
                </Group>
                <Group justify="space-between">
                  <Text size="sm" c="dimmed">Interest Earned YTD</Text>
                  <Text size="sm" fw={500} c="teal">{fmt(data?.interest_earned_ytd || '0')}</Text>
                </Group>
                <Group justify="space-between">
                  <Text size="sm" c="dimmed">Interest Earned YoY</Text>
                  <Group gap={6}>
                    <Text size="sm" fw={500} c="teal">{fmt(data?.interest_projected || '0')}</Text>
                    <Text size="xs" c="dimmed">proj</Text>
                    <Text size="xs" c="dimmed">vs</Text>
                    <Text size="sm" fw={500} c="gray">{fmt(data?.interest_last_year || '0')}</Text>
                    <Text size="xs" c="dimmed">prev</Text>
                    {(() => {
                      const proj = parseFloat(data?.interest_projected || '0');
                      const prev = parseFloat(data?.interest_last_year || '0');
                      const diff = proj - prev;
                      if (prev === 0 && proj === 0) return null;
                      return (
                        <Badge size="xs" color={diff >= 0 ? 'green' : 'red'} variant="light">
                          {diff >= 0 ? '+' : ''}{prev > 0 ? ((diff / prev) * 100).toFixed(0) : '—'}%
                        </Badge>
                      );
                    })()}
                  </Group>
                </Group>
                <Divider my={4} />
                <Text size="xs" c="dimmed" tt="uppercase" fw={700}>Capital Projects</Text>
                <Group justify="space-between">
                  <Text size="sm" c="dimmed">Planned Capital Spend {new Date().getFullYear()}</Text>
                  <Text size="sm" fw={500} c="orange">{fmt(data?.planned_capital_spend || '0')}</Text>
                </Group>
                <Divider my={4} />
                <Group justify="space-between">
                  <Text size="sm" c="dimmed">Outstanding AR</Text>
                  <Text size="sm" fw={500} c="blue">{fmt(data?.total_receivables || '0')}</Text>
                </Group>
                <Group justify="space-between">
                  <Text size="sm" c="dimmed">Delinquent Units</Text>
                  <Text size="sm" fw={500} c={data?.delinquent_units ? 'red' : 'green'}>
                    {data?.delinquent_units || 0}
                  </Text>
                </Group>
              </Stack>
            </Card>
            <Card withBorder padding="lg" radius="md">
              <Title order={4} mb="sm">Recent Transactions</Title>
              {(data?.recent_transactions || []).length === 0 ? (
                <Text c="dimmed" size="sm">No transactions yet. Start by entering journal entries.</Text>
              ) : (
                <Table striped highlightOnHover>
                  <Table.Tbody>
                    {(data?.recent_transactions || []).map((tx) => (
                      <Table.Tr key={tx.id}>
                        <Table.Td>
                          <Text size="xs" c="dimmed">{new Date(tx.entry_date).toLocaleDateString()}</Text>
                        </Table.Td>
                        <Table.Td>
                          <Text size="sm" lineClamp={1}>{tx.description}</Text>
                        </Table.Td>
                        <Table.Td>
                          <Badge size="xs" color={entryTypeColors[tx.entry_type] || 'gray'} variant="light">
                            {tx.entry_type}
                          </Badge>
                        </Table.Td>
                        <Table.Td ta="right" ff="monospace" fw={500}>
                          {fmt(tx.amount)}
                        </Table.Td>
                      </Table.Tr>
                    ))}
                  </Table.Tbody>
                </Table>
              )}
            </Card>
          </SimpleGrid>
        </>
      )}
    </Stack>
  );
}
