import { useEffect, useRef, useState } from 'react';
import { ModalPortal } from './modals/ModalPortal';

/**
 * App-level popups for file-control actions, shaped exactly like the
 * "Are you sure?" revert confirm: a small centered card with an icon on top,
 * a title, body text, and a button row.
 *
 * InfoDialog is the grey single-"Okay" variant used for status explanations
 * and the pull help; DangerConfirmDialog is the red two-button variant used
 * before destructive actions (reverting files with changes).
 */

// SVGs ship monochrome (#e3e3e3); mask-render them so each status keeps its
// color. Inline style because CSS url() would resolve relative to the
// stylesheet — this stays document-relative like every <img src="assets/…">.
export function StatusIcon({ icon, color, className }) {
  return (
    <span
      className={`status-icon status-icon--${color}${className ? ` ${className}` : ''}`}
      style={{ WebkitMaskImage: `url("${icon}")`, maskImage: `url("${icon}")` }}
      aria-hidden="true"
    />
  );
}

function DialogShell({ variant, onDismiss, children }) {
  useEffect(() => {
    const onKey = (e) => {
      if (e.key === 'Escape') {
        e.stopPropagation();
        onDismiss();
      }
    };
    document.addEventListener('keydown', onKey, true);
    return () => document.removeEventListener('keydown', onKey, true);
  }, [onDismiss]);

  return (
    <ModalPortal>
      <div className="cbm-confirm-overlay" onMouseDown={onDismiss}>
        <div
          className={`cbm-confirm-dialog cbm-confirm-dialog--${variant}`}
          role="dialog"
          aria-modal="true"
          onMouseDown={(e) => e.stopPropagation()}
        >
          {children}
        </div>
      </div>
    </ModalPortal>
  );
}

export function InfoDialog({ icon, color = 'grey', title, text, onClose, variant = 'info' }) {
  const okayRef = useRef(null);
  useEffect(() => okayRef.current?.focus(), []);

  return (
    <DialogShell variant={variant} onDismiss={onClose}>
      <StatusIcon icon={icon} color={color} className="cbm-confirm-icon" />
      <h3 className="cbm-confirm-title">{title}</h3>
      <p className="cbm-confirm-text">{text}</p>
      <div className="cbm-confirm-actions">
        <button ref={okayRef} type="button" className="revision-pill-btn" onClick={onClose}>
          Okay
        </button>
      </div>
    </DialogShell>
  );
}

/** Grey two-way question (e.g. teammate-deleted files): both options equal. */
export function ChoiceDialog({ icon, color = 'grey', title, text, options, onDismiss }) {
  const firstRef = useRef(null);
  useEffect(() => firstRef.current?.focus(), []);

  return (
    <DialogShell variant="info" onDismiss={onDismiss}>
      <StatusIcon icon={icon} color={color} className="cbm-confirm-icon" />
      <h3 className="cbm-confirm-title">{title}</h3>
      <p className="cbm-confirm-text">{text}</p>
      <div className="cbm-confirm-actions">
        {options.map((option, index) => (
          <button
            key={option.label}
            ref={index === 0 ? firstRef : undefined}
            type="button"
            className="revision-pill-btn"
            onClick={option.action}
          >
            {option.label}
          </button>
        ))}
      </div>
    </DialogShell>
  );
}

/**
 * Same card as the confirm/info dialogs, but with a scrollable, read-only list
 * of file rows in the middle (no checkboxes, no click handlers). Used by the
 * multi-file revert warning, the submit-conflict listing (with a "Checked out
 * by" column), and the stale-edit warning.
 *
 * Props:
 *  - variant/icon/color/title/text: the shared card chrome.
 *  - rows: [{ path, note? }] — note fills the optional extra column.
 *  - columnLabel: header for the extra column; omit for a single-column list.
 *  - actions: [{ label, action, danger?, primary? }] — one or two buttons.
 */
export function FileListDialog({
  variant = 'info',
  icon,
  color = 'grey',
  title,
  text,
  rows = [],
  columnLabel,
  actions = [],
  onDismiss,
}) {
  const firstRef = useRef(null);
  useEffect(() => firstRef.current?.focus(), []);

  return (
    <DialogShell variant={variant} onDismiss={onDismiss}>
      <StatusIcon icon={icon} color={color} className="cbm-confirm-icon" />
      <h3 className="cbm-confirm-title">{title}</h3>
      {text && <p className="cbm-confirm-text">{text}</p>}
      <div className="cbm-filelist">
        {columnLabel && (
          <div className="cbm-filelist-head">
            <span className="cbm-filelist-head-path">File</span>
            <span className="cbm-filelist-head-note">{columnLabel}</span>
          </div>
        )}
        <ul className="revision-file-list cbm-filelist-list">
          {rows.map((row, index) => (
            <li key={row.path}>
              <div
                className={`revision-file-row cbm-filelist-row${index % 2 === 1 ? ' revision-file-row--alt' : ''}`}
              >
                <img src="assets/file.svg" alt="" className="revision-file-icon" />
                <span className="revision-file-path">{row.path}</span>
                {columnLabel && <span className="cbm-filelist-note">{row.note}</span>}
              </div>
            </li>
          ))}
        </ul>
      </div>
      <div className="cbm-confirm-actions">
        {actions.map((action, index) => (
          <button
            key={action.label}
            ref={index === 0 ? firstRef : undefined}
            type="button"
            className={`revision-pill-btn${action.danger ? ' revision-pill-btn--danger' : ''}${action.primary ? ' revision-pill-btn--primary' : ''}`}
            onClick={action.action}
          >
            {action.label}
          </button>
        ))}
      </div>
    </DialogShell>
  );
}

