import { router, Stack } 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 { LineItemEditor, type EditableLineItem } from "@/components/invoices/LineItemEditor";
import { LoadingScreen } from "@/components/LoadingScreen";
import { Button } from "@/components/ui/Button";
import { Card } from "@/components/ui/Card";
import { DateTimeField } from "@/components/ui/DateTimeField";
import { Input } from "@/components/ui/Input";
import { SelectField } from "@/components/ui/SelectField";
import { fonts, spacing } from "@/constants/theme";
import { useAppTheme } from "@/contexts/ThemeContext";
import { formatCurrency } from "@/lib/format";
import { defaultDueDate, generateInvoiceNumber } from "@/lib/invoice-number";
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 NewInvoiceScreen() {
  const { colors } = useAppTheme();
  const styles = useThemedStyles(createNewInvoiceStyles);
  const utils = api.useUtils();
  const scrollPadding = useTabBarScrollPadding();

  const clientsQuery = api.clients.getAll.useQuery();

  const [clientId, setClientId] = useState("");
  const [invoiceNumber, setInvoiceNumber] = useState(generateInvoiceNumber);
  const [issueDate, setIssueDate] = useState(() => new Date());
  const [dueDate, setDueDate] = useState(() => defaultDueDate(new Date()));
  const [notes, setNotes] = useState("");
  const [taxRate, setTaxRate] = useState("0");
  const [items, setItems] = useState<EditableLineItem[]>([
    {
      date: new Date(),
      description: "",
      hours: "1",
      rate: "0",
    },
  ]);
  const [expandedIndex, setExpandedIndex] = useState<number | null>(0);
  const [error, setError] = useState<string | null>(null);

  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 ?? "USD";

  useEffect(() => {
    if (!selectedClient?.defaultHourlyRate) return;
    setItems((prev) =>
      prev.map((item, index) =>
        index === 0 && (item.rate === "0" || item.rate === "")
          ? { ...item, rate: String(selectedClient.defaultHourlyRate) }
          : item,
      ),
    );
  }, [selectedClient?.defaultHourlyRate, selectedClient?.id]);

  const createInvoice = api.invoices.create.useMutation({
    onSuccess: (invoice) => {
      void utils.invoices.getAll.invalidate();
      void utils.dashboard.getStats.invalidate();
      Alert.alert("Invoice created", "Your draft invoice is ready.", [
        {
          text: "View invoice",
          onPress: () => router.replace(`/(app)/invoices/${invoice.id}`),
        },
      ]);
    },
    onError: (err) => setError(err.message),
  });

  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;

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

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

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

  function removeItem(index: number) {
    if (items.length <= 1) {
      Alert.alert("Cannot remove", "An invoice needs at least one line item.");
      return;
    }
    setItems((prev) => prev.filter((_, i) => i !== index));
    setExpandedIndex((current) => {
      if (current === null) return null;
      if (current === index) return null;
      return current > index ? current - 1 : current;
    });
  }

  function handleCreate() {
    setError(null);

    if (!clientId) {
      setError("Select a client");
      return;
    }

    if (!invoiceNumber.trim()) {
      setError("Invoice number is required");
      return;
    }

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

    for (const item of items) {
      const hours = Number(item.hours);
      const rate = Number(item.rate);
      if (!item.description.trim()) {
        setError("Each line needs a description");
        return;
      }
      if (Number.isNaN(hours) || hours < 0) {
        setError("Hours must be a valid number");
        return;
      }
      if (Number.isNaN(rate) || rate < 0) {
        setError("Rate must be a valid number");
        return;
      }
      parsedItems.push({
        date: item.date,
        description: item.description.trim(),
        hours,
        rate,
      });
    }

    const tax = Number(taxRate);
    if (Number.isNaN(tax) || tax < 0 || tax > 100) {
      setError("Tax rate must be between 0 and 100");
      return;
    }

    createInvoice.mutate({
      clientId,
      invoiceNumber: invoiceNumber.trim(),
      issueDate,
      dueDate,
      notes,
      taxRate: tax,
      currency,
      items: parsedItems,
      status: "draft",
    });
  }

  return (
    <AppBackground>
      <Stack.Screen options={{ headerBackTitle: "Invoices" }} />
      <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"
        >
          <Card title="Details">
            {clientOptions.length === 0 ? (
              <View style={styles.noClients}>
                <Text style={styles.noClientsText}>
                  Add a client before creating an invoice.
                </Text>
                <Button
                  title="Add client"
                  variant="secondary"
                  onPress={() => router.push("/(app)/entities/clients/new")}
                />
              </View>
            ) : (
              <SelectField
                label="Client"
                placeholder="Select client…"
                value={clientId}
                options={clientOptions}
                onValueChange={setClientId}
              />
            )}
            <Input
              label="Invoice number"
              value={invoiceNumber}
              onChangeText={setInvoiceNumber}
              autoCapitalize="characters"
            />
            <DateTimeField
              label="Issue date"
              mode="date"
              value={issueDate}
              onChange={(date) => {
                setIssueDate(date);
                setDueDate((current) => (current < date ? defaultDueDate(date) : current));
              }}
            />
            <DateTimeField label="Due date" mode="date" value={dueDate} onChange={setDueDate} />
            <Input
              label="Tax rate (%)"
              value={taxRate}
              onChangeText={setTaxRate}
              keyboardType="decimal-pad"
            />
            <Input
              label="Notes"
              value={notes}
              onChangeText={setNotes}
              placeholder="Optional notes for the client"
              multiline
              style={styles.notesInput}
            />
          </Card>

          <Card title="Line items">
            {items.map((item, index) => (
              <LineItemEditor
                key={`new-${index}`}
                item={item}
                currency={currency}
                expanded={expandedIndex === index}
                onToggle={() =>
                  setExpandedIndex((current) => (current === index ? null : index))
                }
                onChange={(patch) => updateItem(index, patch)}
                onRemove={() => removeItem(index)}
              />
            ))}

            <Pressable accessibilityRole="button" onPress={addItem} style={styles.addLine}>
              <Text style={styles.addLineText}>+ Add line</Text>
            </Pressable>

            <View style={styles.totals}>
              <TotalRow label="Subtotal" value={formatCurrency(subtotal, currency)} />
              {parsedTaxRate > 0 ? (
                <TotalRow
                  label={`Tax (${parsedTaxRate}%)`}
                  value={formatCurrency(taxAmount, currency)}
                />
              ) : null}
              <TotalRow label="Total" value={formatCurrency(total, currency)} bold />
            </View>
          </Card>

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

          <Button
            title="Create invoice"
            loading={createInvoice.isPending}
            disabled={clientOptions.length === 0}
            onPress={handleCreate}
          />
        </ScrollView>
      </KeyboardAvoidingView>
    </AppBackground>
  );
}

