/* Core component library — Phase 1.
 *
 * Components: Button, Card, Pill, Avatar, Input, TextArea, SegmentedControl,
 * Drawer, Toast, ToastHost, EmptyState, LoadingSpinner, Banner.
 *
 * Each is the canonical implementation — feature flows compose these,
 * never inline equivalents. Phase 2+ components (RecordButton, etc.) live
 * alongside the flow that uses them.
 *
 * Tactile rules baked in: user-select:none on tappables (handled in CSS
 * + class names), 44px min tap targets on phone, focus-visible rings,
 * form-wrapped inputs.
 */
(function () {
  const { useState, useEffect, useRef, useCallback, useId } = React;
  const t = window.CC.tokens;
  const m = window.CC.motion;
  const Icons = window.CC.Icons;

  // ────────────────────────────────────────────────────────────
  // Button
  // ────────────────────────────────────────────────────────────
  function Button({
    variant = "primary",
    size = "md",
    icon,
    iconRight,
    loading = false,
    disabled = false,
    onClick,
    type = "button",
    children,
    fullWidth = false,
    ...rest
  }) {
    const cls = [
      "cc-btn",
      `cc-btn--${variant}`,
      `cc-btn--${size}`,
      fullWidth ? "cc-btn--full" : "",
      loading ? "cc-btn--loading" : "",
    ]
      .filter(Boolean)
      .join(" ");

    return (
      <button
        type={type}
        className={cls}
        onClick={onClick}
        disabled={disabled || loading}
        {...rest}
      >
        {loading ? (
          <LoadingSpinner size="sm" inline />
        ) : (
          <>
            {icon && <span className="cc-btn__icon">{icon}</span>}
            {children && <span className="cc-btn__label">{children}</span>}
            {iconRight && <span className="cc-btn__icon">{iconRight}</span>}
          </>
        )}
      </button>
    );
  }

  // ────────────────────────────────────────────────────────────
  // Card
  // ────────────────────────────────────────────────────────────
  function Card({
    variant = "elevated",
    padding = 20,
    onClick,
    as: Tag = onClick ? "button" : "div",
    className = "",
    children,
    ...rest
  }) {
    const interactive = Boolean(onClick);
    const cls = [
      "cc-card",
      `cc-card--${variant}`,
      interactive ? "cc-card--interactive" : "",
      className,
    ]
      .filter(Boolean)
      .join(" ");
    const style = { padding };
    return (
      <Tag
        className={cls}
        style={style}
        onClick={onClick}
        {...(interactive && Tag === "button" ? { type: "button" } : {})}
        {...rest}
      >
        {children}
      </Tag>
    );
  }

  // ────────────────────────────────────────────────────────────
  // Pill — small status indicator. Tone resolved from token map.
  // ────────────────────────────────────────────────────────────
  function Pill({ tone = "other", size = "md", children }) {
    const colour = t.colors.status[tone] || t.colors.status.other;
    const cls = ["cc-pill", `cc-pill--${size}`].join(" ");
    return (
      <span
        className={cls}
        style={{ "--pill-tone": colour }}
      >
        {children}
      </span>
    );
  }

  // ────────────────────────────────────────────────────────────
  // Avatar — coach identity circle.
  // ────────────────────────────────────────────────────────────
  function Avatar({ coach = "simon", size = 32, label }) {
    const colour = t.colors.coach[coach] || t.colors.greys[5];
    const initial = (label || coach).charAt(0).toUpperCase();
    const fontSize = Math.round(size * 0.42);
    return (
      <span
        className="cc-avatar"
        style={{
          width: size,
          height: size,
          background: colour,
          fontSize,
        }}
        aria-label={label || coach}
      >
        {initial}
      </span>
    );
  }

  // ────────────────────────────────────────────────────────────
  // Input — text field with bottom border, label above.
  // Wrapped in <form> by the caller for Enter-submit semantics.
  // ────────────────────────────────────────────────────────────
  function Input({
    label,
    value,
    onChange,
    onSubmit,
    placeholder,
    type = "text",
    autoFocus = false,
    disabled = false,
    icon,
    name,
    inputMode,
    ...rest
  }) {
    const id = useId();
    const inner = (
      <div className={`cc-input ${icon ? "cc-input--with-icon" : ""}`}>
        {label && (
          <label htmlFor={id} className="cc-input__label">
            {label}
          </label>
        )}
        <div className="cc-input__field">
          {icon && <span className="cc-input__icon">{icon}</span>}
          <input
            id={id}
            type={type}
            value={value ?? ""}
            onChange={(e) => onChange?.(e.target.value)}
            placeholder={placeholder}
            autoFocus={autoFocus}
            disabled={disabled}
            name={name}
            inputMode={inputMode}
            {...rest}
          />
        </div>
      </div>
    );
    if (onSubmit) {
      return (
        <form
          onSubmit={(e) => {
            e.preventDefault();
            onSubmit(value);
          }}
        >
          {inner}
        </form>
      );
    }
    return inner;
  }

  // ────────────────────────────────────────────────────────────
  // TextArea — multi-line, auto-grow up to maxRows.
  // ────────────────────────────────────────────────────────────
  function TextArea({
    label,
    value,
    onChange,
    placeholder,
    rows = 3,
    maxRows = 12,
    disabled = false,
    autoFocus = false,
    name,
  }) {
    const id = useId();
    const ref = useRef(null);
    useEffect(() => {
      const el = ref.current;
      if (!el) return;
      el.style.height = "auto";
      const lineHeight = parseFloat(getComputedStyle(el).lineHeight) || 22;
      const max = lineHeight * maxRows;
      el.style.height = Math.min(el.scrollHeight, max) + "px";
      el.style.overflowY = el.scrollHeight > max ? "auto" : "hidden";
    }, [value, maxRows]);
    return (
      <div className="cc-input cc-input--multiline">
        {label && (
          <label htmlFor={id} className="cc-input__label">
            {label}
          </label>
        )}
        <textarea
          id={id}
          ref={ref}
          rows={rows}
          value={value ?? ""}
          onChange={(e) => onChange?.(e.target.value)}
          placeholder={placeholder}
          disabled={disabled}
          autoFocus={autoFocus}
          name={name}
        />
      </div>
    );
  }

  // ────────────────────────────────────────────────────────────
  // SegmentedControl — pill container with sliding selector.
  // ────────────────────────────────────────────────────────────
  function SegmentedControl({ options, value, onChange, size = "md" }) {
    const refs = useRef({});
    const [thumb, setThumb] = useState({ left: 0, width: 0 });
    useEffect(() => {
      const el = refs.current[value];
      if (!el) return;
      const r = el.getBoundingClientRect();
      const parentR = el.parentElement.getBoundingClientRect();
      setThumb({
        left: r.left - parentR.left,
        width: r.width,
      });
    }, [value, options]);
    return (
      <div className={`cc-segmented cc-segmented--${size}`} role="tablist">
        <span
          className="cc-segmented__thumb"
          style={{ left: thumb.left, width: thumb.width }}
          aria-hidden="true"
        />
        {options.map((opt) => (
          <button
            key={opt.value}
            ref={(el) => (refs.current[opt.value] = el)}
            type="button"
            role="tab"
            aria-selected={value === opt.value}
            className={`cc-segmented__btn ${
              value === opt.value ? "is-active" : ""
            }`}
            onClick={() => onChange(opt.value)}
          >
            {opt.label}
          </button>
        ))}
      </div>
    );
  }

  // ────────────────────────────────────────────────────────────
  // Drawer — slide-up sheet on phone, scale-modal on desktop.
  // ────────────────────────────────────────────────────────────
  function Drawer({ open, onClose, title, children, footer }) {
    useEffect(() => {
      if (!open) return;
      const onKey = (e) => {
        if (e.key === "Escape") onClose?.();
      };
      document.addEventListener("keydown", onKey);
      const prev = document.body.style.overflow;
      document.body.style.overflow = "hidden";
      return () => {
        document.removeEventListener("keydown", onKey);
        document.body.style.overflow = prev;
      };
    }, [open, onClose]);

    if (!open) return null;
    return (
      <div className="cc-drawer-root" role="dialog" aria-modal="true">
        <div className="cc-drawer__backdrop" onClick={onClose} />
        <div className="cc-drawer__sheet">
          <header className="cc-drawer__header">
            <h2 className="cc-drawer__title">{title}</h2>
            <button
              type="button"
              className="cc-drawer__close"
              onClick={onClose}
              aria-label="Close"
            >
              {Icons.x(18)}
            </button>
          </header>
          <div className="cc-drawer__body">{children}</div>
          {footer && <footer className="cc-drawer__footer">{footer}</footer>}
        </div>
      </div>
    );
  }

  // ────────────────────────────────────────────────────────────
  // Toast — undo-style transient message.
  // Use ToastHost + showToast(). Only one host per app.
  // ────────────────────────────────────────────────────────────
  let pushToast = () => {};
  function ToastHost() {
    const [toasts, setToasts] = useState([]);
    useEffect(() => {
      pushToast = (toast) => {
        const id = Math.random().toString(36).slice(2);
        const duration = toast.duration ?? 6000;
        setToasts((prev) => [...prev, { ...toast, id }]);
        if (duration > 0) {
          setTimeout(() => {
            setToasts((prev) => prev.filter((t) => t.id !== id));
          }, duration);
        }
      };
      return () => {
        pushToast = () => {};
      };
    }, []);
    const dismiss = (id) =>
      setToasts((prev) => prev.filter((t) => t.id !== id));
    return (
      <div className="cc-toast-host" aria-live="polite">
        {toasts.map((tt) => (
          <div key={tt.id} className="cc-toast" role="status">
            <span className="cc-toast__msg">{tt.message}</span>
            {tt.action && (
              <button
                type="button"
                className="cc-toast__action"
                onClick={() => {
                  tt.action.onClick?.();
                  dismiss(tt.id);
                }}
              >
                {tt.action.label}
              </button>
            )}
            <button
              type="button"
              className="cc-toast__close"
              onClick={() => dismiss(tt.id)}
              aria-label="Dismiss"
            >
              {Icons.x(14)}
            </button>
          </div>
        ))}
      </div>
    );
  }
  function showToast(message, opts = {}) {
    pushToast({ message, ...opts });
  }

  // ────────────────────────────────────────────────────────────
  // EmptyState — designed empty state for views with no data.
  // ────────────────────────────────────────────────────────────
  function EmptyState({ title, subtitle, icon, action }) {
    return (
      <div className="cc-empty">
        {icon && <div className="cc-empty__icon">{icon}</div>}
        <h3 className="cc-empty__title">{title}</h3>
        {subtitle && <p className="cc-empty__sub">{subtitle}</p>}
        {action && (
          <div className="cc-empty__action">
            <Button variant="secondary" onClick={action.onClick}>
              {action.label}
            </Button>
          </div>
        )}
      </div>
    );
  }

  // ────────────────────────────────────────────────────────────
  // LoadingSpinner — only renders after `delay` ms (default 300)
  // to avoid flashing on fast operations. Spec section 8.15.
  // ────────────────────────────────────────────────────────────
  function LoadingSpinner({ size = "md", delay = 300, inline = false }) {
    const [show, setShow] = useState(delay === 0);
    useEffect(() => {
      if (delay === 0) return;
      const id = setTimeout(() => setShow(true), delay);
      return () => clearTimeout(id);
    }, [delay]);
    if (!show) return null;
    const px = { sm: 16, md: 24, lg: 40 }[size] ?? size;
    return (
      <span
        className={`cc-spinner ${inline ? "cc-spinner--inline" : ""}`}
        style={{ width: px, height: px }}
        aria-hidden="true"
      />
    );
  }

  // ────────────────────────────────────────────────────────────
  // Banner — full-width strip at top of a page.
  // ────────────────────────────────────────────────────────────
  function Banner({ tone = "info", message, action, onDismiss }) {
    return (
      <div className={`cc-banner cc-banner--${tone}`} role="status">
        <span className="cc-banner__msg">{message}</span>
        <div className="cc-banner__actions">
          {action && (
            <button
              type="button"
              className="cc-banner__action"
              onClick={action.onClick}
            >
              {action.label}
            </button>
          )}
          {onDismiss && (
            <button
              type="button"
              className="cc-banner__close"
              onClick={onDismiss}
              aria-label="Dismiss"
            >
              {Icons.x(14)}
            </button>
          )}
        </div>
      </div>
    );
  }

  window.CC = Object.assign(window.CC || {}, {
    Button,
    Card,
    Pill,
    Avatar,
    Input,
    TextArea,
    SegmentedControl,
    Drawer,
    Toast: ToastHost,
    ToastHost,
    showToast,
    EmptyState,
    LoadingSpinner,
    Banner,
  });
})();