export function DangerConfirmDialog({
  title = 'Are you sure?',
  text,
  cancelLabel = 'Go back',
  confirmLabel = 'I am sure',
  onCancel,
  onConfirm,
}) {
  const cancelRef = useRef(null);
  useEffect(() => cancelRef.current?.focus(), []);

  return (
    <DialogShell variant="danger" onDismiss={onCancel}>
      <img src="assets/circle_exclaim.svg" alt="" className="cbm-confirm-icon" />
      <h3 className="cbm-confirm-title">{title}</h3>
      <p className="cbm-confirm-text">{text}</p>
      <div className="cbm-confirm-actions">
        <button ref={cancelRef} type="button" className="revision-pill-btn" onClick={onCancel}>
          {cancelLabel}
        </button>
        <button
          type="button"
          className="revision-pill-btn revision-pill-btn--danger"
          onClick={onConfirm}
        >
          {confirmLabel}
        </button>
      </div>
    </DialogShell>
  );
}

/**
 * Single text field in the same card as the confirm/info dialogs, for naming
 * something before it is created.
 *
 * `validate` gates the confirm button as the user types. `onSubmit` resolves
 * to { ok, error }; a failure keeps the dialog open with the message inline,
 * so a rejected name never costs the user what they typed. On success the
 * caller unmounts this dialog — it does not close itself.
 */
export function PromptDialog({
  icon,
  color = 'grey',
  title,
  text,
  label,
  initialValue = '',
  confirmLabel = 'Create',
  validate,
  onSubmit,
  onCancel,
}) {
  const inputRef = useRef(null);
  const [value, setValue] = useState(initialValue);
  const [submitError, setSubmitError] = useState(null);
  const [busy, setBusy] = useState(false);

  useEffect(() => {
    inputRef.current?.focus();
    inputRef.current?.select();
  }, []);

  const validationError = validate ? validate(value) : null;
  // An untouched, empty field isn't a mistake yet — the disabled button says
  // enough without an error greeting the user before they've typed.
  const shownError = submitError ?? (value.trim() ? validationError : null);
  const canSubmit = !validationError && !busy;

  const submit = async () => {
    if (!canSubmit) return;
    setBusy(true);
    try {
      const result = await onSubmit(value.trim());
      if (result?.ok) return; // the caller unmounts us
      setSubmitError(result?.error ?? 'That didn\'t work.');
      inputRef.current?.focus();
    } catch (err) {
      setSubmitError(err?.message || 'That didn\'t work.');
      inputRef.current?.focus();
    } finally {
      setBusy(false);
    }
  };

  return (
    <DialogShell variant="info" onDismiss={onCancel}>
      <StatusIcon icon={icon} color={color} className="cbm-confirm-icon" />
      <h3 className="cbm-confirm-title">{title}</h3>
      {text && <p className="cbm-confirm-text">{text}</p>}
      <div className="cbm-prompt-field">
        {label && (
          <label className="cbm-prompt-label" htmlFor="cbm-prompt-input">
            {label}
          </label>
        )}
        <input
          id="cbm-prompt-input"
          ref={inputRef}
          type="text"
          className="cbm-prompt-input"
          value={value}
          onChange={(e) => {
            setValue(e.target.value);
            // The rejection described the name they've now changed.
            setSubmitError(null);
          }}
          onKeyDown={(e) => {
            if (e.key === 'Enter') {
              e.preventDefault();
              submit();
            }
          }}
        />
      </div>
      <p
        className={`cbm-prompt-error${shownError ? '' : ' cbm-prompt-error--hidden'}`}
        role="alert"
      >
        {shownError ?? ' '}
      </p>
      <div className="cbm-confirm-actions">
        <button type="button" className="revision-pill-btn" onClick={onCancel}>
          Cancel
        </button>
        <button
          type="button"
          className="revision-pill-btn revision-pill-btn--primary"
          disabled={!canSubmit}
          onClick={submit}
        >
          {confirmLabel}
        </button>
      </div>
    </DialogShell>
  );
}
