import { useEffect, useState, type CSSProperties } from 'react';
import { useNavigate, useSearchParams } from 'react-router-dom';
import DOMPurify from 'dompurify';
import { Sidebar } from '../components/Sidebar';
import { useNotificationStore } from '../store/notification';
import { adaptAnnouncementColors } from '../lib/adaptAnnouncementColors';
import type { AppNotification, NotificationType } from '../types';

// 剥 HTML 取纯文本前 N 字,用于列表行缩略预览
function stripAndTruncate(html: string, maxChars = 60): string {
  // 用 DOMParser 而非正则,防 `<script>` 这种诡异内容
  const doc = new DOMParser().parseFromString(html, 'text/html');
  const text = (doc.body.textContent || '').replace(/\s+/g, ' ').trim();
  if (text.length <= maxChars) return text;
  return text.slice(0, maxChars) + '…';
}

// 每条通知顶部标签 — 4 色一目了然
const TYPE_CHIP: Record<NotificationType, { text: string; color: string; bg: string }> = {
  announcement: { text: '公告', color: 'var(--color-primary)', bg: 'var(--color-primary-bg, rgba(0,184,230,0.12))' },
  anomaly_disabled_user: { text: '安全', color: 'var(--color-danger)', bg: 'rgba(231,76,60,0.12)' },
  anomaly_disabled_team: { text: '安全', color: 'var(--color-danger)', bg: 'rgba(231,76,60,0.12)' },
  quota_warning: { text: '额度', color: '#faad14', bg: 'rgba(250,173,20,0.12)' },
  system: { text: '系统', color: 'var(--color-text-tertiary)', bg: 'var(--color-bg-elevated)' },
};

function formatRelative(iso: string): string {
  const ts = new Date(iso).getTime();
  if (Number.isNaN(ts)) return '';
  const ms = Date.now() - ts;
  if (ms < 0) return '刚刚';
  const sec = Math.floor(ms / 1000);
  if (sec < 60) return '刚刚';
  if (sec < 3600) return `${Math.floor(sec / 60)} 分钟前`;
  if (sec < 86400) return `${Math.floor(sec / 3600)} 小时前`;
  if (sec < 86400 * 7) return `${Math.floor(sec / 86400)} 天前`;
  return new Date(iso).toLocaleDateString('zh-CN');
}

