import { zodResolver } from "@hookform/resolvers/zod";
import { useEffect, useRef } from "react";
import { Controller, useForm, useWatch } from "react-hook-form";
import { z } from "zod";
import { Button } from "@/components/ui/button";
import { DatePicker } from "@/components/ui/date-picker";
import {
  ResponsiveDialog,
  ResponsiveDialogContent,
  ResponsiveDialogFooter,
  ResponsiveDialogHeader,
  ResponsiveDialogTitle,
} from "@/components/ui/responsive-dialog";
import type { Expense } from "@/lib/api";
import { useExpensesContext } from "../ExpensesProvider";

const editSchema = z.object({
  amount: z.number().positive("El monto debe ser mayor a 0"),
  dueDate: z.date({ message: "La fecha es obligatoria" }),
  amountPayed: z.number().positive("El monto pagado debe ser mayor a 0").optional(),
  paymentDate: z.date().optional(),
  markAsPending: z.boolean(),
});

type EditFormValues = z.infer<typeof editSchema>;

interface EditExpenseDialogProps {
  expense: Expense | null;
  open: boolean;
  onOpenChange: (open: boolean) => void;
}

export function EditExpenseDialog({
  expense,
  open,
  onOpenChange,
}: EditExpenseDialogProps) {
  const { updateExpense } = useExpensesContext();
  const amountInputRef = useRef<HTMLInputElement | null>(null);

  const isPayed = expense?.status === "PAYED";

  const {
    register,
    handleSubmit,
    control,
    formState: { errors, isSubmitting },
    reset,
  } = useForm<EditFormValues>({
    resolver: zodResolver(editSchema),
    defaultValues: {
      amount: 0,
      dueDate: undefined,
      amountPayed: undefined,
      paymentDate: undefined,
      markAsPending: false,
    },
  });
  const { ref: amountRef, ...amountField } = register("amount", {
    setValueAs: (value) => Number(value),
  });

  const markAsPending = useWatch({ control, name: "markAsPending" });

  useEffect(() => {
    if (expense) {
      reset({
        amount: Number(expense.amount),
        dueDate: new Date(expense.dueDate),
        amountPayed: expense.amountPayed
          ? Number(expense.amountPayed)
          : undefined,
        paymentDate: expense.paymentDate
          ? new Date(expense.paymentDate)
          : undefined,
        markAsPending: false,
      });
    }
  }, [expense, reset]);

  useEffect(() => {
    if (!open || !expense) return;

    const frame = requestAnimationFrame(() => {
      amountInputRef.current?.focus();
      amountInputRef.current?.select();
    });

    return () => cancelAnimationFrame(frame);
  }, [open, expense]);

  function handleClose(open: boolean) {
    onOpenChange(open);
    if (!open) reset();
  }

  async function onSubmit(data: EditFormValues) {
    if (!expense) return;

    if (isPayed && data.markAsPending) {
      await updateExpense(expense.id, {
        amount: data.amount,
        dueDate: data.dueDate.toISOString(),
        status: "PENDING",
      });
    } else if (isPayed) {
      await updateExpense(expense.id, {
        amount: data.amount,
        dueDate: data.dueDate.toISOString(),
        amountPayed: data.amountPayed!,
        paymentDate: data.paymentDate!.toISOString(),
      });
    } else {
      await updateExpense(expense.id, {
        amount: data.amount,
        dueDate: data.dueDate.toISOString(),
      });
    }

    handleClose(false);
  }

  if (!expense) return null;

  return (
    <ResponsiveDialog open={open} onOpenChange={handleClose}>
      <ResponsiveDialogContent>
        <ResponsiveDialogHeader>
          <ResponsiveDialogTitle>Editar gasto</ResponsiveDialogTitle>
        </ResponsiveDialogHeader>

        <div className="flex flex-col gap-1 rounded-lg bg-muted px-3 py-2 text-sm">
          <span className="font-medium">{expense.description}</span>
        </div>

        <form
          id="edit-expense-form"
          onSubmit={handleSubmit(onSubmit)}
          className="flex flex-col gap-4"
        >
          <div className="flex flex-col gap-1.5">
            <label htmlFor="amount" className="text-sm font-medium">
              Monto
            </label>
            <input
              id="amount"
              type="text"
              inputMode="numeric"
              pattern="[0-9]*"
              {...amountField}
              ref={(node) => {
                amountRef(node);
                amountInputRef.current = node;
              }}
              className="h-8 rounded-lg border border-input bg-background px-2.5 text-sm outline-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50"
            />
            {errors.amount && (
              <span className="text-xs text-destructive">
                {errors.amount.message}
              </span>
            )}
          </div>

          <div className="flex flex-col gap-1.5">
            <span className="text-sm font-medium">Fecha de vencimiento</span>
            <Controller
              control={control}
              name="dueDate"
              render={({ field }) => (
                <DatePicker
                  value={field.value}
                  onChange={field.onChange}
                  placeholder="Seleccionar fecha"
                />
              )}
            />
            {errors.dueDate && (
              <span className="text-xs text-destructive">
                {errors.dueDate.message}
              </span>
            )}
          </div>

          {isPayed && (
            <>
              <hr className="border-border" />

              <div className="flex flex-col gap-3">
                <span className="text-sm font-medium">
                  Información del pago
                </span>

                {!markAsPending && (
                  <>
                    <div className="flex flex-col gap-1.5">
                      <label htmlFor="amountPayed" className="text-sm font-medium">
                        Monto pagado
                      </label>
                      <input
                        id="amountPayed"
                        type="text"
                        inputMode="numeric"
                        pattern="[0-9]*"
                        {...register("amountPayed", {
                          setValueAs: (value) => Number(value),
                        })}
                        className="h-8 rounded-lg border border-input bg-background px-2.5 text-sm outline-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50"
                      />
                      {errors.amountPayed && (
                        <span className="text-xs text-destructive">
                          {errors.amountPayed.message}
                        </span>
                      )}
                    </div>

                    <div className="flex flex-col gap-1.5">
                      <span className="text-sm font-medium">
                        Fecha de pago
                      </span>
                      <Controller
                        control={control}
                        name="paymentDate"
                        render={({ field }) => (
                          <DatePicker
                            value={field.value}
                            onChange={field.onChange}
                            placeholder="Seleccionar fecha"
                          />
                        )}
                      />
                      {errors.paymentDate && (
                        <span className="text-xs text-destructive">
                          {errors.paymentDate.message}
                        </span>
                      )}
                    </div>
                  </>
                )}

                <label className="flex items-center gap-2 text-sm cursor-pointer">
                  <Controller
                    control={control}
                    name="markAsPending"
                    render={({ field }) => (
                      <button
                        type="button"
                        role="checkbox"
                        aria-checked={field.value}
                        onClick={() => field.onChange(!field.value)}
                        className={
                          field.value
                            ? "flex size-4 shrink-0 items-center justify-center rounded-[4px] bg-primary text-primary-foreground ring-offset-background transition-colors"
                            : "flex size-4 shrink-0 items-center justify-center rounded-[4px] border border-input bg-background ring-offset-background transition-colors hover:border-ring"
                        }
                      >
                        {field.value && (
                          <svg
                            width="10"
                            height="10"
                            viewBox="0 0 10 10"
                            fill="none"
                            xmlns="http://www.w3.org/2000/svg"
                          >
                            <path
                              d="M2 5.5L4 7.5L8 3"
                              stroke="currentColor"
                              strokeWidth="1.5"
                              strokeLinecap="round"
                              strokeLinejoin="round"
                            />
                          </svg>
                        )}
                      </button>
                    )}
                  />
                  <span>Marcar como pendiente</span>
                </label>

                {markAsPending && (
                  <p className="text-xs text-muted-foreground">
                    Al marcar como pendiente, se borrarán el monto pagado y la
                    fecha de pago.
                  </p>
                )}
              </div>
            </>
          )}
        </form>

        <ResponsiveDialogFooter>
          <Button
            variant="outline"
            onClick={() => handleClose(false)}
            disabled={isSubmitting}
          >
            Cancelar
          </Button>
          <Button
            type="submit"
            form="edit-expense-form"
            disabled={isSubmitting}
          >
            Guardar cambios
          </Button>
        </ResponsiveDialogFooter>
      </ResponsiveDialogContent>
    </ResponsiveDialog>
  );
}
