/**
 * Dialog — 令牌驱动的模态对话框（task 18.8，Req 19.1 / 19.5）。
 *
 * 受控显隐（`open` + `onClose`）。可访问性（便于 task 22.x）：
 *   - 容器 `role="dialog"` 且 `aria-modal="true"`；
 *   - `aria-labelledby` 关联标题；
 *   - 打开时自动聚焦关闭按钮；按 `Escape` 触发关闭；
 *   - 关闭按钮图标取自单一来源图标集（Req 19.5）。
 *
 * 完整的焦点陷阱（focus trap）留待 task 22.x；此处提供合理的基础行为。
 */

import { useEffect, useRef } from 'react';
import type { CSSProperties, ReactNode } from 'react';
import { colorVar, FONT_FAMILY, RADIUS, space, typographyStyle } from './styles.js';
import { Icon } from './Icon.js';

/** `Dialog` 组件属性。 */
export interface DialogProps {
  /** 是否显示。 */
  readonly open: boolean;
  /** 请求关闭的回调（点击遮罩、关闭按钮或按 Escape 时触发）。 */
  readonly onClose: () => void;
  /** 对话框标题。 */
  readonly title: string;
  /** 对话框主体内容。 */
  readonly children: ReactNode;
  /** 可选底部操作区。 */
  readonly footer?: ReactNode;
  /** 关闭按钮的无障碍标签，默认「关闭」。 */
  readonly closeLabel?: string;
}

/**
 * 模态对话框。显隐受控，具备基础键盘与焦点行为（Req 19.1）。
 */
export function Dialog({
  open,
  onClose,
  title,
  children,
  footer,
  closeLabel = '关闭',
}: DialogProps): JSX.Element | null {
  const closeButtonRef = useRef<HTMLButtonElement>(null);
  const titleId = useRef(`dialog-title-${Math.random().toString(36).slice(2)}`).current;

  // 打开时聚焦关闭按钮，提供合理的初始焦点。
  useEffect(() => {
    if (open) {
      closeButtonRef.current?.focus();
    }
  }, [open]);

  // Escape 关闭。
  useEffect(() => {
    if (!open) {
      return;
    }
    const handler = (event: KeyboardEvent): void => {
      if (event.key === 'Escape') {
        onClose();
      }
    };
    document.addEventListener('keydown', handler);
    return () => {
      document.removeEventListener('keydown', handler);
    };
  }, [open, onClose]);

  if (!open) {
    return null;
  }

  const overlayStyle: CSSProperties = {
    position: 'fixed',
    inset: 0,
    backgroundColor: 'rgba(0, 0, 0, 0.5)',
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center',
    padding: `${space(4)}px`,
    zIndex: 1000,
  };

  const dialogStyle: CSSProperties = {
    display: 'flex',
    flexDirection: 'column',
    width: '100%',
    maxWidth: '480px',
    maxHeight: '100%',
    backgroundColor: colorVar('color.bg.elevated'),
    border: `1px solid ${colorVar('color.border.default')}`,
    borderRadius: `${RADIUS.md}px`,
    fontFamily: FONT_FAMILY,
    color: colorVar('color.text.primary'),
    overflow: 'hidden',
  };

  const headerStyle: CSSProperties = {
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'space-between',
    gap: `${space(3)}px`,
    padding: `${space(3)}px ${space(4)}px`,
    borderBottom: `1px solid ${colorVar('color.border.default')}`,
    ...typographyStyle('title'),
    fontWeight: 700,
  };

  const closeButtonStyle: CSSProperties = {
    display: 'inline-flex',
    alignItems: 'center',
    justifyContent: 'center',
    padding: `${space(1)}px`,
    background: 'transparent',
    border: 'none',
    borderRadius: `${RADIUS.sm}px`,
    cursor: 'pointer',
    color: colorVar('color.text.secondary'),
  };

  return (
    <div
      style={overlayStyle}
      onClick={(event) => {
        if (event.target === event.currentTarget) {
          onClose();
        }
      }}
    >
      <div role="dialog" aria-modal="true" aria-labelledby={titleId} style={dialogStyle}>
        <header style={headerStyle}>
          <h2 id={titleId} style={{ margin: 0, ...typographyStyle('title') }}>
            {title}
          </h2>
          <button
            ref={closeButtonRef}
            type="button"
            aria-label={closeLabel}
            onClick={onClose}
            style={closeButtonStyle}
          >
            <Icon name="close" size={20} />
          </button>
        </header>
        <div style={{ padding: `${space(4)}px`, overflowY: 'auto', ...typographyStyle('body') }}>
          {children}
        </div>
        {footer !== undefined ? (
          <footer
            style={{
              display: 'flex',
              justifyContent: 'flex-end',
              gap: `${space(2)}px`,
              padding: `${space(3)}px ${space(4)}px`,
              borderTop: `1px solid ${colorVar('color.border.default')}`,
            }}
          >
            {footer}
          </footer>
        ) : null}
      </div>
    </div>
  );
}
