'use client';

import { Button } from '@/components/ui/button';
import {
  Dialog,
  DialogBody,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from '@/components/ui/dialog';
import { Field } from '@/components/ui/field';
import { Input } from '@/components/ui/input';
import { Textarea } from '@/components/ui/textarea';
import {
  createContext,
  useCallback,
  useContext,
  useEffect,
  useRef,
  useState,
  type FormEvent,
} from 'react';

/*
 * Reemplazo de `window.prompt`.
 *
 * El prompt del navegador no valida nada, no admite texto de varias líneas, no
 * explica para qué sirve el dato, y en la app instalada aparece con el nombre
 * del sitio adelante. Acá es un formulario de verdad: etiqueta, ayuda,
 * validación y un botón que dice lo que hace.
 *
 * Mantiene la API de promesa para que el código que lo llama no cambie de
 * forma:
 *
 *   const nombre = window.prompt('Nueva marca:');        // antes
 *   const nombre = await prompt({ title: 'Nueva marca' }); // ahora
 *
 * Devuelve el texto ya recortado, o null si la persona canceló.
 */

export type PromptOptions = {
  title: string;
  /** Para qué se pide el dato. Una frase, en palabras del taller. */
  description?: string;
  /** Etiqueta del campo. Por defecto usa el título. */
  label?: string;
  placeholder?: string;
  defaultValue?: string;
  hint?: string;
  /** `true` para un campo de varias líneas (por ejemplo, un motivo). */
  multiline?: boolean;
  confirmLabel?: string;
  cancelLabel?: string;
  /** Si es false, se acepta dejarlo vacío. Por defecto es obligatorio. */
  required?: boolean;
  /** Validación extra. Devolvé el mensaje de error, o null si está bien. */
  validate?: (value: string) => string | null;
};

type PromptFn = (options: PromptOptions) => Promise<string | null>;

const PromptContext = createContext<PromptFn | null>(null);

export function usePrompt(): PromptFn {
  const context = useContext(PromptContext);
  if (!context) {
    throw new Error('usePrompt debe usarse dentro de PromptProvider');
  }
  return context;
}

export function PromptProvider({ children }: { children: React.ReactNode }) {
  const [options, setOptions] = useState<PromptOptions | null>(null);
  const [open, setOpen] = useState(false);
  const [value, setValue] = useState('');
  const [error, setError] = useState<string | null>(null);
  const resolverRef = useRef<((value: string | null) => void) | null>(null);

  const prompt = useCallback<PromptFn>((nextOptions) => {
    return new Promise<string | null>((resolve) => {
      resolverRef.current?.(null);
      resolverRef.current = resolve;
      setOptions(nextOptions);
      setValue(nextOptions.defaultValue ?? '');
      setError(null);
      setOpen(true);
    });
  }, []);

  const settle = useCallback((result: string | null) => {
    resolverRef.current?.(result);
    resolverRef.current = null;
    setOpen(false);
  }, []);

  // Limpia el texto recién cuando la animación de cierre terminó, para que no
  // se vea el campo vaciarse mientras el diálogo se va.
  useEffect(() => {
    if (open) return;
    const timer = window.setTimeout(() => setOptions(null), 200);
    return () => window.clearTimeout(timer);
  }, [open]);

  const handleSubmit = (event: FormEvent) => {
    event.preventDefault();
    if (!options) return;

    const trimmed = value.trim();
    const required = options.required ?? true;

    if (required && !trimmed) {
      setError('Este dato es obligatorio.');
      return;
    }

    const custom = options.validate?.(trimmed) ?? null;
    if (custom) {
      setError(custom);
      return;
    }

    settle(trimmed);
  };

  const fieldId = 'prompt-field';
  const multiline = options?.multiline ?? false;

  return (
    <PromptContext.Provider value={prompt}>
      {children}

      <Dialog
        open={open}
        onOpenChange={(next) => {
          if (!next) settle(null);
        }}
      >
        {options ? (
          <DialogContent className="sm:max-w-md">
            <form onSubmit={handleSubmit} className="flex min-h-0 flex-col">
              <DialogHeader>
                <DialogTitle>{options.title}</DialogTitle>
                {options.description ? (
                  <DialogDescription>{options.description}</DialogDescription>
                ) : null}
              </DialogHeader>

              <DialogBody>
                <Field
                  label={options.label || options.title}
                  htmlFor={fieldId}
                  hint={options.hint}
                  error={error ?? undefined}
                  required={options.required ?? true}
                >
                  {multiline ? (
                    <Textarea
                      autoFocus
                      value={value}
                      placeholder={options.placeholder}
                      onChange={(event) => {
                        setValue(event.target.value);
                        if (error) setError(null);
                      }}
                    />
                  ) : (
                    <Input
                      autoFocus
                      value={value}
                      placeholder={options.placeholder}
                      onChange={(event) => {
                        setValue(event.target.value);
                        if (error) setError(null);
                      }}
                    />
                  )}
                </Field>
              </DialogBody>

              <DialogFooter>
                <Button type="button" variant="outline" size="lg" onClick={() => settle(null)}>
                  {options.cancelLabel || 'Cancelar'}
                </Button>
                <Button type="submit" size="lg">
                  {options.confirmLabel || 'Guardar'}
                </Button>
              </DialogFooter>
            </form>
          </DialogContent>
        ) : null}
      </Dialog>
    </PromptContext.Provider>
  );
}
