import { useMemo, useState } from 'react';
import { Link } from 'react-router-dom';
import { query } from '../api/client';
import { useQuery } from '../lib/hooks';
import { ago, num, when } from '../lib/format';
import {
  Banner,
  Button,
  Card,
  EmptyRow,
  Field,
  Loading,
  PageHead,
  Segments,
  TableWrap,
  Tag,
  Tiles,
} from '../components/ui';
import { Glyph } from '../components/Icon';
import {
  eventIcon,
  eventTone,
  eventTypeLabel,
  useNotifications,
  type AdminEvent,
  type EventTypeCount,
} from '../lib/notifications';

/* The activity feed in full: the bell's dropdown with filters and no twenty-row cap.
 *
 * It reads its own window from the server rather than the provider's cached list, because
 * the provider holds only the most recent fifty — enough for a badge and a dropdown, not
 * enough to answer "what happened on Tuesday". The badge and the "mark all read" button
 * still come from the provider, so this page and the bell can never disagree about how
 * much is unread. */

interface FeedResponse {
  events: AdminEvent[];
  total: number;
  unread: number;
  types: EventTypeCount[];
  subscribers: number;
}

const WINDOWS = [
  { value: 1, label: 'Today' },
  { value: 7, label: '7 days' },
  { value: 30, label: '30 days' },
];

export function ActivityPage() {
  const { unread, connected, markAllRead, reload: reloadBell } = useNotifications();
  const [days, setDays] = useState(7);
  const [type, setType] = useState('');
  const [severity, setSeverity] = useState('');
  const [unreadOnly, setUnreadOnly] = useState(false);
  const [page, setPage] = useState(0);

  const limit = 100;
  const path = useMemo(
    () =>
      `/admin/api/notifications${query({
        days,
        type,
        severity,
        unread: unreadOnly,
        limit,
        offset: page * limit,
      })}`,
    [days, type, severity, unreadOnly, page],
  );
  const { data, error, loading, reload } = useQuery<FeedResponse>(path);

  const markAll = async () => {
    await markAllRead();
    await reload();
  };

  return (
    <>
      <PageHead
        title="Activity"
        intro="Every administrative event the gateway has published: sign-ins, devices, scheduled tasks, integrations and the server itself. The same feed the bell and every integration read from."
        actions={
          unread > 0 ? (
            <Button onClick={() => void markAll()} icon="check">
              Mark all read
            </Button>
          ) : undefined
        }
      />

      <Banner message={error} />

      <Tiles
        tiles={[
          { label: 'Events in window', value: num(data?.total ?? 0), icon: 'bell', tone: 'info' },
          { label: 'Unread', value: num(unread), icon: 'alert', tone: unread > 0 ? 'warn' : undefined },
          { label: 'Kinds seen', value: num(data?.types.length ?? 0), icon: 'list', tone: 'note' },
          {
            label: 'Live feed',
            value: connected ? 'connected' : 'reconnecting',
            small: true,
            icon: 'pulse',
            tone: connected ? 'ok' : 'warn',
          },
        ]}
      />

      <div className="filters">
        <Field label="Window">
          <Segments
            value={days}
            options={WINDOWS.map((w) => ({ value: w.value, label: w.label }))}
            onChange={(next) => {
              setDays(next);
              setPage(0);
            }}
          />
        </Field>
        <Field label="Kind">
          {/* Built from what has actually been published, so the filter can neither offer a
              kind that matches nothing nor miss one a service added after this shipped. */}
          <select
            value={type}
            onChange={(event) => {
              setType(event.target.value);
              setPage(0);
            }}
          >
            <option value="">Everything</option>
            {(data?.types ?? []).map((entry) => (
              <option key={entry.type} value={entry.type}>
                {eventTypeLabel(entry.type)} ({entry.count})
              </option>
            ))}
          </select>
        </Field>
        <Field label="Severity">
          <select
            value={severity}
            onChange={(event) => {
              setSeverity(event.target.value);
              setPage(0);
            }}
          >
            <option value="">Any</option>
            <option value="info">Information</option>
            <option value="warning">Warning</option>
            <option value="error">Error</option>
          </select>
        </Field>
        <Field label="Read state">
          <select
            value={unreadOnly ? 'unread' : ''}
            onChange={(event) => {
              setUnreadOnly(event.target.value === 'unread');
              setPage(0);
            }}
          >
            <option value="">All</option>
            <option value="unread">Unread only</option>
          </select>
        </Field>
        <div className="filter-actions">
          <Button
            variant="quiet"
            size="sm"
            icon="refresh"
            onClick={() => {
              void reload();
              void reloadBell();
            }}
          >
            Refresh
          </Button>
        </div>
      </div>

      {loading ? (
        <Loading />
      ) : (
        <Card
          title="Events"
          icon="bell"
          tone="info"
          footer={
            (data?.total ?? 0) > limit ? (
              <>
                <Button size="sm" disabled={page === 0} onClick={() => setPage(page - 1)}>
                  Newer
                </Button>
                <Button
                  size="sm"
                  disabled={(page + 1) * limit >= (data?.total ?? 0)}
                  onClick={() => setPage(page + 1)}
                >
                  Older
                </Button>
              </>
            ) : undefined
          }
        >
          <TableWrap>
            <table>
              <thead>
                <tr>
                  <th className="nowrap">When</th>
                  <th>Kind</th>
                  <th>What happened</th>
                  <th>Who</th>
                  <th>What</th>
                  <th />
                </tr>
              </thead>
              <tbody>
                {(data?.events.length ?? 0) === 0 ? (
                  <EmptyRow columns={6}>Nothing has happened in this window.</EmptyRow>
                ) : (
                  data?.events.map((event) => (
                    <tr key={event.id}>
                      <td className="nowrap muted" title={when(event.occurredAt)}>
                        {ago(event.occurredAt)}
                      </td>
                      <td className="nowrap">
                        <span className="row tight">
                          <Glyph name={eventIcon(event.type)} tone={eventTone(event)} />
                          {eventTypeLabel(event.type)}
                        </span>
                      </td>
                      <td>
                        <b>{event.title}</b>
                        {event.summary ? <div className="muted">{event.summary}</div> : null}
                      </td>
                      <td className="muted nowrap">{event.actor || '—'}</td>
                      <td className="muted nowrap">{event.target || '—'}</td>
                      <td className="nowrap">
                        {!event.readAt ? <Tag tone="ok">new</Tag> : null}
                        {event.link ? (
                          <Link className="table-row-link" to={event.link}>
                            Open
                          </Link>
                        ) : null}
                      </td>
                    </tr>
                  ))
                )}
              </tbody>
            </table>
          </TableWrap>
        </Card>
      )}
    </>
  );
}
