import { useInfiniteQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { useState } from 'react';
import type { TimelineEvent } from '../../../shared/types';
import { fetchTimeline, markAllRead, markRead } from '../api';
import { relativeTime, shortRepo } from '../format';

const GROUP_WINDOW_MS = 10 * 60 * 1000;

interface Group {
  key: string;
  actor: string;
  repo: string;
  prNumber: number;
  prTitle: string;
  events: TimelineEvent[];
}

function groupEvents(events: TimelineEvent[]): Group[] {
  const groups: Group[] = [];
  for (const e of events) {
    const last = groups[groups.length - 1];
    const lastEvent = last?.events[last.events.length - 1];
    if (
      last &&
      lastEvent &&
      last.actor === e.actor &&
      last.repo === e.repo &&
      last.prNumber === e.prNumber &&
      Date.parse(lastEvent.createdAt) - Date.parse(e.createdAt) < GROUP_WINDOW_MS
    ) {
      last.events.push(e);
    } else {
      groups.push({
        key: e.id,
        actor: e.actor,
        repo: e.repo,
        prNumber: e.prNumber,
        prTitle: e.prTitle,
        events: [e],
      });
    }
  }
  return groups;
}

function KindLabel({ event }: { event: TimelineEvent }) {
  if (event.kind === 'review') {
    const cls =
      event.reviewState === 'APPROVED'
        ? 'approved'
        : event.reviewState === 'CHANGES_REQUESTED'
          ? 'changes'
          : '';
    const label =
      event.reviewState === 'APPROVED'
        ? 'approved'
        : event.reviewState === 'CHANGES_REQUESTED'
          ? 'requested changes'
          : 'reviewed';
    return <span className={`tl-review-state ${cls}`}>{label}</span>;
  }
  if (event.kind === 'review_comment') {
    return (
      <span>
        commented{event.path ? ' on ' : ''}
        {event.path && <span className="path">{event.path.split('/').pop()}</span>}
      </span>
    );
  }
  return <span>commented</span>;
}

export default function Timeline() {
  const [unreadOnly, setUnreadOnly] = useState(false);
  const queryClient = useQueryClient();

  const query = useInfiniteQuery({
    queryKey: ['timeline', unreadOnly],
    queryFn: ({ pageParam }) => fetchTimeline({ cursor: pageParam, unreadOnly }),
    initialPageParam: undefined as string | undefined,
    getNextPageParam: (page) => page.nextCursor ?? undefined,
  });

  const invalidate = () => {
    void queryClient.invalidateQueries({ queryKey: ['timeline'] });
    void queryClient.invalidateQueries({ queryKey: ['state'] });
  };

  const readMutation = useMutation({
    mutationFn: ({ id, read }: { id: string; read: boolean }) => markRead(id, read),
    onSettled: invalidate,
  });

  const readAllMutation = useMutation({ mutationFn: markAllRead, onSettled: invalidate });

  const events = query.data?.pages.flatMap((p) => p.events) ?? [];
  const groups = groupEvents(events);

  const openEvent = (e: TimelineEvent) => {
    if (!e.read) readMutation.mutate({ id: e.id, read: true });
    window.open(e.url, '_blank', 'noopener');
  };

  return (
    <>
      <div className="timeline-head">
        <h2>Activity</h2>
        <button className={unreadOnly ? 'active' : ''} onClick={() => setUnreadOnly((v) => !v)}>
          Unread only
        </button>
        <button onClick={() => readAllMutation.mutate()}>Mark all read</button>
      </div>
      <div className="timeline-list">
        {query.isLoading && <div className="empty-note">Loading…</div>}
        {!query.isLoading && groups.length === 0 && (
          <div className="empty-note">{unreadOnly ? 'Nothing unread.' : 'No activity yet.'}</div>
        )}
        {groups.map((group) => (
          <div className="tl-group" key={group.key}>
            <div className="tl-group-head">
              <span className="actor">{group.actor}</span>
              <a
                href={`https://github.com/${group.repo}/pull/${group.prNumber}`}
                target="_blank"
                rel="noreferrer"
                title={group.prTitle}
              >
                {shortRepo(group.repo)}#{group.prNumber} · {group.prTitle}
              </a>
              <span>{relativeTime(group.events[0]!.createdAt)}</span>
            </div>
            {group.events.map((e) => (
              <div
                key={e.id}
                className={`tl-item${e.read ? '' : ' unread'}`}
                onClick={() => openEvent(e)}
              >
                <button
                  className="dot"
                  aria-label={e.read ? 'mark unread' : 'mark read'}
                  title={e.read ? 'Mark unread' : 'Mark read'}
                  onClick={(ev) => {
                    ev.stopPropagation();
                    readMutation.mutate({ id: e.id, read: !e.read });
                  }}
                />
                <div>
                  <div className="tl-kind">
                    <KindLabel event={e} />
                  </div>
                  {e.bodyExcerpt && <div className="body">{e.bodyExcerpt}</div>}
                </div>
              </div>
            ))}
          </div>
        ))}
        {query.hasNextPage && (
          <button
            className="load-more"
            onClick={() => query.fetchNextPage()}
            disabled={query.isFetchingNextPage}
          >
            {query.isFetchingNextPage ? 'Loading…' : 'Load older'}
          </button>
        )}
      </div>
    </>
  );
}
