import { Ionicons } from "@expo/vector-icons";
import { router } from "expo-router";
import { useMemo, useState } from "react";
import {
  Pressable,
  RefreshControl,
  ScrollView,
  StyleSheet,
  Text,
  View,
} from "react-native";
import type { AppRouter } from "beenvoice/server/api/root";
import type { inferRouterOutputs } from "@trpc/server";

import { AppBackground } from "@/components/AppBackground";
import { FilterChip } from "@/components/FilterChip";
import { LoadingScreen } from "@/components/LoadingScreen";
import { PageHeader } from "@/components/PageHeader";
import { SwipeableRow } from "@/components/SwipeableRow";
import { TabPage } from "@/components/TabPage";
import { TabScrollView } from "@/components/TabScrollView";
import { Button } from "@/components/ui/Button";
import { fonts, radii, spacing } from "@/constants/theme";
import { useAppTheme } from "@/contexts/ThemeContext";
import { formatCurrency, formatDate } from "@/lib/format";
import { api } from "@/lib/trpc";
import { formatTrpcErrorMessage } from "@/lib/trpc-errors";
import type { ThemeColors } from "@/lib/theme-palette";
import { useThemedStyles } from "@/lib/use-themed-styles";

type ExpenseFilter = "all" | "billable" | "receipts";
type Expense = inferRouterOutputs<AppRouter>["expenses"]["getAll"][number];

export default function ExpensesScreen() {
  const { colors } = useAppTheme();
  const styles = useThemedStyles(createStyles);
  const utils = api.useUtils();
  const [filter, setFilter] = useState<ExpenseFilter>("all");
  const expensesQuery = api.expenses.getAll.useQuery();

  const deleteExpense = api.expenses.delete.useMutation({
    onSuccess: () => void utils.expenses.getAll.invalidate(),
  });

  const expenses = expensesQuery.data ?? [];
  const filteredExpenses = useMemo(
    () =>
      expenses.filter((expense) => {
        if (filter === "billable") return expense.billable;
        if (filter === "receipts") return expense.receiptCount > 0;
        return true;
      }),
    [expenses, filter],
  );
  const summary = useMemo(() => {
    const total = filteredExpenses.reduce(
      (sum, expense) => sum + expense.amount,
      0,
    );
    const billable = filteredExpenses.reduce(
      (sum, expense) => sum + (expense.billable ? expense.amount : 0),
      0,
    );
    const receiptCount = filteredExpenses.reduce(
      (sum, expense) => sum + (expense.receiptCount ?? 0),
      0,
    );
    return { total, billable, receiptCount };
  }, [filteredExpenses]);
  const groupedExpenses = useMemo(
    () => groupExpensesByMonth(filteredExpenses),
    [filteredExpenses],
  );

  if (expensesQuery.isLoading) {
    return <LoadingScreen message="Loading expenses..." />;
  }

  if (expensesQuery.error) {
    return (
      <AppBackground>
        <TabPage showMoreBack>
          <View style={styles.errorBox}>
            <PageHeader title="Expenses" subtitle="Expense tracking" />
            <Text style={[styles.errorTitle, { color: colors.foreground }]}>
              Could not load expenses
            </Text>
            <Text style={{ color: colors.mutedForeground }}>
              {formatTrpcErrorMessage(expensesQuery.error)}
            </Text>
          </View>
        </TabPage>
      </AppBackground>
    );
  }

  return (
    <AppBackground>
      <TabPage showMoreBack>
        <TabScrollView
          header={
            <View style={styles.header}>
              <PageHeader
                title="Expenses"
                subtitle={`${expenses.length} recorded expense${expenses.length === 1 ? "" : "s"}`}
              />
              <Button
                title="Add expense"
                onPress={() => router.push("/(app)/more/expenses/new" as never)}
              />
            </View>
          }
          refreshControl={
            <RefreshControl
              refreshing={expensesQuery.isRefetching}
              onRefresh={() => void expensesQuery.refetch()}
              tintColor={colors.primary}
            />
          }
        >
          {expenses.length === 0 ? (
            <View
              style={[
                styles.emptyCard,
                { borderColor: colors.border, backgroundColor: colors.cardGlass },
              ]}
            >
              <View style={[styles.emptyIcon, { backgroundColor: colors.muted }]}>
                <Ionicons name="receipt-outline" size={24} color={colors.primary} />
              </View>
              <Text style={[styles.emptyTitle, { color: colors.foreground }]}>
                No expenses yet
              </Text>
              <Text style={[styles.empty, { color: colors.mutedForeground }]}>
                Scan a receipt or add a manual entry when something needs to be tracked, billed, or reimbursed.
              </Text>
              <Button
                title="Add expense"
                onPress={() => router.push("/(app)/more/expenses/new" as never)}
              />
            </View>
          ) : (
            <>
              <View style={styles.summaryGrid}>
                <SummaryTile label="Visible total" value={formatCurrency(summary.total)} />
                <SummaryTile label="Billable" value={formatCurrency(summary.billable)} />
                <SummaryTile label="Receipts" value={String(summary.receiptCount)} />
              </View>

              <ScrollView
                horizontal
                showsHorizontalScrollIndicator={false}
                contentContainerStyle={styles.filters}
              >
                <FilterChip
                  label="All"
                  active={filter === "all"}
                  onPress={() => setFilter("all")}
                />
                <FilterChip
                  label="Billable"
                  active={filter === "billable"}
                  onPress={() => setFilter("billable")}
                />
                <FilterChip
                  label="With receipts"
                  active={filter === "receipts"}
                  onPress={() => setFilter("receipts")}
                />
              </ScrollView>

              {filteredExpenses.length === 0 ? (
                <Text style={[styles.empty, { color: colors.mutedForeground }]}>
                  No expenses match this filter.
                </Text>
              ) : (
                groupedExpenses.map(([monthLabel, group]) => (
                  <View key={monthLabel} style={styles.monthGroup}>
                    <Text style={[styles.monthLabel, { color: colors.mutedForeground }]}>
                      {monthLabel}
                    </Text>
                    {group.map((expense) => (
                      <ExpenseRow
                        key={expense.id}
                        expense={expense}
                        onDelete={() => deleteExpense.mutate({ id: expense.id })}
                      />
                    ))}
                  </View>
                ))
              )}
            </>
          )}
        </TabScrollView>
      </TabPage>
    </AppBackground>
  );
}