const styles: Record<string, CSSProperties> = {
  layout: {
    display: 'flex',
    height: '100%',
    position: 'relative',
    zIndex: 2,
  },
  main: {
    flex: 1,
    overflowY: 'auto',
    padding: '24px 32px 60px',
    background: 'var(--color-bg-page)',
  },
  container: {
    maxWidth: 800,
    margin: '0 auto',
  },
  header: {
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'space-between',
    marginBottom: 20,
  },
  title: {
    fontSize: 20,
    fontWeight: 600,
    color: 'var(--color-text-primary)',
    margin: 0,
  },
  markAllBtn: {
    padding: '6px 14px',
    background: 'transparent',
    border: '1px solid var(--color-border-card)',
    borderRadius: 'var(--radius-btn, 6px)',
    color: 'var(--color-text-secondary)',
    fontSize: 13,
    cursor: 'pointer',
    transition: 'background 0.15s, color 0.15s',
  },
  list: {
    background: 'var(--color-bg-card)',
    border: '1px solid var(--color-border-modal-soft)',
    borderRadius: 8,
    overflow: 'hidden',
  },
  row: {
    display: 'flex',
    gap: 12,
    padding: '14px 18px',
    borderBottom: '1px solid var(--color-border-modal-soft)',
    cursor: 'pointer',
    transition: 'background 0.15s',
    position: 'relative',
  },
  rowLast: {
    borderBottom: 'none',
  },
  unreadDot: {
    width: 8,
    height: 8,
    borderRadius: '50%',
    background: 'var(--color-primary)',
    flexShrink: 0,
    marginTop: 7,
  },
  dotPlaceholder: {
    width: 8,
    height: 8,
    flexShrink: 0,
  },
  rowContent: {
    flex: 1,
    minWidth: 0,
  },
  rowHead: {
    display: 'flex',
    alignItems: 'baseline',
    justifyContent: 'space-between',
    gap: 12,
    marginBottom: 4,
  },
  rowTitle: {
    fontSize: 14,
    fontWeight: 600,
    color: 'var(--color-text-primary)',
    overflow: 'hidden',
    textOverflow: 'ellipsis',
    whiteSpace: 'nowrap',
  },
  rowTitleRead: {
    fontWeight: 500,
    color: 'var(--color-text-light)',
  },
  rowTime: {
    fontSize: 12,
    color: 'var(--color-text-tertiary)',
    flexShrink: 0,
    whiteSpace: 'nowrap',
  },
  rowBody: {
    fontSize: 13,
    color: 'var(--color-text-secondary)',
    lineHeight: 1.5,
    wordBreak: 'break-word',
  },
  empty: {
    padding: '80px 0',
    textAlign: 'center',
    color: 'var(--color-text-tertiary)',
    fontSize: 14,
  },
  loading: {
    padding: '60px 0',
    textAlign: 'center',
    color: 'var(--color-text-secondary)',
    fontSize: 14,
  },
  pagination: {
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center',
    gap: 16,
    marginTop: 20,
    color: 'var(--color-text-secondary)',
    fontSize: 13,
  },
  pageBtn: {
    width: 28,
    height: 28,
    display: 'inline-flex',
    alignItems: 'center',
    justifyContent: 'center',
    border: '1px solid var(--color-border-card)',
    background: 'transparent',
    borderRadius: 6,
    cursor: 'pointer',
    color: 'var(--color-text-secondary)',
    padding: 0,
  },
  pageBtnDisabled: {
    cursor: 'not-allowed',
    opacity: 0.4,
  },
  backBtn: {
    display: 'inline-flex',
    alignItems: 'center',
    gap: 6,
    padding: '6px 14px',
    background: 'transparent',
    border: '1px solid var(--color-border-card)',
    borderRadius: 'var(--radius-btn, 6px)',
    color: 'var(--color-text-secondary)',
    fontSize: 13,
    cursor: 'pointer',
    marginRight: 12,
  },
};

interface NotificationRowProps {
  item: AppNotification;
  isLast: boolean;
  expanded: boolean;
  onToggle: (item: AppNotification) => void;
  onJump: (url: string) => void;
}

/**
 * 通知行 — accordion 模式:
 *
 * - 折叠态:chip + title + 时间 + 一行剥 HTML 后的纯文本缩略
 * - 展开态:折叠态内容 + 下方完整内容(announcement 用 HTML 渲染,其他 plain) +
 *           如果 link_url 非空,底部加【前往查看】按钮(用户主动点才跳,不再自动跳)
 *
 * 始终同一时刻最多 1 行展开(父组件用 expandedId 单值 state 控制),
 * 点已展开的行再次点 → 收起;点其他行 → 自动收起当前展开 + 展开新行。
 */
