'use client';
import { createContext, useCallback, useContext, useEffect, useRef, useState, ReactNode } from 'react';

export type DialogTone = 'success' | 'error' | 'info';

type DialogState =
  | { id: number; kind: 'alert'; title: string; message: string; tone: DialogTone }
  | { id: number; kind: 'confirm'; title: string; message: string; confirmLabel: string; resolve: (v: boolean) => void }
  | { id: number; kind: 'prompt'; title: string; message: string; initial: string; resolve: (v: string | null) => void };

interface DialogApi {
  /** App-styled modal replacing window.alert — resolves when dismissed. */
  notify: (message: string, opts?: { title?: string; tone?: DialogTone }) => void;
  /** App-styled modal replacing window.confirm. */
  confirmDialog: (message: string, opts?: { title?: string; confirmLabel?: string }) => Promise<boolean>;
  /** App-styled modal replacing window.prompt. */
  promptDialog: (message: string, opts?: { title?: string; initial?: string; confirmLabel?: string }) => Promise<string | null>;
}

const Ctx = createContext<DialogApi>({
  notify: () => {},
  confirmDialog: async () => false,
  promptDialog: async () => null,
});

export const useDialog = () => useContext(Ctx);

let nextId = 1;

const TONE_STYLE: Record<DialogTone, { bg: string; fg: string; glyph: string }> = {
  success: { bg: '#dcfce7', fg: '#15803d', glyph: '✓' },
  error: { bg: '#fee2e2', fg: '#dc2626', glyph: '!' },
  info: { bg: '#dbeafe', fg: '#1d4ed8', glyph: 'i' },
};

export function DialogProvider({ children }: { children: ReactNode }) {
  const [stack, setStack] = useState<DialogState[]>([]);
  const [promptVal, setPromptVal] = useState('');
  const okRef = useRef<HTMLButtonElement>(null);

  const dismiss = useCallback((id: number, result?: boolean | string | null) => {
    setStack((s) => {
      const d = s.find((x) => x.id === id);
      if (d?.kind === 'confirm') d.resolve(result === true);
      else if (d?.kind === 'prompt') d.resolve(typeof result === 'string' ? result : null);
      return s.filter((x) => x.id !== id);
    });
  }, []);

  const notify = useCallback<DialogApi['notify']>((message, opts) => {
    setStack((s) => [...s, {
      id: nextId++, kind: 'alert',
      title: opts?.title ?? (opts?.tone === 'error' ? 'Something went wrong' : opts?.tone === 'success' ? 'Done' : 'Notice'),
      message, tone: opts?.tone ?? 'info',
    }]);
  }, []);

  const confirmDialog = useCallback<DialogApi['confirmDialog']>((message, opts) => {
    return new Promise<boolean>((resolve) => {
      setStack((s) => [...s, {
        id: nextId++, kind: 'confirm', resolve,
        title: opts?.title ?? 'Please confirm',
        message, confirmLabel: opts?.confirmLabel ?? 'Confirm',
      }]);
    });
  }, []);

  const promptDialog = useCallback<DialogApi['promptDialog']>((message, opts) => {
    return new Promise<string | null>((resolve) => {
      setPromptVal(opts?.initial ?? '');
      setStack((s) => [...s, {
        id: nextId++, kind: 'prompt', resolve,
        title: opts?.title ?? 'Input required',
        message, initial: opts?.initial ?? '',
      }]);
    });
  }, []);

  const top = stack[stack.length - 1];

  useEffect(() => {
    if (!top) return;
    okRef.current?.focus();
    const onKey = (e: KeyboardEvent) => {
      if (e.key === 'Escape') dismiss(top.id);
      if (e.key === 'Enter' && top.kind === 'alert') dismiss(top.id);
    };
    document.addEventListener('keydown', onKey);
    return () => document.removeEventListener('keydown', onKey);
  }, [top, dismiss]);

  return (
    <Ctx.Provider value={{ notify, confirmDialog, promptDialog }}>
      {children}
      {top && (
        <div className="fixed inset-0 z-[100] grid place-items-center p-4" role="presentation"
          onMouseDown={(e) => { if (e.target === e.currentTarget) dismiss(top.id); }}>
          <div className="absolute inset-0 bg-black/50" aria-hidden="true" />
          <div role="alertdialog" aria-modal="true" aria-label={top.title}
            className="relative card !p-5 w-full max-w-sm space-y-3 shadow-xl">
            <div className="flex items-center gap-3">
              <span aria-hidden="true" className="inline-flex w-9 h-9 items-center justify-center rounded-full text-lg font-bold shrink-0"
                style={top.kind === 'alert'
                  ? { background: TONE_STYLE[top.tone].bg, color: TONE_STYLE[top.tone].fg }
                  : { background: '#dbeafe', color: '#1d4ed8' }}>
                {top.kind === 'alert' ? TONE_STYLE[top.tone].glyph : top.kind === 'confirm' ? '?' : '✎'}
              </span>
              <h2 className="font-semibold">{top.title}</h2>
            </div>
            <p className="text-sm text-slate-600 whitespace-pre-wrap">{top.message}</p>
            {top.kind === 'prompt' && (
              <input autoFocus className="input text-sm" aria-label={top.message} value={promptVal}
                onChange={(e) => setPromptVal(e.target.value)}
                onKeyDown={(e) => {
                  if (e.key === 'Enter' && promptVal.trim()) dismiss(top.id, promptVal.trim());
                }} />
            )}
            <div className="flex justify-end gap-2">
              {top.kind === 'alert' && (
                <button ref={okRef} className="btn-primary btn-sm" onClick={() => dismiss(top.id)}>OK</button>
              )}
              {top.kind === 'confirm' && (
                <>
                  <button className="btn-ghost btn-sm" onClick={() => dismiss(top.id, false)}>Cancel</button>
                  <button ref={okRef} className="btn-primary btn-sm" onClick={() => dismiss(top.id, true)}>{top.confirmLabel}</button>
                </>
              )}
              {top.kind === 'prompt' && (
                <>
                  <button className="btn-ghost btn-sm" onClick={() => dismiss(top.id, null)}>Cancel</button>
                  <button className="btn-primary btn-sm" disabled={!promptVal.trim()} onClick={() => dismiss(top.id, promptVal.trim())}>Save</button>
                </>
              )}
            </div>
          </div>
        </div>
      )}
    </Ctx.Provider>
  );
}