function SummaryTile({ label, value }: { label: string; value: string }) {
  const { colors } = useAppTheme();
  const styles = useThemedStyles(createStyles);

  return (
    <View
      style={[
        styles.summaryTile,
        { borderColor: colors.border, backgroundColor: colors.cardGlass },
      ]}
    >
      <Text style={[styles.summaryLabel, { color: colors.mutedForeground }]}>
        {label}
      </Text>
      <Text style={[styles.summaryValue, { color: colors.foreground }]} numberOfLines={1}>
        {value}
      </Text>
    </View>
  );
}

function ExpenseRow({ expense, onDelete }: { expense: Expense; onDelete: () => void }) {
  const { colors } = useAppTheme();
  const styles = useThemedStyles(createStyles);

  return (
    <SwipeableRow
      backgroundColor={colors.cardGlass}
      actions={[
        {
          key: "open",
          label: "Open",
          icon: "open-outline",
          color: "#fff",
          backgroundColor: colors.primary,
          onPress: () => router.push(`/(app)/more/expenses/${expense.id}` as never),
        },
        {
          key: "delete",
          label: "Delete",
          icon: "trash-outline",
          color: "#fff",
          backgroundColor: colors.destructive,
          onPress: onDelete,
        },
      ]}
    >
      <Pressable
        accessibilityRole="button"
        onPress={() => router.push(`/(app)/more/expenses/${expense.id}` as never)}
        style={({ pressed }) => [
          styles.row,
          { borderColor: colors.border },
          pressed && styles.rowPressed,
        ]}
      >
        <View style={[styles.categoryIcon, { backgroundColor: colors.muted }]}>
          <Ionicons name={expenseIcon(expense.category)} size={18} color={colors.primary} />
        </View>
        <View style={styles.meta}>
          <View style={styles.titleRow}>
            <Text style={[styles.title, { color: colors.foreground }]} numberOfLines={1}>
              {expense.description}
            </Text>
            {expense.receiptCount ? (
              <View
                style={[
                  styles.receiptPill,
                  { borderColor: colors.border, backgroundColor: colors.background },
                ]}
              >
                <Ionicons name="document-attach-outline" size={13} color={colors.primary} />
                <Text style={[styles.receiptPillText, { color: colors.primary }]}>
                  {expense.receiptCount}
                </Text>
              </View>
            ) : null}
          </View>
          <Text style={[styles.sub, { color: colors.mutedForeground }]} numberOfLines={1}>
            {formatDate(expense.date)}
            {expense.category ? ` · ${expense.category}` : ""}
            {expense.client?.name ? ` · ${expense.client.name}` : ""}
          </Text>
          <View style={styles.tagRow}>
            {expense.billable ? (
              <Text style={[styles.tag, { color: colors.primary, borderColor: colors.border }]}>
                Billable
              </Text>
            ) : null}
            {expense.reimbursable ? (
              <Text style={[styles.tag, { color: colors.foreground, borderColor: colors.border }]}>
                Reimbursable
              </Text>
            ) : null}
            {expense.taxDeductible ? (
              <Text style={[styles.tag, { color: colors.success, borderColor: colors.border }]}>
                Tax
              </Text>
            ) : null}
          </View>
        </View>
        <View style={styles.amountStack}>
          <Text style={[styles.amount, { color: colors.foreground }]}>
            {formatCurrency(expense.amount, expense.currency)}
          </Text>
          <Ionicons name="chevron-forward" size={16} color={colors.mutedForeground} />
        </View>
      </Pressable>
    </SwipeableRow>
  );
}

