import { useCallback, useEffect, useMemo, useState } from 'react';
import { createPortal } from 'react-dom';
import { Eye, RefreshCw, Trash2 } from 'lucide-react';
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
import rehypeRaw from 'rehype-raw';
import rehypeSanitize from 'rehype-sanitize';
import { LucentIconButton } from '../../../components/lucent/LucentIconButton';
import { LucentSelect } from '../../../components/lucent/LucentSelect';
import { PreviewModalShell } from '../../../shared/ui/PreviewModalShell';
import {
  createWorkspaceMarkdownComponents,
  decorateWorkspacePathsForMarkdown,
  resolveWorkspaceDocumentPath,
} from '../../../shared/workspace/workspaceMarkdown';
import './TopicFeedPanel.css';

export interface TopicFeedItem {
  id: number;
  bot_id: string;
  topic_key: string;
  title: string;
  content: string;
  level: string;
  tags: string[];
  view: Record<string, unknown>;
  source: string;
  dedupe_key: string;
  is_read: boolean;
  created_at?: string;
}

export interface TopicFeedOption {
  key: string;
  label: string;
}

interface TopicFeedPanelProps {
  isZh: boolean;
  topicKey: string;
  topicOptions: TopicFeedOption[];
  topicState?: 'none' | 'inactive' | 'ready';
  items: TopicFeedItem[];
  loading: boolean;
  loadingMore: boolean;
  nextCursor: number | null;
  error: string;
  readSavingById: Record<number, boolean>;
  deleteSavingById: Record<number, boolean>;
  onTopicChange: (value: string) => void;
  onRefresh: () => void;
  onMarkRead: (itemId: number) => void;
  onDeleteItem: (item: TopicFeedItem) => void;
  onLoadMore: () => void;
  onOpenWorkspacePath: (path: string) => void;
  resolveWorkspaceMediaSrc?: (src: string, baseFilePath?: string) => string;
  onOpenTopicSettings?: () => void;
  onDetailOpenChange?: (open: boolean) => void;
  layout?: 'compact' | 'panel';
}

interface TopicSummaryCard {
  title: string;
  summary: string;
  highlights: string[];
  snippet: string;
}

interface TopicDetailState {
  itemId: number;
  fallbackTitle: string;
  fallbackContent: string;
}

function formatTopicItemTime(raw: string | undefined, isZh: boolean): string {
  const text = String(raw || '').trim();
  if (!text) return '-';
  const dt = new Date(text);
  if (Number.isNaN(dt.getTime())) return '-';
  try {
    return dt.toLocaleString(isZh ? 'zh-CN' : 'en-US', {
      month: '2-digit',
      day: '2-digit',
      hour: '2-digit',
      minute: '2-digit',
      hour12: false,
    });
  } catch {
    return dt.toLocaleString();
  }
}

