import { router, Stack, useLocalSearchParams } from "expo-router";
import { useEffect, useMemo, useState } from "react";
import {
  Alert,
  KeyboardAvoidingView,
  Platform,
  Pressable,
  ScrollView,
  StyleSheet,
  Text,
  View,
} from "react-native";

import { AppBackground } from "@/components/AppBackground";
import {
  InvoiceEditorSectionTabs,
  type InvoiceEditorSection,
} from "@/components/invoices/InvoiceEditorSectionTabs";
import { InvoiceEditorFooter } from "@/components/invoices/InvoiceEditorFooter";
import { InvoicePdfPreview } from "@/components/invoices/InvoicePdfPreview";
import { InvoiceSetupForm } from "@/components/invoices/InvoiceSetupForm";
import { InvoiceTotals } from "@/components/invoices/InvoiceTotals";
import { LineItemEditor, type EditableLineItem } from "@/components/invoices/LineItemEditor";
import { LoadingScreen } from "@/components/LoadingScreen";
import { Card } from "@/components/ui/Card";
import { fonts, spacing } from "@/constants/theme";
import { useAppTheme } from "@/contexts/ThemeContext";
import { formatCurrency } from "@/lib/format";
import { isValidTaxRate, validateLineItems } from "@/lib/form-validation";
import { resolveInvoiceBusinessId } from "@/lib/invoice-business";
import { getInvoiceStatus } from "@/lib/invoice-status";
import { buildPreviewPdfInput } from "@/lib/invoice-pdf-input";
import { ensureNotificationPermissions } from "@/lib/invoice-send-reminders";
import { useTabBarScrollPadding } from "@/lib/tab-bar-insets";
import type { ThemeColors } from "@/lib/theme-palette";
import { useThemedStyles } from "@/lib/use-themed-styles";
import { api } from "@/lib/trpc";