function groupExpensesByMonth(expenses: Expense[]) {
  const groups = new Map<string, Expense[]>();
  for (const expense of expenses) {
    const date = new Date(expense.date);
    const key = date.toLocaleDateString(undefined, {
      month: "long",
      year: "numeric",
    });
    const group = groups.get(key) ?? [];
    group.push(expense);
    groups.set(key, group);
  }
  return Array.from(groups.entries());
}

function expenseIcon(category: string | null): keyof typeof Ionicons.glyphMap {
  const normalized = category?.toLowerCase() ?? "";
  if (normalized.includes("travel") || normalized.includes("mileage")) return "airplane-outline";
  if (normalized.includes("meal") || normalized.includes("food")) return "restaurant-outline";
  if (normalized.includes("software") || normalized.includes("subscription")) return "laptop-outline";
  if (normalized.includes("office") || normalized.includes("supply")) return "briefcase-outline";
  if (normalized.includes("phone") || normalized.includes("internet")) return "wifi-outline";
  return "receipt-outline";
}

const createStyles = (colors: ThemeColors) =>
  StyleSheet.create({
    header: {
      gap: spacing.md,
    },
    row: {
      flexDirection: "row",
      alignItems: "center",
      gap: spacing.md,
      paddingHorizontal: spacing.md,
      paddingVertical: 12,
      borderWidth: 1,
      borderRadius: radii.lg,
    },
    rowPressed: {
      opacity: 0.82,
    },
    categoryIcon: {
      width: 40,
      height: 40,
      borderRadius: radii.md,
      alignItems: "center",
      justifyContent: "center",
    },
    meta: {
      flex: 1,
      minWidth: 0,
      gap: spacing.xs,
    },
    titleRow: {
      flexDirection: "row",
      alignItems: "center",
      gap: spacing.sm,
    },
    title: {
      flex: 1,
      fontFamily: fonts.bodySemiBold,
      fontSize: 15,
    },
    sub: {
      fontFamily: fonts.body,
      fontSize: 13,
    },
    tagRow: {
      flexDirection: "row",
      flexWrap: "wrap",
      gap: spacing.xs,
    },
    tag: {
      borderWidth: 1,
      borderRadius: radii.pill,
      paddingHorizontal: spacing.sm,
      paddingVertical: 2,
      fontFamily: fonts.bodyMedium,
      fontSize: 11,
      overflow: "hidden",
    },
    amountStack: {
      alignItems: "flex-end",
      gap: spacing.xs,
    },
    amount: {
      fontFamily: fonts.bodySemiBold,
      fontSize: 15,
      fontVariant: ["tabular-nums"],
    },
    summaryGrid: {
      flexDirection: "row",
      flexWrap: "wrap",
      gap: spacing.xs,
    },
    summaryTile: {
      flexGrow: 1,
      flexBasis: "30%",
      minWidth: 104,
      paddingHorizontal: spacing.md,
      paddingVertical: 12,
      borderRadius: radii.lg,
      borderWidth: 1,
    },
    summaryLabel: {
      fontFamily: fonts.bodyMedium,
      fontSize: 12,
      textTransform: "uppercase",
    },
    summaryValue: {
      marginTop: 2,
      fontFamily: fonts.bodySemiBold,
      fontSize: 20,
      fontVariant: ["tabular-nums"],
    },
    monthGroup: {
      gap: 2,
    },
    monthLabel: {
      fontFamily: fonts.bodySemiBold,
      fontSize: 12,
      textTransform: "uppercase",
      letterSpacing: 0,
      paddingHorizontal: spacing.xs,
    },
    filters: {
      gap: spacing.sm,
      paddingRight: spacing.lg,
    },
    receiptPill: {
      flexDirection: "row",
      alignItems: "center",
      gap: 2,
      borderWidth: 1,
      borderRadius: radii.pill,
      paddingHorizontal: 7,
      paddingVertical: 2,
    },
    receiptPillText: {
      fontFamily: fonts.bodyMedium,
      fontSize: 12,
    },
    empty: {
      fontFamily: fonts.body,
      fontSize: 14,
      lineHeight: 20,
      textAlign: "center",
    },
    emptyCard: {
      alignItems: "center",
      gap: spacing.sm,
      padding: spacing.lg,
      borderWidth: 1,
      borderRadius: radii.lg,
    },
    emptyIcon: {
      width: 52,
      height: 52,
      borderRadius: radii.lg,
      alignItems: "center",
      justifyContent: "center",
    },
    emptyTitle: {
      fontFamily: fonts.bodySemiBold,
      fontSize: 17,
    },
    errorBox: {
      padding: spacing.lg,
      gap: spacing.sm,
    },
    errorTitle: {
      fontFamily: fonts.bodySemiBold,
      fontSize: 18,
    },
  });