function cleanTopicLine(raw: unknown): string {
  const text = String(raw || '').trim();
  if (!text) return '';
  if (/^\|.*\|$/.test(text)) return '';
  if (/^[-=:_`~]{3,}$/.test(text)) return '';
  return text.replace(/^\s{0,3}(?:[#>*-]+|\d+[.)])\s*/, '').trim();
}

function deriveTopicSummaryCard(item: TopicFeedItem): TopicSummaryCard {
  const view = item.view && typeof item.view === 'object' ? item.view : {};
  const titleFromView = String(view.title || '').trim();
  const summaryFromView = String(view.summary || '').trim();
  const snippetFromView = String(view.snippet || '').trim();
  const highlightsFromView = Array.isArray(view.highlights)
    ? view.highlights.map((row) => String(row || '').trim()).filter(Boolean)
    : [];

  const lines = String(item.content || '')
    .split('\n')
    .map(cleanTopicLine)
    .filter(Boolean);
  const title = titleFromView || String(item.title || '').trim() || lines[0] || item.topic_key || 'Topic';
  const summaryCandidates = lines.filter((line) => line !== title);
  const summary = summaryFromView || summaryCandidates.slice(0, 2).join(' ').slice(0, 220).trim() || title;

  const fallbackHighlights = String(item.content || '')
    .split('\n')
    .map((line) => ({ raw: String(line || '').trim(), cleaned: cleanTopicLine(line) }))
    .filter((row) => row.cleaned)
    .filter((row) => row.raw.startsWith('-') || row.raw.startsWith('*') || row.cleaned.includes(':') || row.cleaned.includes('：'))
    .map((row) => row.cleaned.slice(0, 120))
    .filter((row, idx, arr) => arr.indexOf(row) === idx)
    .slice(0, 3);
  const snippetCandidates = summaryCandidates
    .filter((line) => line !== summary)
    .filter((line) => !fallbackHighlights.includes(line))
    .slice(0, 2);
  const snippet = snippetFromView || snippetCandidates.join(' ').slice(0, 180).trim();

  return {
    title,
    summary,
    highlights: highlightsFromView.length > 0 ? highlightsFromView.slice(0, 3) : fallbackHighlights,
    snippet,
  };
}

export function TopicFeedPanel({
  isZh,
  topicKey,
  topicOptions,
  topicState = 'ready',
  items,
  loading,
  loadingMore,
  nextCursor,
  error,
  readSavingById,
  deleteSavingById,
  onTopicChange,
  onRefresh,
  onMarkRead,
  onDeleteItem,
  onLoadMore,
  onOpenWorkspacePath,
  resolveWorkspaceMediaSrc,
  onOpenTopicSettings,
  onDetailOpenChange,
  layout = 'compact',
}: TopicFeedPanelProps) {
  const [detailState, setDetailState] = useState<TopicDetailState | null>(null);
  const closeDetail = useCallback(() => setDetailState(null), []);
  const detailItem = useMemo(
    () => (detailState ? items.find((item) => Number(item.id || 0) === detailState.itemId) || null : null),
    [detailState, items],
  );
  const detailTitle = detailItem
    ? String(detailItem.title || detailItem.topic_key || detailState?.fallbackTitle || '').trim()
    : String(detailState?.fallbackTitle || '').trim();
  const detailContent = detailItem
    ? String(detailItem.content || detailState?.fallbackContent || '').trim()
    : String(detailState?.fallbackContent || '').trim();
  const detailBaseFilePath = useMemo(() => {
    if (!detailItem) return '';
    const view = detailItem.view && typeof detailItem.view === 'object' ? detailItem.view as Record<string, unknown> : {};
    const candidates = [
      view.path,
      view.file_path,
      view.source_path,
      view.workspace_path,
      detailItem.source,
    ];
    for (const candidate of candidates) {
      const raw = String(candidate || '').trim();
      const resolved = resolveWorkspaceDocumentPath(raw);
      if (resolved) return resolved;
    }
    return '';
  }, [detailItem]);
  const markdownComponents = useMemo(
    () => createWorkspaceMarkdownComponents((path) => onOpenWorkspacePath(path), {
      baseFilePath: detailBaseFilePath || undefined,
      resolveMediaSrc: resolveWorkspaceMediaSrc,
    }),
    [detailBaseFilePath, onOpenWorkspacePath, resolveWorkspaceMediaSrc],
  );
  const portalTarget = useMemo(() => {
    if (typeof document === 'undefined') return null;
    return document.querySelector('.app-shell[data-theme]') || document.body;
  }, []);

  useEffect(() => {
    if (!detailState) return;
    const onKeyDown = (event: KeyboardEvent) => {
      if (event.key === 'Escape') {
        closeDetail();
      }
    };
    window.addEventListener('keydown', onKeyDown);
    return () => window.removeEventListener('keydown', onKeyDown);
  }, [closeDetail, detailState]);

  useEffect(() => {
    onDetailOpenChange?.(Boolean(detailState));
  }, [detailState, onDetailOpenChange]);

  return (
    <div className={`ops-topic-feed ${layout === 'panel' ? 'is-panel' : ''}`}>
      {topicState === 'ready' ? (
        <div className="ops-topic-feed-toolbar">
          <LucentSelect value={topicKey || '__all__'} onChange={(e) => onTopicChange(String(e.target.value || '__all__'))}>
            <option value="__all__">{isZh ? '全部主题' : 'All Topics'}</option>
            {topicOptions.map((row) => (
              <option key={row.key} value={row.key}>
                {row.label}
              </option>
            ))}
          </LucentSelect>
          <LucentIconButton
            className="btn btn-secondary btn-sm icon-btn"
            disabled={loading || loadingMore}
            onClick={onRefresh}
            tooltip={isZh ? '刷新主题消息' : 'Refresh Topic feed'}
            aria-label={isZh ? '刷新主题消息' : 'Refresh Topic feed'}
          >
            <RefreshCw size={14} className={loading ? 'animate-spin' : ''} />
          </LucentIconButton>
        </div>
      ) : null}
      {error ? <div className="ops-empty-inline">{error}</div> : null}
      <div className={`ops-topic-feed-list ${layout === 'panel' ? 'is-panel' : ''}`}>
        {topicState === 'none' ? (
          <div className="ops-topic-feed-empty-state">
            <div className="ops-topic-feed-empty-title">{isZh ? '还没有配置主题' : 'No topics configured'}</div>
            <div className="ops-topic-feed-empty-desc">
              {isZh ? '请先到主题设置中新增至少一个主题，Bot 的消息才能被路由到这里。' : 'Create at least one topic in settings before feed messages can appear here.'}
            </div>
            {onOpenTopicSettings ? (
              <button className="btn btn-secondary btn-sm" onClick={onOpenTopicSettings}>
                {isZh ? '打开主题设置' : 'Open Topic settings'}
              </button>
            ) : null}
          </div>
        ) : topicState === 'inactive' ? (
          <div className="ops-topic-feed-empty-state">
            <div className="ops-topic-feed-empty-title">{isZh ? '没有启用中的主题' : 'No active topics'}</div>
            <div className="ops-topic-feed-empty-desc">
              {isZh ? '你已经配置了主题，但当前都处于关闭状态。启用一个主题后，这里才会开始接收消息。' : 'Topics exist, but all of them are disabled. Enable one to start receiving feed items here.'}
            </div>
            {onOpenTopicSettings ? (
              <button className="btn btn-secondary btn-sm" onClick={onOpenTopicSettings}>
                {isZh ? '打开主题设置' : 'Open Topic settings'}
              </button>
            ) : null}
          </div>
        ) : loading ? (
          <div className="ops-empty-inline">{isZh ? '读取主题消息中...' : 'Loading topic feed...'}</div>
        ) : items.length === 0 ? (
          <div className="ops-empty-inline">{isZh ? '暂无主题消息。' : 'No topic messages.'}</div>
        ) : (
          items.map((item) => {
            const itemId = Number(item.id || 0);
            const level = String(item.level || 'info').trim().toLowerCase();
            const levelText = level === 'warn' ? 'WARN' : level === 'error' ? 'ERROR' : level === 'success' ? 'SUCCESS' : 'INFO';
            const unread = !item.is_read;
            const card = deriveTopicSummaryCard(item);
            const rawContent = String(item.content || '').trim();
            return (
              <article key={`topic-item-${itemId}`} className={`ops-topic-feed-item ${unread ? 'unread' : ''}`}>
                <div className="ops-topic-feed-item-head">
                  <div className="ops-topic-feed-meta">
                    <span className={`ops-topic-feed-level ${level}`}>{levelText}</span>
                    <span className="ops-topic-feed-topic-chip mono">{item.topic_key || '-'}</span>
                    {unread ? <span className="ops-topic-feed-unread-dot" aria-label={isZh ? '未读' : 'Unread'} /> : null}
                  </div>
                  <div className="ops-topic-feed-meta-right">
                    <span className="ops-topic-feed-source-chip">{item.source || 'mcp'}</span>
                    <span className="ops-topic-feed-time">{formatTopicItemTime(item.created_at, isZh)}</span>
                  </div>
                </div>
                <div className="ops-topic-card-shell">
                  <div className="ops-topic-card-title">{card.title}</div>
                  <div className="ops-topic-card-summary">{card.summary}</div>
                  {card.highlights.length > 0 ? (
                    <div className="ops-topic-card-highlights">
                      {card.highlights.map((line) => (
                        <div key={`${itemId}-${line}`} className="ops-topic-card-highlight">
                          <span className="ops-topic-card-bullet" />
                          <span>{line}</span>
                        </div>
                      ))}
                    </div>
                  ) : null}
                  {card.snippet ? <div className="ops-topic-card-snippet">{card.snippet}</div> : null}
                  {rawContent ? null : null}
                </div>
                {(item.tags || []).length > 0 ? (
                  <div className="ops-topic-feed-tags">
                    {(item.tags || []).map((tag) => (
                      <span key={`${itemId}-${tag}`} className="ops-topic-feed-tag mono">
                        {tag}
                      </span>
                    ))}
                  </div>
                ) : null}
                <div className="ops-topic-feed-item-foot">
                  <span className={`ops-topic-read-state ${unread ? 'is-unread' : 'is-read'}`}>
                    {unread ? (isZh ? '新消息' : 'New') : (isZh ? '已读' : 'Read')}
                  </span>
                  <div className="ops-topic-feed-item-actions">
                    {rawContent ? (
                      <LucentIconButton
                        className="btn btn-secondary btn-sm icon-btn"
                        onClick={() => setDetailState({ itemId, fallbackTitle: card.title, fallbackContent: rawContent })}
                        tooltip={isZh ? '查看详情' : 'View details'}
                        aria-label={isZh ? '查看详情' : 'View details'}
                      >
                        <Eye size={14} />
                      </LucentIconButton>
                    ) : null}
                    <LucentIconButton
                      className="btn btn-secondary btn-sm icon-btn"
                      disabled={Boolean(deleteSavingById[itemId])}
                      onClick={() => onDeleteItem(item)}
                      tooltip={isZh ? '删除消息' : 'Delete item'}
                      aria-label={isZh ? '删除消息' : 'Delete item'}
                    >
                      {deleteSavingById[itemId] ? <RefreshCw size={14} className="animate-spin" /> : <Trash2 size={14} />}
                    </LucentIconButton>
                    {unread ? (
                      <button
                        className="btn btn-secondary btn-sm"
                        disabled={Boolean(readSavingById[itemId])}
                        onClick={() => onMarkRead(itemId)}
                      >
                        {readSavingById[itemId] ? (isZh ? '处理中...' : 'Saving...') : (isZh ? '标记已读' : 'Mark read')}
                      </button>
                    ) : null}
                  </div>
                </div>
              </article>
            );
          })
        )}
      </div>
      {detailState && portalTarget
        ? createPortal(
            <PreviewModalShell
              closeLabel={isZh ? '关闭详情' : 'Close detail'}
              onClose={closeDetail}
              subtitle={detailTitle || (isZh ? '原文详情' : 'Raw detail')}
              title={isZh ? '主题详情' : 'Topic detail'}
            >
                <div className="workspace-preview-body markdown">
                  <div className="workspace-markdown">
                    <ReactMarkdown
                      remarkPlugins={[remarkGfm]}
                      rehypePlugins={[rehypeRaw, rehypeSanitize]}
                      components={markdownComponents}
                    >
                      {decorateWorkspacePathsForMarkdown(detailContent)}
                    </ReactMarkdown>
                  </div>
                </div>
            </PreviewModalShell>,
            portalTarget,
          )
        : null}
      {topicState === 'ready' && (items.length > 0 || nextCursor) ? (
        <div className="row-between">
          <span className="field-label">
            {items.length > 0 ? (isZh ? `共 ${items.length} 条` : `${items.length} items`) : ''}
          </span>
          {nextCursor ? (
            <button className="btn btn-secondary btn-sm" disabled={loadingMore} onClick={onLoadMore}>
              {loadingMore ? (isZh ? '加载中...' : 'Loading...') : (isZh ? '加载更多' : 'Load more')}
            </button>
          ) : (
            <span />
          )}
        </div>
      ) : null}
    </div>
  );
}
