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

import { AppBackground } from "@/components/AppBackground";
import {
  defaultExpenseFormState,
  ExpenseFormFields,
  type ExpenseFormState,
} from "@/components/expenses/ExpenseFormFields";
import { ReceiptItemSelector } from "@/components/expenses/ReceiptItemSelector";
import { PageHeader } from "@/components/PageHeader";
import { TabPage } from "@/components/TabPage";
import { Button } from "@/components/ui/Button";
import { spacing } from "@/constants/theme";
import { useAppTheme } from "@/contexts/ThemeContext";
import { mlKitOcrAvailable } from "@/lib/receipt-ocr";
import {
  scanReceiptImage,
  type PickedReceiptImage,
  type ReceiptScanResult,
} from "@/lib/receipt-scan";
import { api } from "@/lib/trpc";

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

export default function NewExpenseScreen() {
  const { colors } = useAppTheme();
  const utils = api.useUtils();
  const businessesQuery = api.businesses.getAll.useQuery();
  const clientsQuery = api.clients.getAll.useQuery();

  const businesses = businessesQuery.data ?? [];
  const clients = clientsQuery.data ?? [];
  const defaultBusinessId = useMemo(
    () =>
      businesses.find((business) => business.isDefault)?.id ??
      businesses[0]?.id ??
      "",
    [businesses],
  );
  const [form, setForm] = useState<ExpenseFormState>(() =>
    defaultExpenseFormState(),
  );
  const [scanning, setScanning] = useState(false);
  const [pendingReceipt, setPendingReceipt] =
    useState<PickedReceiptImage | null>(null);
  const [receiptSplit, setReceiptSplit] = useState<ReceiptSplitDraft | null>(
    null,
  );

  const createExpense = api.expenses.create.useMutation();
  const uploadReceipt = api.expenses.uploadReceipt.useMutation();
  const suggest = api.expenses.suggestFromReceiptText.useMutation();

  async function runScan(fromCamera: boolean) {
    setScanning(true);
    try {
      const result = await scanReceiptImage(
        fromCamera,
        {
          description: form.description,
          amountText: form.amountText,
          date: form.date,
        },
        (input) => suggest.mutateAsync(input),
      );
      if (!result) return;

      setForm((current) => ({
        ...current,
        description: result.description,
        amountText: result.amountText,
        date: result.date,
        notes: result.ocrText,
        businessId: current.businessId || defaultBusinessId,
      }));
      setPendingReceipt(result.image);
      setReceiptSplit(
        result.items.length > 0
          ? {
              items: result.items,
              subtotal: result.subtotal,
              tax: result.tax,
              total: result.total,
            }
          : null,
      );

      Alert.alert(
        "Receipt scanned",
        result.items.length > 0
          ? "Select the items this person owes, then apply the split amount."
          : result.amountText
            ? `Filled amount $${result.amountText}${result.description ? ` from ${result.description}` : ""}. Review and save.`
            : "Review the fields — OCR could not find a total automatically.",
      );
    } finally {
      setScanning(false);
    }
  }

  async function handleSave() {
    const amount = Number(form.amountText);
    if (!form.description.trim()) {
      Alert.alert("Description required", "Enter what this expense was for.");
      return;
    }
    if (!Number.isFinite(amount) || amount <= 0) {
      Alert.alert("Amount required", "Enter a valid amount.");
      return;
    }

    try {
      const expense = await createExpense.mutateAsync({
        description: form.description.trim(),
        amount,
        date: form.date,
        currency: "USD",
        category: form.category || undefined,
        clientId: form.clientId || undefined,
        businessId: form.businessId || defaultBusinessId || undefined,
        billable: form.billable,
        reimbursable: form.reimbursable,
        taxDeductible: form.taxDeductible,
        notes: form.notes.trim() || undefined,
      });

      if (pendingReceipt) {
        await uploadReceipt.mutateAsync({
          expenseId: expense.id,
          filename: pendingReceipt.filename,
          mimeType: pendingReceipt.mimeType,
          data: pendingReceipt.base64,
        });
      }

      await utils.expenses.getAll.invalidate();
      router.replace(`/(app)/more/expenses/${expense.id}` as never);
    } catch (err) {
      Alert.alert(
        "Could not save expense",
        err instanceof Error ? err.message : "Try again.",
      );
    }
  }

  return (
    <AppBackground>
      <TabPage>
        <ScrollView
          contentContainerStyle={styles.body}
          keyboardShouldPersistTaps="handled"
        >
          <PageHeader
            title="New expense"
            subtitle={
              mlKitOcrAvailable()
                ? "Scan a receipt with on-device ML Kit OCR"
                : "Manual entry (OCR unavailable on this device)"
            }
          />

          <View style={styles.actions}>
            <Button
              title={scanning ? "Scanning…" : "Scan receipt"}
              variant="secondary"
              loading={scanning}
              style={styles.actionButton}
              onPress={() => void runScan(true)}
            />
            <Button
              title="Import photo"
              variant="secondary"
              loading={scanning}
              style={styles.actionButton}
              onPress={() => void runScan(false)}
            />
          </View>

          {pendingReceipt ? (
            <Text style={{ color: colors.success, fontSize: 13 }}>
              Receipt image ready — it will attach when you save.
            </Text>
          ) : null}

          {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,
              businessId: form.businessId || defaultBusinessId,
            }}
            businesses={businesses}
            clients={clients}
            onChange={setForm}
            notesLabel="Notes"
            notesPlaceholder="Receipt OCR text or internal notes"
          />

          <Button
            title="Save expense"
            loading={createExpense.isPending}
            onPress={() => void handleSave()}
          />
          <Button
            title="Cancel"
            variant="secondary"
            onPress={() => router.back()}
          />
        </ScrollView>
      </TabPage>
    </AppBackground>
  );
}

const styles = StyleSheet.create({
  body: {
    padding: spacing.lg,
    gap: spacing.md,
  },
  actions: {
    flexDirection: "row",
    gap: spacing.sm,
  },
  actionButton: {
    flex: 1,
  },
});

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}`;
}