function NotificationRow({ item, isLast, expanded, onToggle, onJump }: NotificationRowProps) {
  const rowStyle: CSSProperties = {
    ...styles.row,
    ...(isLast && !expanded ? styles.rowLast : {}),
    background: item.is_read ? 'transparent' : 'var(--color-primary-bg, transparent)',
    flexDirection: 'column',
    alignItems: 'stretch',
    cursor: 'pointer',
  };
  const titleStyle: CSSProperties = {
    ...styles.rowTitle,
    ...(item.is_read ? styles.rowTitleRead : {}),
    whiteSpace: 'normal',  // 展开后允许换行
  };
  const chip = TYPE_CHIP[item.type] || TYPE_CHIP.system;
  const isAnnouncement = item.type === 'announcement';
  const previewText = isAnnouncement
    ? stripAndTruncate(item.content, 60)
    : (item.content.length > 60 ? item.content.slice(0, 60) + '…' : item.content);

  return (
    <div
      style={rowStyle}
      onClick={() => onToggle(item)}
      onMouseEnter={(e) => {
        if (!expanded) e.currentTarget.style.background = 'var(--color-bg-hover)';
      }}
      onMouseLeave={(e) => {
        if (!expanded) {
          e.currentTarget.style.background = item.is_read
            ? 'transparent'
            : 'var(--color-primary-bg, transparent)';
        }
      }}
    >
      {/* 折叠/展开公共头部 */}
      <div style={{ display: 'flex', gap: 12, alignItems: 'flex-start' }}>
        {item.is_read ? (
          <div style={styles.dotPlaceholder} />
        ) : (
          <div style={styles.unreadDot} aria-label="未读" />
        )}
        <div style={styles.rowContent}>
          <div style={styles.rowHead}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8, minWidth: 0, flex: 1 }}>
              <span style={{
                padding: '1px 7px', borderRadius: 4, fontSize: 11, fontWeight: 500,
                color: chip.color, background: chip.bg, flexShrink: 0,
              }}>
                {chip.text}
              </span>
              <span style={titleStyle}>{item.title}</span>
            </div>
            <span style={styles.rowTime} title={new Date(item.created_at).toLocaleString('zh-CN')}>
              {formatRelative(item.created_at)}
            </span>
          </div>
          {/* 折叠态:一行缩略;展开态:不渲染缩略(改下方完整内容) */}
          {!expanded && previewText && (
            <div style={{ ...styles.rowBody, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
              {previewText}
            </div>
          )}
        </div>
        {/* 折叠/展开 chevron 视觉指示 */}
        <div style={{
          flexShrink: 0, color: 'var(--color-text-tertiary)', marginTop: 3,
          transform: expanded ? 'rotate(180deg)' : 'rotate(0deg)',
          transition: 'transform 0.15s',
        }}>
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
            <polyline points="6 9 12 15 18 9" />
          </svg>
        </div>
      </div>

      {/* 展开态:完整内容 + 【前往查看】按钮 */}
      {expanded && (
        <div style={{
          marginTop: 12, paddingTop: 12, paddingLeft: 20,
          borderTop: '1px dashed var(--color-border-modal-soft)',
        }} onClick={(e) => e.stopPropagation()}>
          {isAnnouncement ? (
            <div
              style={{
                fontSize: 13, color: 'var(--color-text-primary)', lineHeight: 1.7, wordBreak: 'break-word',
              }}
              dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(adaptAnnouncementColors(item.content)) }}
            />
          ) : (
            <div style={{
              fontSize: 13, color: 'var(--color-text-primary)', lineHeight: 1.7,
              wordBreak: 'break-word', whiteSpace: 'pre-wrap',
            }}>
              {item.content}
            </div>
          )}
          {item.link_url && (
            <button
              type="button"
              onClick={(e) => { e.stopPropagation(); onJump(item.link_url); }}
              style={{
                marginTop: 12, padding: '6px 14px', fontSize: 13,
                background: 'var(--color-primary)', color: '#fff',
                border: 'none', borderRadius: 6, cursor: 'pointer',
                display: 'inline-flex', alignItems: 'center', gap: 6,
              }}
            >
              前往查看
              <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                <path d="M5 12h14M13 5l7 7-7 7" />
              </svg>
            </button>
          )}
        </div>
      )}
    </div>
  );
}