function TotalRow({
  label,
  value,
  bold,
}: {
  label: string;
  value: string;
  bold?: boolean;
}) {
  const { colors } = useAppTheme();
  return (
    <View style={totalStyles.row}>
      <Text
        style={[
          totalStyles.label,
          { color: colors.mutedForeground },
          bold && totalStyles.bold,
          bold && { color: colors.foreground },
        ]}
      >
        {label}
      </Text>
      <Text
        style={[
          totalStyles.value,
          { color: colors.foreground },
          bold && totalStyles.bold,
        ]}
      >
        {value}
      </Text>
    </View>
  );
}

const totalStyles = StyleSheet.create({
  row: {
    flexDirection: "row",
    justifyContent: "space-between",
    alignItems: "center",
  },
  label: {
    fontFamily: fonts.body,
    fontSize: 14,
  },
  value: {
    fontFamily: fonts.bodyMedium,
    fontSize: 14,
  },
  bold: {
    fontFamily: fonts.bodySemiBold,
    fontSize: 15,
  },
});

const createNewInvoiceStyles = (colors: ThemeColors, _isDark: boolean) =>
  StyleSheet.create({
    flex: { flex: 1 },
    container: {
      padding: spacing.md,
      gap: spacing.md,
    },
    notesInput: {
      minHeight: 72,
      textAlignVertical: "top",
    },
    noClients: {
      gap: spacing.sm,
    },
    noClientsText: {
      fontFamily: fonts.body,
      fontSize: 14,
      color: colors.mutedForeground,
      lineHeight: 20,
    },
    addLine: {
      paddingTop: spacing.sm,
      paddingBottom: spacing.xs,
    },
    addLineText: {
      fontFamily: fonts.bodySemiBold,
      fontSize: 14,
      color: colors.primary,
    },
    totals: {
      marginTop: spacing.sm,
      paddingTop: spacing.sm,
      borderTopWidth: 1,
      borderTopColor: colors.border,
      gap: 6,
    },
    error: {
      color: colors.destructive,
      fontFamily: fonts.body,
      fontSize: 14,
    },
  });
