import { useLocalSearchParams, router } from "expo-router";
import { useState } from "react";
import { Alert, ScrollView, StyleSheet, Text, View } from "react-native";

import { AppBackground } from "@/components/AppBackground";
import {
  ExpenseFormFields,
  type ExpenseFormState,
} from "@/components/expenses/ExpenseFormFields";
import { ReceiptItemSelector } from "@/components/expenses/ReceiptItemSelector";
import { LoadingScreen } from "@/components/LoadingScreen";
import { PageHeader } from "@/components/PageHeader";
import { SwipeableRow } from "@/components/SwipeableRow";
import { TabPage } from "@/components/TabPage";
import { Button } from "@/components/ui/Button";
import { fonts, spacing } from "@/constants/theme";
import { useAppTheme } from "@/contexts/ThemeContext";
import { formatCurrency, formatDate } from "@/lib/format";
import { scanReceiptImage, type ReceiptScanResult } from "@/lib/receipt-scan";
import { api } from "@/lib/trpc";

type ReceiptSplitDraft = Pick<
  ReceiptScanResult,
  "items" | "subtotal" | "tax" | "total"
>;

export default function ExpenseDetailScreen() {
  const { id } = useLocalSearchParams<{ id: string }>();
  const { colors } = useAppTheme();
  const utils = api.useUtils();
  const [scanning, setScanning] = useState(false);
  const [editing, setEditing] = useState(false);
  const [receiptSplit, setReceiptSplit] = useState<ReceiptSplitDraft | null>(
    null,
  );
  const [form, setForm] = useState<ExpenseFormState>({
    description: "",
    amountText: "",
    date: new Date(),
    category: "",
    businessId: "",
    clientId: "",
    billable: false,
    reimbursable: false,
    taxDeductible: false,
    notes: "",
  });

  const expenseQuery = api.expenses.getById.useQuery(
    { id: id ?? "" },
    { enabled: Boolean(id) },
  );
  const businessesQuery = api.businesses.getAll.useQuery();
  const clientsQuery = api.clients.getAll.useQuery();

  const uploadReceipt = api.expenses.uploadReceipt.useMutation({
    onSuccess: () => void expenseQuery.refetch(),
  });
  const deleteReceipt = api.expenses.deleteReceipt.useMutation({
    onSuccess: () => void expenseQuery.refetch(),
  });
  const updateExpense = api.expenses.update.useMutation({
    onSuccess: async () => {
      await utils.expenses.getAll.invalidate();
      await expenseQuery.refetch();
      setEditing(false);
    },
  });
  const suggest = api.expenses.suggestFromReceiptText.useMutation();

  const expense = expenseQuery.data;
  const businesses = businessesQuery.data ?? [];
  const clients = clientsQuery.data ?? [];

  async function attachAndScan(fromCamera: boolean) {
    if (!id || !expense) return;

    setScanning(true);
    try {
      const result = await scanReceiptImage(
        fromCamera,
        {
          description: expense.description,
          amountText: String(expense.amount),
          date: new Date(expense.date),
        },
        (input) => suggest.mutateAsync(input),
      );
      if (!result) return;

      await uploadReceipt.mutateAsync({
        expenseId: id,
        filename: result.image.filename,
        mimeType: result.image.mimeType,
        data: result.image.base64,
      });

      setForm(
        expenseToForm(expense, {
          description: result.description,
          amountText: result.amountText,
          date: result.date,
          notes: result.ocrText,
        }),
      );
      setReceiptSplit(
        result.items.length > 0
          ? {
              items: result.items,
              subtotal: result.subtotal,
              tax: result.tax,
              total: result.total,
            }
          : null,
      );
      setEditing(true);

      Alert.alert(
        "Receipt attached",
        result.items.length > 0
          ? "Select the owed items, apply the split amount, then save the expense."
          : "OCR filled the fields below. Save to update this expense.",
      );
    } finally {
      setScanning(false);
    }
  }

  function handleSaveEdits() {
    if (!id) return;
    const amount = Number(form.amountText);
    if (!form.description.trim() || !Number.isFinite(amount) || amount <= 0) {
      Alert.alert("Invalid fields", "Description and amount are required.");
      return;
    }

    updateExpense.mutate({
      id,
      description: form.description.trim(),
      amount,
      date: form.date,
      category: form.category || undefined,
      businessId: form.businessId || undefined,
      clientId: form.clientId || undefined,
      billable: form.billable,
      reimbursable: form.reimbursable,
      taxDeductible: form.taxDeductible,
      notes: form.notes.trim() || undefined,
    });
  }

  function startEditing() {
    if (!expense) return;
    setForm(expenseToForm(expense));
    setReceiptSplit(null);
    setEditing(true);
  }

  if (expenseQuery.isLoading) {
    return <LoadingScreen message="Loading expense…" />;
  }

  if (!expense) {
    return (
      <AppBackground>
        <TabPage>
          <Text style={{ color: colors.mutedForeground, padding: spacing.lg }}>
            Expense not found
          </Text>
        </TabPage>
      </AppBackground>
    );
  }

  return (
    <AppBackground>
      <TabPage>
        <ScrollView contentContainerStyle={styles.body}>
          <PageHeader
            title={expense.description}
            subtitle={formatDate(expense.date)}
          />

          {editing ? (
            <>
              {receiptSplit ? (
                <ReceiptItemSelector
                  items={receiptSplit.items}
                  subtotal={receiptSplit.subtotal}
                  tax={receiptSplit.tax}
                  total={receiptSplit.total}
                  onApply={(selection) => {
                    setForm((current) => ({
                      ...current,
                      amountText: selection.owedTotal.toFixed(2),
                      notes: mergeNotes(selection.notes, current.notes),
                    }));
                  }}
                />
              ) : null}
              <ExpenseFormFields
                value={form}
                businesses={businesses}
                clients={clients}
                onChange={setForm}
              />
              <Button
                title="Save changes"
                loading={updateExpense.isPending}
                onPress={handleSaveEdits}
              />
              <Button
                title="Cancel edit"
                variant="secondary"
                onPress={() => setEditing(false)}
              />
            </>
          ) : (
            <>
              <Text style={[styles.amount, { color: colors.foreground }]}>
                {formatCurrency(expense.amount, expense.currency)}
              </Text>
              <View style={styles.metaStack}>
                <Text style={[styles.meta, { color: colors.mutedForeground }]}>
                  {expense.category || "No category"}
                  {expense.business?.name ? ` · ${expense.business.name}` : ""}
                  {expense.client?.name ? ` · ${expense.client.name}` : ""}
                </Text>
                <View style={styles.badges}>
                  {expense.billable ? (
                    <Text
                      style={[
                        styles.badge,
                        { color: colors.primary, borderColor: colors.border },
                      ]}
                    >
                      Billable
                    </Text>
                  ) : null}
                  {expense.reimbursable ? (
                    <Text
                      style={[
                        styles.badge,
                        {
                          color: colors.foreground,
                          borderColor: colors.border,
                        },
                      ]}
                    >
                      Reimbursable
                    </Text>
                  ) : null}
                  {expense.taxDeductible ? (
                    <Text
                      style={[
                        styles.badge,
                        { color: colors.success, borderColor: colors.border },
                      ]}
                    >
                      Tax deductible
                    </Text>
                  ) : null}
                </View>
              </View>
              {expense.notes ? (
                <Text style={{ color: colors.mutedForeground }}>
                  {expense.notes}
                </Text>
              ) : null}
              <Button
                title="Edit expense"
                variant="secondary"
                onPress={startEditing}
              />
            </>
          )}

          <Text style={[styles.section, { color: colors.foreground }]}>
            Receipts ({expense.receipts.length})
          </Text>

          {expense.receipts.map((receipt) => (
            <SwipeableRow
              key={receipt.id}
              actions={[
                {
                  key: "delete",
                  label: "Delete",
                  icon: "trash-outline",
                  color: "#fff",
                  backgroundColor: colors.destructive,
                  onPress: () => deleteReceipt.mutate({ id: receipt.id }),
                },
              ]}
            >
              <Text
                style={[styles.receiptRow, { color: colors.mutedForeground }]}
              >
                {receipt.originalFilename}
              </Text>
            </SwipeableRow>
          ))}

          <View style={styles.actions}>
            <Button
              title={scanning ? "Scanning…" : "Scan receipt"}
              loading={scanning || uploadReceipt.isPending}
              style={styles.actionButton}
              onPress={() => void attachAndScan(true)}
            />
            <Button
              title="Import photo"
              variant="secondary"
              loading={scanning || uploadReceipt.isPending}
              style={styles.actionButton}
              onPress={() => void attachAndScan(false)}
            />
          </View>
          <Button
            title="Back"
            variant="secondary"
            onPress={() => router.back()}
          />
        </ScrollView>
      </TabPage>
    </AppBackground>
  );
}