export function NotificationsPage() {
  const navigate = useNavigate();
  const [searchParams] = useSearchParams();
  const unreadOnly = searchParams.get('unread_only') === 'true';

  // accordion 模式:始终最多 1 条展开
  const [expandedId, setExpandedId] = useState<number | null>(null);

  const list = useNotificationStore((s) => s.list);
  const total = useNotificationStore((s) => s.total);
  const page = useNotificationStore((s) => s.page);
  const pageSize = useNotificationStore((s) => s.pageSize);
  const unreadCount = useNotificationStore((s) => s.unreadCount);
  const loading = useNotificationStore((s) => s.loading);
  const fetchList = useNotificationStore((s) => s.fetchList);
  const markRead = useNotificationStore((s) => s.markRead);
  const markAllRead = useNotificationStore((s) => s.markAllRead);

  // 首次加载 + URL 切换时拉第一页
  useEffect(() => {
    fetchList({ page: 1, unread_only: unreadOnly });
    setExpandedId(null);  // 切页时收起所有
  }, [fetchList, unreadOnly]);

  const totalPages = Math.max(1, Math.ceil(total / Math.max(1, pageSize)));

  const goPage = (p: number) => {
    if (p < 1 || p > totalPages || p === page) return;
    fetchList({ page: p, unread_only: unreadOnly });
  };

  // accordion toggle:同 id 再点收起;不同 id 切换到新 id;未读自动标已读
  const handleToggle = (item: AppNotification) => {
    if (expandedId === item.id) {
      setExpandedId(null);
    } else {
      setExpandedId(item.id);
      if (!item.is_read) {
        markRead(item.id);
      }
    }
  };

  // 跳转按钮 — 用户主动点【前往查看】才触发,不再点行就跳
  const handleJump = (url: string) => {
    if (!url) return;
    if (url.startsWith('http')) {
      window.open(url, '_blank', 'noopener,noreferrer');
    } else {
      navigate(url);
    }
  };

  return (
    <div style={styles.layout}>
      <Sidebar />
      <main style={styles.main}>
        <div style={styles.container}>
          <div style={styles.header}>
            <div style={{ display: 'flex', alignItems: 'center' }}>
              <button
                style={styles.backBtn}
                onClick={() => navigate(-1)}
                title="返回上一页"
              >
                <svg viewBox="0 0 24 24" width="16" height="16" fill="currentColor">
                  <path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z" />
                </svg>
                返回
              </button>
              <h1 style={styles.title}>消息中心</h1>
            </div>
            {unreadCount > 0 && (
              <button
                style={styles.markAllBtn}
                onClick={() => markAllRead()}
                onMouseEnter={(e) => {
                  e.currentTarget.style.background = 'var(--color-bg-hover)';
                  e.currentTarget.style.color = 'var(--color-text-primary)';
                }}
                onMouseLeave={(e) => {
                  e.currentTarget.style.background = 'transparent';
                  e.currentTarget.style.color = 'var(--color-text-secondary)';
                }}
              >
                全部标记已读
              </button>
            )}
          </div>

          {loading && list.length === 0 ? (
            <div style={styles.loading}>加载中...</div>
          ) : list.length === 0 ? (
            <div style={styles.empty}>暂无消息</div>
          ) : (
            <>
              <div style={styles.list}>
                {list.map((item, idx) => (
                  <NotificationRow
                    key={item.id}
                    item={item}
                    isLast={idx === list.length - 1}
                    expanded={expandedId === item.id}
                    onToggle={handleToggle}
                    onJump={handleJump}
                  />
                ))}
              </div>

              {totalPages > 1 && (
                <div style={styles.pagination}>
                  <button
                    style={{
                      ...styles.pageBtn,
                      ...(page <= 1 ? styles.pageBtnDisabled : {}),
                    }}
                    onClick={() => goPage(page - 1)}
                    disabled={page <= 1}
                    aria-label="上一页"
                  >
                    <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                      <polyline points="15 18 9 12 15 6" />
                    </svg>
                  </button>
                  <span>第 {page} / {totalPages} 页</span>
                  <button
                    style={{
                      ...styles.pageBtn,
                      ...(page >= totalPages ? styles.pageBtnDisabled : {}),
                    }}
                    onClick={() => goPage(page + 1)}
                    disabled={page >= totalPages}
                    aria-label="下一页"
                  >
                    <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                      <polyline points="9 18 15 12 9 6" />
                    </svg>
                  </button>
                </div>
              )}
            </>
          )}
        </div>
      </main>
    </div>
  );
}
