import { useCoreServices } from '@learnitive/context';
import { projectFilePath } from '@learnitive/project-storage';
import { Button, toast } from '@learnitive/ui-components';
import { WsPath } from '@learnitive/ws-path';
import { useAtomValue } from 'jotai';
import { Check, ChevronDown, ChevronRight, ChevronUp, GitCompareArrows, MessageSquarePlus, RotateCcw, Trash2, X, XCircle } from 'lucide-react';
import React from 'react';
import type { ReviewCommentTarget } from './review-comment-dialog';
import { requestPageConfirm } from './page-modal-service';
import { ReviewHistoryPanel } from './review-history-panel';
import { requestProjectEditorReveal } from '../project-compile-ui';


const ReviewMathPreview = React.lazy(async () => {
  const module = await import('./mathlive-equation-editor');
  return { default: module.MathLivePreview };
});

function reviewMathValue(source: string): string | undefined {
  let value = source.trim();
  if (!value) return undefined;
  value = value
    .replace(/^\\begin\{(?:equation\*?|align\*?|gather\*?|multline\*?|displaymath)\}\s*/u, '')
    .replace(/\s*\\end\{(?:equation\*?|align\*?|gather\*?|multline\*?|displaymath)\}$/u, '')
    .replace(/^\\\[\s*/u, '')
    .replace(/\s*\\\]$/u, '')
    .replace(/^\$\$\s*/u, '')
    .replace(/\s*\$\$$/u, '')
    .replace(/^\$\s*/u, '')
    .replace(/\s*\$$/u, '')
    .trim();
  return value && !/\\begin\{|\\end\{/u.test(value) ? value : undefined;
}

function sourceLine(source: string, offset: number): number {
  return source.slice(0, Math.max(0, Math.min(offset, source.length))).split('\n').length;
}

export function ReviewSidebar({
  wsName,
  currentFile,
  activeThreadId,
  onActiveThreadChange,
  onClose,
  onRequestComment,
  onAcceptedChange,
}: {
  wsName: string;
  currentFile?: string;
  activeThreadId?: string;
  onActiveThreadChange: (id: string | undefined) => void;
  onClose: () => void;
  onRequestComment: (target: ReviewCommentTarget) => void;
  onAcceptedChange?: () => void;
}) {
  const { projectReview, projectCollaboration, latexSource, navigation, projectStorage } = useCoreServices();
  const version = useAtomValue(projectReview.$version);
  const collaborationState = useAtomValue(projectCollaboration.$state);
  const collaborativeReview = collaborationState.active && collaborationState.wsName === wsName;
  const [panelMode, setPanelMode] = React.useState<'review' | 'history'>('review');
  const [status, setStatus] = React.useState<'open' | 'resolved' | 'all'>('open');
  const [kindFilter, setKindFilter] = React.useState<'all' | 'comments' | 'changes'>('all');
  const [scope, setScope] = React.useState<'project' | 'file'>('project');
  const [mine, setMine] = React.useState(false);
  const [outdated, setOutdated] = React.useState(false);
  const [replyId, setReplyId] = React.useState<string>();
  const [replyBody, setReplyBody] = React.useState('');
  const [editingId, setEditingId] = React.useState<string>();
  const [editingBody, setEditingBody] = React.useState('');
  const [selectedChangeIds, setSelectedChangeIds] = React.useState<Set<string>>(new Set());
  const author = projectReview.getLocalAuthor(wsName);
  const [authorName, setAuthorName] = React.useState(author.displayName);

  React.useEffect(() => {
    void projectReview.refresh(wsName).catch((reason) => toast.error(reason instanceof Error ? reason.message : 'Unable to load review comments.'));
  }, [collaborationState.active, collaborationState.roomId, projectReview, wsName]);

  React.useEffect(() => {
    setAuthorName(projectReview.getLocalAuthor(wsName).displayName);
  }, [collaborationState.userName, projectReview, version, wsName]);

  React.useEffect(() => {
    if (!activeThreadId) return;
    const thread = projectReview.getThread(wsName, activeThreadId);
    if (!thread) return;
    // A programmatically focused suggestion (including AI Suggest) must be
    // visible even if Review was previously left on History or a narrow filter.
    setPanelMode('review');
    setStatus(thread.status === 'resolved' ? 'resolved' : 'open');
    setKindFilter('all');
    setScope('project');
    setMine(false);
    setOutdated(thread.status === 'outdated');
  }, [activeThreadId, projectReview, wsName]);

  const reviewThreads = projectReview.getThreads(wsName, {
    status,
    ...(scope === 'file' && currentFile ? { file: currentFile } : {}),
    ...(mine ? { mine: true } : {}),
    ...(outdated ? { outdated: true } : {}),
  });
  const commentCount = reviewThreads.filter((thread) => thread.kind === 'comment').length;
  const changeCount = reviewThreads.filter((thread) => Boolean(thread.change)).length;
  const threads = reviewThreads.filter((thread) => kindFilter === 'all' || (kindFilter === 'comments' ? thread.kind === 'comment' : Boolean(thread.change)));

  const pendingChanges = projectReview.getChanges(wsName, {
    status: 'pending',
    ...(scope === 'file' && currentFile ? { file: currentFile } : {}),
  });

  void version;


  const runBulk = async (action: 'accept' | 'reject', ids: readonly string[], projectWide = false) => {
    if (!ids.length) return;
    if (projectWide && !(await requestPageConfirm({ title: `${action === 'accept' ? 'Accept' : 'Reject'} tracked changes?`, description: `${action === 'accept' ? 'Accept' : 'Reject'} ${ids.length} tracked changes across the project?`, confirmText: action === 'accept' ? 'Accept changes' : 'Reject changes', tone: action === 'reject' ? 'destructive' : 'default' }))) return;
    try {
      if (action === 'accept') {
        await projectReview.acceptChanges(wsName, ids);
        onAcceptedChange?.();
      } else await projectReview.rejectChanges(wsName, ids);
      setSelectedChangeIds(new Set());
    } catch (reason) {
      toast.error(reason instanceof Error ? reason.message : 'Unable to update tracked changes.');
    }
  };



  const openSource = async (id: string) => {
    const thread = projectReview.getThread(wsName, id);
    if (!thread?.anchor) return;
    const wsPath = WsPath.fromParts(wsName, thread.anchor.filePath).wsPath;
    const loaded = latexSource.getSnapshot(wsPath);
    let source = loaded?.text;
    if (source === undefined) {
      const provider = await projectStorage.getProvider(wsName);
      const bytes = await provider.readFile(projectFilePath(thread.anchor.filePath));
      source = bytes ? new TextDecoder('utf-8', { fatal: false }).decode(bytes) : undefined;
    }
    if (source === undefined) return;
    const recovered = await projectReview.recoverThread(wsName, thread);
    if (!recovered.anchor || recovered.status === 'outdated') {
      toast.error('This comment is outdated and cannot be reattached safely.');
      return;
    }
    const projected = projectReview.getTrackChangesEnabled(wsName)
      ? projectReview.getProjectedSource(wsName, recovered.anchor.filePath, source)
      : source;
    const projectedDecoration = projectReview
      .getEditorDecorations(wsName, recovered.anchor.filePath, source)
      .find((item) => item.id === id);
    const line = sourceLine(projected, projectedDecoration?.from ?? recovered.anchor.from);
    const isLatexSource = /\.(?:tex|ltx|bib)$/iu.test(recovered.anchor.filePath);
    if (isLatexSource) {
      latexSource.requestSelect(wsPath, line, 1);
      navigation.goWsPath(wsPath);
    } else {
      navigation.goWsPath(wsPath);
      requestProjectEditorReveal(wsPath, line, 1);
    }
    onActiveThreadChange(id);
  };

  const navigateReview = (direction: -1 | 1) => {
    if (!threads.length) return;
    const current = activeThreadId ? threads.findIndex((thread) => thread.id === activeThreadId) : -1;
    const nextIndex = current < 0
      ? (direction > 0 ? 0 : threads.length - 1)
      : (current + direction + threads.length) % threads.length;
    const next = threads[nextIndex];
    if (next) void openSource(next.id);
  };

  const deleteComment = async (id: string) => {
    try {
      await projectReview.deleteOwnComment(wsName, id);
      if (activeThreadId === id) onActiveThreadChange(undefined);
      if (replyId === id) { setReplyId(undefined); setReplyBody(''); }
      if (editingId === id) setEditingId(undefined);
    } catch (reason) {
      toast.error(reason instanceof Error ? reason.message : 'Unable to delete comment.');
    }
  };

  return (
    <aside className="flex w-[21rem] min-w-[18rem] max-w-[38vw] shrink-0 flex-col border-l bg-background max-lg:absolute max-lg:inset-y-0 max-lg:right-0 max-lg:z-50 max-lg:w-[min(92vw,21rem)] max-lg:max-w-none max-lg:shadow-xl" data-testid="review-sidebar" aria-label="Review comments">
      <div className="flex items-center gap-2 border-b px-3 py-2">
        <strong className="text-sm">Review</strong>
        <span className="rounded bg-muted px-1.5 py-0.5 text-[11px]">{panelMode === 'review' ? threads.length : projectReview.getActivity(wsName).length}</span>
        <Button className="ml-auto" size="icon" variant="ghost" aria-label="Previous review item" disabled={panelMode === 'history' || !threads.length} onClick={() => navigateReview(-1)}><ChevronUp className="size-4" /></Button>
        <Button size="icon" variant="ghost" aria-label="Next review item" disabled={panelMode === 'history' || !threads.length} onClick={() => navigateReview(1)}><ChevronDown className="size-4" /></Button>
        <Button size="icon" variant="ghost" aria-label="Close review" onClick={onClose}><X className="size-4" /></Button>
      </div>
      <div className="flex gap-1 border-b p-2" role="tablist" aria-label="Review panels">
        <Button size="sm" variant={panelMode === 'review' ? 'secondary' : 'ghost'} role="tab" aria-selected={panelMode === 'review'} onClick={() => setPanelMode('review')}>Review</Button>
        <Button size="sm" variant={panelMode === 'history' ? 'secondary' : 'ghost'} role="tab" aria-selected={panelMode === 'history'} onClick={() => setPanelMode('history')}>History</Button>
      </div>
      <p className="border-b px-3 py-1.5 text-[11px] text-muted-foreground" data-testid="review-storage-note">
        {collaborativeReview
          ? 'Review metadata is shared live with collaborators and remains separate from project source.'
          : /\.(?:tex|ltx|bib)$/i.test(currentFile ?? '')
            ? 'Review metadata is stored separately from LaTeX and does not modify canonical source until a change is accepted.'
            : 'Review metadata is stored separately from project source and does not modify canonical code until a change is accepted.'}
      </p>
      {panelMode === 'history' ? (
        <ReviewHistoryPanel wsName={wsName} currentFile={currentFile} onOpenThread={(id) => void openSource(id)} />
      ) : (<>
      <div className="space-y-2 border-b p-2 text-xs">
        <div className="flex gap-1" role="group" aria-label="Review status">
          {(['open', 'resolved', 'all'] as const).map((item) => <Button key={item} size="sm" variant={status === item ? 'secondary' : 'ghost'} onClick={() => setStatus(item)}>{item[0]!.toUpperCase() + item.slice(1)}</Button>)}
        </div>
        <div className="flex flex-wrap gap-1" role="group" aria-label="Review item type">
          <Button size="sm" variant={kindFilter === 'all' ? 'secondary' : 'ghost'} onClick={() => setKindFilter('all')}>All {reviewThreads.length}</Button>
          <Button size="sm" variant={kindFilter === 'comments' ? 'secondary' : 'ghost'} onClick={() => setKindFilter('comments')}>Comments {commentCount}</Button>
          <Button size="sm" variant={kindFilter === 'changes' ? 'secondary' : 'ghost'} onClick={() => setKindFilter('changes')}>Changes {changeCount}</Button>
        </div>
        <div className="flex flex-wrap items-center gap-2">
          <label className="flex items-center gap-1"><input type="checkbox" checked={scope === 'file'} onChange={(event) => setScope(event.currentTarget.checked ? 'file' : 'project')} />Current file</label>
          <label className="flex items-center gap-1"><input type="checkbox" checked={mine} onChange={(event) => setMine(event.currentTarget.checked)} />Mine</label>
          <label className="flex items-center gap-1"><input type="checkbox" checked={outdated} onChange={(event) => setOutdated(event.currentTarget.checked)} />Outdated</label>
        </div>
        <label className="flex items-center gap-2">
          <span className="text-muted-foreground">{collaborativeReview ? 'Collaboration name' : 'Display name'}</span>
          <input
            className="min-w-0 flex-1 rounded border bg-background px-2 py-1 disabled:opacity-70"
            value={authorName}
            disabled={collaborativeReview}
            title={collaborativeReview ? 'Uses your live collaboration identity' : undefined}
            onChange={(event) => setAuthorName(event.currentTarget.value)}
            onBlur={() => { if (!collaborativeReview) projectReview.setLocalDisplayName(authorName); }}
            aria-label="Review display name"
          />
        </label>
        <div className="flex gap-1">
          <Button size="sm" variant="outline" onClick={() => onRequestComment({ scope: 'project' })}><MessageSquarePlus className="mr-1 size-3.5" />Project comment</Button>
          {currentFile && <Button size="sm" variant="outline" onClick={() => onRequestComment({ scope: 'document', anchor: { filePath: currentFile, from: 0, to: 0 } })}>Document comment</Button>}
        </div>
        {pendingChanges.length > 0 && (
          <div className="rounded border bg-muted/25 p-2" data-testid="review-bulk-actions">
            <div className="mb-1 flex items-center gap-1 font-medium"><GitCompareArrows className="size-3.5" />{pendingChanges.length} pending change{pendingChanges.length === 1 ? '' : 's'}</div>
            <div className="flex flex-wrap gap-1">
              <Button size="sm" variant="outline" disabled={!selectedChangeIds.size} onClick={() => void runBulk('accept', [...selectedChangeIds])}>Accept selected</Button>
              <Button size="sm" variant="outline" disabled={!selectedChangeIds.size} onClick={() => void runBulk('reject', [...selectedChangeIds])}>Reject selected</Button>
              {currentFile && <Button size="sm" variant="ghost" onClick={() => void runBulk('accept', projectReview.getChanges(wsName, { status: 'pending', file: currentFile }).map((change) => change.id))}>Accept all in file</Button>}
              {currentFile && <Button size="sm" variant="ghost" onClick={() => void runBulk('reject', projectReview.getChanges(wsName, { status: 'pending', file: currentFile }).map((change) => change.id))}>Reject all in file</Button>}
              {scope === 'project' && <Button size="sm" variant="ghost" onClick={() => void runBulk('accept', pendingChanges.map((change) => change.id), true)}>Accept project</Button>}
              {scope === 'project' && <Button size="sm" variant="ghost" onClick={() => void runBulk('reject', pendingChanges.map((change) => change.id), true)}>Reject project</Button>}
            </div>
          </div>
        )}
      </div>
      <div className="min-h-0 flex-1 space-y-2 overflow-auto p-2">
        {threads.length === 0 && <p className="p-3 text-sm text-muted-foreground">No comments match these filters.</p>}
        {threads.map((thread) => {
          const selected = thread.id === activeThreadId;
          const own = thread.author.id === author.id;
          return (
            <article key={thread.id} className={`rounded-md border p-2 text-sm ${selected ? 'ring-2 ring-primary/35' : ''}`} data-review-thread={thread.id}>
              <div className="flex items-start gap-2">
                {thread.change?.status === 'pending' && (
                  <input
                    type="checkbox"
                    className="mt-1"
                    aria-label={`Select tracked change ${thread.id}`}
                    checked={selectedChangeIds.has(thread.id)}
                    onChange={(event) => { const checked=event.currentTarget.checked; setSelectedChangeIds((current) => { const next = new Set(current); if (checked) next.add(thread.id); else next.delete(thread.id); return next; }); }}
                  />
                )}
                <button type="button" className="flex min-w-0 flex-1 items-start gap-2 text-left" onClick={() => { onActiveThreadChange(thread.id); void openSource(thread.id); }}>
                  <ChevronRight className="mt-0.5 size-3.5 shrink-0 text-muted-foreground" />
                  <span className="min-w-0 flex-1">
                    <span className="flex flex-wrap items-center gap-1 text-xs text-muted-foreground"><b className="text-foreground">{thread.author.displayName}</b>{thread.author.kind === 'ai' && <span className="rounded bg-muted px-1">AI suggestion</span>}{thread.change?.metadata?.category && <span className="rounded bg-muted px-1">{thread.change.metadata.category}</span>}{thread.change && <span className="rounded bg-muted px-1">{thread.change.type}</span>}<span>·</span><span>{new Date(thread.createdAt).toLocaleString()}</span>{thread.change ? <span className="rounded bg-muted px-1">{thread.change.status}</span> : thread.status !== 'open' && <span className="rounded bg-muted px-1">{thread.status}</span>}</span>
                    {thread.anchor && <span className="mt-0.5 block truncate text-[11px] text-muted-foreground">{thread.anchor.filePath}{thread.anchor.selectedText ? ` · “${thread.anchor.selectedText.replace(/\s+/gu, ' ').slice(0, 90)}”` : ''}</span>}
                  </span>
                </button>
              </div>
              {thread.change ? (
                <div className="mt-2 space-y-1.5" data-testid={`review-change-${thread.change.type}`}>
                  <p className="text-xs font-medium text-muted-foreground">{thread.change.presentation === 'source-only' ? 'Source-only change' : thread.change.semanticOperation ?? (thread.change.presentation === 'semantic' ? 'Semantic change' : 'Tracked source change')}</p>
                  {thread.change.presentation === 'semantic' && /math|equation/u.test(thread.change.anchor.semanticKind ?? '') && (reviewMathValue(thread.change.originalText) || reviewMathValue(thread.change.proposedText)) && (
                    <div className="grid gap-1 rounded border bg-muted/15 p-2" data-testid="review-equation-change">
                      {reviewMathValue(thread.change.originalText) && <div><span className="text-[10px] font-medium uppercase text-destructive">Old rendered equation</span><div className="mt-1 pointer-events-none"><React.Suspense fallback={<code className="text-xs">{reviewMathValue(thread.change.originalText)}</code>}><ReviewMathPreview value={reviewMathValue(thread.change.originalText)!} onEdit={() => undefined} /></React.Suspense></div></div>}
                      {reviewMathValue(thread.change.proposedText) && <div><span className="text-[10px] font-medium uppercase text-emerald-700 dark:text-emerald-400">New rendered equation</span><div className="mt-1 pointer-events-none"><React.Suspense fallback={<code className="text-xs">{reviewMathValue(thread.change.proposedText)}</code>}><ReviewMathPreview value={reviewMathValue(thread.change.proposedText)!} onEdit={() => undefined} /></React.Suspense></div></div>}
                    </div>
                  )}
                  {thread.change.originalText && <div><span className="text-[10px] font-medium uppercase text-destructive">Original source</span><pre className="mt-0.5 max-h-32 overflow-auto whitespace-pre-wrap rounded bg-destructive/5 p-1.5 text-xs line-through">{thread.change.originalText}</pre></div>}
                  {thread.change.proposedText && <div><span className="text-[10px] font-medium uppercase text-emerald-700 dark:text-emerald-400">Proposed source</span><pre className="mt-0.5 max-h-32 overflow-auto whitespace-pre-wrap rounded bg-emerald-500/5 p-1.5 text-xs">{thread.change.proposedText}</pre></div>}
                  {thread.change.metadata?.reason && <p className="rounded border bg-muted/20 p-2 text-xs text-muted-foreground">{thread.change.metadata.reason}</p>}
                  {thread.author.kind === 'ai' && (thread.change.metadata?.provider || thread.change.metadata?.model) && <p className="text-[11px] text-muted-foreground">{thread.change.metadata?.provider ?? 'AI'}{thread.change.metadata?.model ? ` · ${thread.change.metadata.model}` : ''}{thread.change.metadata?.confidence !== undefined ? ` · ${Math.round(thread.change.metadata.confidence * 100)}% confidence` : ''}</p>}
                  {thread.change.status === 'conflicted' && (
                    <p className="rounded border border-amber-300 bg-amber-50 p-2 text-xs text-amber-900 dark:border-amber-700 dark:bg-amber-950/30 dark:text-amber-200">
                      This tracked change overlaps with newer edits and needs manual review.
                    </p>
                  )}
                </div>
              ) : editingId === thread.id ? (
                <div className="mt-2 space-y-1"><textarea className="min-h-20 w-full rounded border bg-background p-2 text-sm" value={editingBody} onChange={(event) => setEditingBody(event.currentTarget.value)} /><div className="flex gap-1"><Button size="sm" onClick={() => void projectReview.editOwnComment(wsName, thread.id, editingBody).then(() => setEditingId(undefined)).catch((reason) => toast.error(reason.message))}>Save</Button><Button size="sm" variant="ghost" onClick={() => setEditingId(undefined)}>Cancel</Button></div></div>
              ) : <p className="mt-2 whitespace-pre-wrap">{thread.body}</p>}
              {thread.replies.map((reply) => <div key={reply.id} className="mt-2 border-l-2 pl-2 text-xs"><b>{reply.author.displayName}</b><p className="mt-0.5 whitespace-pre-wrap">{reply.body}</p></div>)}
              {replyId === thread.id && <div className="mt-2 space-y-1"><textarea className="min-h-16 w-full rounded border bg-background p-2 text-xs" placeholder="Reply…" value={replyBody} onChange={(event) => setReplyBody(event.currentTarget.value)} /><div className="flex gap-1"><Button size="sm" onClick={() => void projectReview.reply(wsName, thread.id, replyBody).then(() => { setReplyBody(''); setReplyId(undefined); })}>Reply</Button><Button size="sm" variant="ghost" onClick={() => setReplyId(undefined)}>Cancel</Button></div></div>}
              <div className="mt-2 flex flex-wrap gap-1">
                {thread.change?.status === 'conflicted' ? (
                  <>
                    <Button size="sm" variant="outline" onClick={() => void projectReview.resolveConflictKeepCurrent(wsName, thread.id).catch((reason) => toast.error(reason instanceof Error ? reason.message : 'Unable to keep current text.'))}>Keep current text</Button>
                    {thread.change.metadata?.applicationMode !== 'deferred' && <Button size="sm" variant="outline" onClick={() => void projectReview.resolveConflictRestoreOriginal(wsName, thread.id).catch((reason) => toast.error(reason instanceof Error ? reason.message : 'Unable to restore original text.'))}>Restore original text</Button>}
                    <Button size="sm" variant="ghost" onClick={() => void projectReview.dismissConflict(wsName, thread.id).catch((reason) => toast.error(reason instanceof Error ? reason.message : 'Unable to dismiss change.'))}>Dismiss change</Button>
                    <Button size="sm" variant="ghost" onClick={() => { setReplyId(thread.id); setReplyBody(''); }}>Comment</Button>
                  </>
                ) : thread.change?.status === 'pending' ? (
                  <>
                    <Button size="sm" variant="outline" onClick={() => void projectReview.acceptReviewChange(wsName, thread.id).then(() => onAcceptedChange?.()).catch((reason) => toast.error(reason instanceof Error ? reason.message : 'Unable to accept change.'))}><Check className="mr-1 size-3" />Accept</Button>
                    <Button size="sm" variant="outline" onClick={() => void projectReview.rejectReviewChange(wsName, thread.id).catch((reason) => toast.error(reason instanceof Error ? reason.message : 'Unable to reject change.'))}><XCircle className="mr-1 size-3" />Reject</Button>
                    <Button size="sm" variant="ghost" onClick={() => { setReplyId(thread.id); setReplyBody(''); }}>Comment</Button>
                    <Button size="sm" variant="ghost" onClick={() => void runBulk('accept', projectReview.getChanges(wsName, { status: 'pending', authorId: thread.author.id }).map((change) => change.id), true)}>Accept all by author</Button>
                    <Button size="sm" variant="ghost" onClick={() => void runBulk('reject', projectReview.getChanges(wsName, { status: 'pending', authorId: thread.author.id }).map((change) => change.id), true)}>Reject all by author</Button>
                  </>
                ) : thread.change ? (
                  <Button size="sm" variant="ghost" onClick={() => { setReplyId(thread.id); setReplyBody(''); }}>Comment</Button>
                ) : (
                  <>
                    <Button size="sm" variant="ghost" onClick={() => { setReplyId(thread.id); setReplyBody(''); }}>Reply</Button>
                    {thread.status === 'resolved' ? <Button size="sm" variant="ghost" onClick={() => void projectReview.reopen(wsName, thread.id)}><RotateCcw className="mr-1 size-3" />Reopen</Button> : <Button size="sm" variant="ghost" disabled={thread.status === 'outdated'} onClick={() => void projectReview.resolve(wsName, thread.id)}>Resolve</Button>}
                    {own && <Button size="sm" variant="ghost" onClick={() => { setEditingId(thread.id); setEditingBody(thread.body); }}>Edit</Button>}
                    {own && <Button size="sm" variant="ghost" className="text-destructive" onClick={() => void deleteComment(thread.id)}><Trash2 className="mr-1 size-3" />Delete</Button>}
                  </>
                )}
              </div>
            </article>
          );
        })}
      </div>
      </>)}
    </aside>
  );
}
