import { router } from "expo-router";
import { useMemo, useState } from "react";
import { Alert, 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 { TabScrollView } from "@/components/TabScrollView";
import { Button } from "@/components/ui/Button";
import { Card } from "@/components/ui/Card";
import { fonts, spacing } from "@/constants/theme";
import { useAppTheme } from "@/contexts/ThemeContext";
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 and enter the total before saving.",
      );
    } 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 showMoreBack>
        <TabScrollView
          header={
            <PageHeader
              title="New expense"
              subtitle="Add a receipt, fill the details, and save it"
            />
          }
          keyboardShouldPersistTaps="handled"
        >
          <Card title="Receipt">
            <View style={styles.actions}>
              <Button
                title={scanning ? "Scanning..." : "Take photo"}
                variant="secondary"
                leftIcon="camera-outline"
                loading={scanning}
                style={styles.actionButton}
                onPress={() => void runScan(true)}
              />
              <Button
                title="Choose photo"
                variant="secondary"
                leftIcon="image-outline"
                loading={scanning}
                style={styles.actionButton}
                onPress={() => void runScan(false)}
              />
            </View>

            {pendingReceipt ? (
              <View style={[styles.notice, { backgroundColor: colors.successBg }]}>
                <Text style={[styles.noticeText, { color: colors.success }]}>
                  Receipt attached. Review the details below before saving.
                </Text>
              </View>
            ) : null}
          </Card>

          {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}

          <Card title="Details">
            <ExpenseFormFields
              value={{
                ...form,
                businessId: form.businessId || defaultBusinessId,
              }}
              businesses={businesses}
              clients={clients}
              onChange={setForm}
              notesLabel="Notes"
              notesPlaceholder="Internal details"
            />
          </Card>

          <View style={styles.saveActions}>
            <Button
              title="Save expense"
              leftIcon="checkmark-circle-outline"
              loading={createExpense.isPending}
              onPress={() => void handleSave()}
            />
            <Button
              title="Cancel"
              leftIcon="close-circle-outline"
              variant="secondary"
              onPress={() => router.back()}
            />
          </View>
        </TabScrollView>
      </TabPage>
    </AppBackground>
  );
}

const styles = StyleSheet.create({
  actions: {
    flexDirection: "row",
    gap: spacing.sm,
  },
  actionButton: {
    flex: 1,
  },
  saveActions: {
    gap: spacing.sm,
  },
  notice: {
    borderRadius: 12,
    paddingHorizontal: spacing.md,
    paddingVertical: spacing.sm,
  },
  noticeText: {
    fontFamily: fonts.bodyMedium,
    fontSize: 13,
    lineHeight: 18,
  },
});

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