export default function InvoiceEditScreen() {
  const { colors } = useAppTheme();
  const styles = useThemedStyles(createInvoiceEditStyles);
  const { id } = useLocalSearchParams<{ id: string }>();
  const utils = api.useUtils();
  const scrollPadding = useTabBarScrollPadding();

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

  const [businessId, setBusinessId] = useState("");
  const [clientId, setClientId] = useState("");
  const [notes, setNotes] = useState("");
  const [dueDate, setDueDate] = useState(() => new Date());
  const [taxRate, setTaxRate] = useState("0");
  const [sendReminderAt, setSendReminderAt] = useState<Date | null>(null);
  const [items, setItems] = useState<EditableLineItem[]>([]);
  const [section, setSection] = useState<InvoiceEditorSection>("setup");
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    const invoice = invoiceQuery.data;
    if (!invoice) return;
    setBusinessId(invoice.businessId ?? invoice.business?.id ?? "");
    setClientId(invoice.clientId);
    setNotes(invoice.notes ?? "");
    setDueDate(new Date(invoice.dueDate));
    setTaxRate(String(invoice.taxRate));
    setSendReminderAt(invoice.sendReminderAt ? new Date(invoice.sendReminderAt) : null);
    setItems(
      invoice.items.map((item) => ({
        id: item.id,
        date: new Date(item.date),
        description: item.description,
        hours: String(item.hours),
        rate: String(item.rate),
      })),
    );
  }, [invoiceQuery.data]);

  useEffect(() => {
    if (businessId || !businessesQuery.data?.length) return;
    setBusinessId(resolveInvoiceBusinessId(null, businessesQuery.data));
  }, [businessId, businessesQuery.data]);

  const updateInvoice = api.invoices.update.useMutation({
    onSuccess: () => {
      void utils.invoices.getById.invalidate({ id: id ?? "" });
      void utils.invoices.getAll.invalidate();
      void utils.invoices.getAll.invalidate({ status: "draft" });
      void utils.dashboard.getStats.invalidate();
      Alert.alert("Saved", "Invoice updated", [
        { text: "OK", onPress: () => router.back() },
      ]);
    },
    onError: (err) => setError(err.message),
  });

  const invoice = invoiceQuery.data;
  const isDraft = invoice?.status === "draft";

  const businessOptions = useMemo(
    () =>
      (businessesQuery.data ?? []).map((business) => ({
        label: business.name,
        value: business.id,
      })),
    [businessesQuery.data],
  );

  const clientOptions = useMemo(
    () =>
      (clientsQuery.data ?? []).map((client) => ({
        label: client.name,
        value: client.id,
      })),
    [clientsQuery.data],
  );

  const selectedClient = clientsQuery.data?.find((client) => client.id === clientId);
  const currency = selectedClient?.currency ?? invoice?.currency ?? "USD";
  const resolvedBusinessId = resolveInvoiceBusinessId(businessId, businessesQuery.data);

  const subtotal = useMemo(
    () =>
      items.reduce((sum, item) => {
        const hours = Number(item.hours) || 0;
        const rate = Number(item.rate) || 0;
        return sum + hours * rate;
      }, 0),
    [items],
  );

  const parsedTaxRate = Number(taxRate) || 0;
  const taxAmount = subtotal * (parsedTaxRate / 100);
  const total = subtotal + taxAmount;
  const lineItemsError = isDraft ? validateLineItems(items) : null;
  const taxError = isDraft && !isValidTaxRate(taxRate) ? "Tax rate must be between 0 and 100" : null;
  const businessError = isDraft && !resolvedBusinessId ? "Select a business" : undefined;
  const clientError = isDraft && !clientId ? "Select a client" : undefined;
  const canSave = isDraft
    ? !lineItemsError && !taxError && !businessError && !clientError
    : true;

  const previewInput = useMemo(() => {
    if (!invoice) return null;
    return buildPreviewPdfInput({
      invoiceNumber: invoice.invoiceNumber,
      invoicePrefix: invoice.invoicePrefix,
      businessId: resolvedBusinessId,
      clientId,
      issueDate: new Date(invoice.issueDate),
      dueDate,
      status: invoice.status as "draft" | "sent" | "paid",
      notes,
      taxRate: parsedTaxRate,
      currency,
      items,
    });
  }, [invoice, resolvedBusinessId, clientId, dueDate, notes, parsedTaxRate, currency, items]);

  if (!id) {
    return <LoadingScreen message="Invalid invoice" />;
  }

  if (invoiceQuery.isLoading || businessesQuery.isLoading || clientsQuery.isLoading) {
    return <LoadingScreen message="Loading invoice…" />;
  }

  if (!invoice) {
    return <LoadingScreen message="Invoice not found" />;
  }

  const status = getInvoiceStatus(invoice);
  const clientEmail = invoice.client?.email?.trim() ?? "";

  function updateItem(index: number, patch: Partial<EditableLineItem>) {
    setItems((prev) => prev.map((item, i) => (i === index ? { ...item, ...patch } : item)));
  }

  function addItem() {
    setItems((prev) => [
      ...prev,
      {
        date: new Date(),
        description: "",
        hours: "1",
        rate: prev[prev.length - 1]?.rate ?? "0",
      },
    ]);
  }

  function removeItem(index: number) {
    setItems((prev) => prev.filter((_, i) => i !== index));
  }

  function duplicateItem(index: number) {
    setItems((prev) => {
      const source = prev[index];
      if (!source) return prev;
      const copy = { ...source, id: undefined };
      return [...prev.slice(0, index + 1), copy, ...prev.slice(index + 1)];
    });
  }

  async function handleSave() {
    if (!canSave) return;
    setError(null);

    if (isDraft && sendReminderAt) {
      const granted = await ensureNotificationPermissions();
      if (!granted) {
        Alert.alert(
          "Notifications disabled",
          "Turn on notifications in Settings to get reminded when it's time to send this invoice.",
        );
      }
    }

    const parsedItems: Array<{
      date: Date;
      description: string;
      hours: number;
      rate: number;
    }> = [];

    for (const item of items) {
      parsedItems.push({
        date: item.date,
        description: item.description.trim(),
        hours: Number(item.hours),
        rate: Number(item.rate),
      });
    }

    updateInvoice.mutate({
      id,
      notes,
      dueDate,
      sendReminderAt,
      ...(isDraft
        ? {
            businessId: resolvedBusinessId,
            clientId,
            taxRate: parsedTaxRate,
            currency,
            items: parsedItems,
          }
        : {}),
    });
  }

  return (
    <AppBackground>
      <Stack.Screen options={{ headerBackTitle: "Invoice" }} />
      <KeyboardAvoidingView
        behavior={Platform.OS === "ios" ? "padding" : undefined}
        style={styles.flex}
      >
        <ScrollView
          contentContainerStyle={[styles.container, { paddingBottom: scrollPadding }]}
          contentInsetAdjustmentBehavior={Platform.OS === "ios" ? "automatic" : undefined}
          scrollIndicatorInsets={{ bottom: scrollPadding }}
          keyboardShouldPersistTaps="handled"
        >
          <View style={styles.hero}>
            <Text style={styles.invoiceNumber}>
              {invoice.invoicePrefix}
              {invoice.invoiceNumber}
            </Text>
            <Text style={styles.clientName}>
              {selectedClient?.name ?? invoice.client?.name ?? "Client"}
            </Text>
          </View>

          <InvoiceEditorSectionTabs value={section} onChange={setSection} />

          {section === "preview" ? (
            <Card title="PDF preview">
              <InvoicePdfPreview input={previewInput} />
            </Card>
          ) : section === "setup" ? (
            <Card title="Invoice setup">
              <InvoiceSetupForm
                businessId={businessId}
                onBusinessIdChange={setBusinessId}
                businessOptions={businessOptions}
                businessError={businessError}
                businessReadOnly={!isDraft}
                clientId={clientId}
                onClientIdChange={setClientId}
                clientOptions={clientOptions}
                clientError={clientError}
                clientReadOnly={!isDraft}
                invoiceNumber={`${invoice.invoicePrefix}${invoice.invoiceNumber}`}
                invoiceNumberReadOnly
                issueDate={new Date(invoice.issueDate)}
                issueDateReadOnly
                dueDate={dueDate}
                onDueDateChange={setDueDate}
                taxRate={taxRate}
                onTaxRateChange={isDraft ? setTaxRate : undefined}
                taxRateReadOnly={!isDraft}
                notes={notes}
                onNotesChange={setNotes}
                sendReminderAt={sendReminderAt}
                onSendReminderAtChange={isDraft ? setSendReminderAt : undefined}
                showSendReminder={isDraft}
              />
              {taxError ? <Text style={styles.error}>{taxError}</Text> : null}
            </Card>
          ) : (
            <>
              <Card title="Line items">
                {!isDraft ? (
                  <Text style={styles.lockedHint}>
                    Line items are locked after an invoice is sent. Mark as draft on the invoice
                    screen to edit entries.
                  </Text>
                ) : items.length === 0 ? (
                  <Text style={styles.emptyLines}>
                    No line items yet. Add lines here or clock time to this invoice from the
                    Timer tab.
                  </Text>
                ) : null}
                {items.map((item, index) => (
                  <LineItemEditor
                    key={item.id ?? `new-${index}`}
                    index={index}
                    item={item}
                    currency={currency}
                    isLast={index === items.length - 1}
                    onChange={(patch) => updateItem(index, patch)}
                    onRemove={() => removeItem(index)}
                    onDuplicate={isDraft ? () => duplicateItem(index) : undefined}
                    readOnly={!isDraft}
                  />
                ))}

                {isDraft ? (
                  <Pressable accessibilityRole="button" onPress={addItem} style={styles.addLine}>
                    <Text style={styles.addLineText}>+ Add another line</Text>
                  </Pressable>
                ) : null}

                <InvoiceTotals
                  subtotal={formatCurrency(subtotal, currency)}
                  taxLabel={parsedTaxRate > 0 ? `Tax (${parsedTaxRate}%)` : undefined}
                  taxAmount={parsedTaxRate > 0 ? formatCurrency(taxAmount, currency) : undefined}
                  total={formatCurrency(total, currency)}
                />
              </Card>

              {lineItemsError ? <Text style={styles.error}>{lineItemsError}</Text> : null}
            </>
          )}

          {error ? <Text style={styles.error}>{error}</Text> : null}

          <InvoiceEditorFooter
            primaryTitle="Save changes"
            onPrimary={handleSave}
            primaryLoading={updateInvoice.isPending}
            primaryDisabled={!canSave}
            secondary={
              status !== "paid"
                ? {
                    title: status === "draft" ? "Send invoice" : "Resend invoice",
                    subtitle: clientEmail
                      ? items.length === 0
                        ? "Add line items before sending"
                        : `Review PDF and email to ${clientEmail}`
                      : "Add a client email on the web app first",
                    icon: "mail-outline",
                    onPress: () => {
                      if (!clientEmail) {
                        Alert.alert(
                          "No client email",
                          "Add an email address to this client on the web app before sending invoices.",
                        );
                        return;
                      }
                      if (items.length === 0) {
                        Alert.alert(
                          "No line items",
                          "Add line items or clock time to this invoice before sending.",
                        );
                        return;
                      }
                      router.push(`/(app)/invoices/send/${invoice.id}`);
                    },
                    disabled: !clientEmail || items.length === 0,
                  }
                : undefined
            }
          />
        </ScrollView>
      </KeyboardAvoidingView>
    </AppBackground>
  );
}

const createInvoiceEditStyles = (colors: ThemeColors, _isDark: boolean) =>
  StyleSheet.create({
    flex: { flex: 1 },
    container: {
      padding: spacing.md,
      gap: spacing.md,
    },
    hero: {
      gap: 4,
    },
    invoiceNumber: {
      fontSize: 24,
      lineHeight: 28,
      fontFamily: fonts.heading,
      color: colors.foreground,
    },
    clientName: {
      fontSize: 14,
      fontFamily: fonts.body,
      color: colors.mutedForeground,
    },
    lockedHint: {
      fontFamily: fonts.body,
      fontSize: 13,
      color: colors.mutedForeground,
      marginBottom: spacing.sm,
    },
    emptyLines: {
      fontFamily: fonts.body,
      fontSize: 14,
      lineHeight: 20,
      color: colors.mutedForeground,
      marginBottom: spacing.sm,
    },
    addLine: {
      paddingTop: spacing.md,
      paddingBottom: spacing.xs,
    },
    addLineText: {
      fontFamily: fonts.bodySemiBold,
      fontSize: 14,
      color: colors.primary,
    },
    error: {
      color: colors.destructive,
      fontFamily: fonts.body,
      fontSize: 14,
    },
  });