const styles = StyleSheet.create({
  body: {
    padding: spacing.lg,
    gap: spacing.md,
  },
  amount: {
    fontSize: 28,
    fontWeight: "600",
  },
  metaStack: {
    gap: spacing.sm,
  },
  meta: {
    fontFamily: fonts.body,
    fontSize: 14,
  },
  badges: {
    flexDirection: "row",
    flexWrap: "wrap",
    gap: spacing.sm,
  },
  badge: {
    borderWidth: 1,
    borderRadius: 999,
    paddingHorizontal: spacing.sm,
    paddingVertical: 4,
    fontFamily: fonts.bodyMedium,
    fontSize: 12,
  },
  section: {
    fontSize: 16,
    fontWeight: "600",
    marginTop: spacing.md,
  },
  receiptRow: {
    paddingVertical: spacing.sm,
    fontSize: 14,
  },
  actions: {
    flexDirection: "row",
    gap: spacing.sm,
  },
  actionButton: {
    flex: 1,
  },
});

function expenseToForm(
  expense: {
    description: string;
    amount: number;
    date: Date | string;
    category: string | null;
    businessId: string | null;
    clientId: string | null;
    billable: boolean;
    reimbursable: boolean;
    taxDeductible: boolean | null;
    notes: string | null;
  },
  overrides: Partial<ExpenseFormState> = {},
): ExpenseFormState {
  return {
    description: expense.description,
    amountText: String(expense.amount),
    date: new Date(expense.date),
    category: expense.category ?? "",
    businessId: expense.businessId ?? "",
    clientId: expense.clientId ?? "",
    billable: expense.billable,
    reimbursable: expense.reimbursable,
    taxDeductible: expense.taxDeductible ?? false,
    notes: expense.notes ?? "",
    ...overrides,
  };
}

function mergeNotes(prefix: string, existing: string) {
  const trimmed = existing.trim();
  if (!trimmed) return prefix;
  if (trimmed.startsWith("Receipt split")) {
    const ocrStart = trimmed.indexOf("\n\nOCR text:");
    return ocrStart >= 0 ? `${prefix}${trimmed.slice(ocrStart)}` : prefix;
  }
  return `${prefix}\n\nOCR text:\n${trimmed}`;
}
