import { useMemo, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { query } from '../api/client';
import { useQuery } from '../lib/hooks';
import { duration, num, percent, when } from '../lib/format';
import {
  Banner,
  Card,
  EmptyRow,
  Field,
  Grid,
  Loading,
  Meter,
  PageHead,
  TableWrap,
  Tag,
  Tiles,
} from '../components/ui';

/* Memby's major feature catalogue, in the order it is presented.
 *
 * It is a list here rather than derived from what has been used, and that is the whole
 * point of the table it feeds: a feature nobody has touched has no row in the analytics
 * and would simply be absent, which is indistinguishable from a feature that does not
 * exist. Listing it and showing a zero is what makes "not used" an answer. */
const FEATURE_CATALOGUE = [
  'home', 'movies', 'shows', 'favorites', 'search', 'recent_searches',
  'genre_browse', 'for_you', 'for_you_time', 'recommendation', 'continue',
  'latest', 'my_shows', 'details', 'playback', 'notifications', 'profiles', 'settings',
];

/** The wire values are ids; this is the render, so it is spelled — the same boundary the
 *  launcher's own row titles observe. */
function label(value: string | undefined | null): string {
  const text = String(value || '—').replaceAll('_', ' ');
  if (text === 'favorites') return 'Favourites';
  if (text === 'abandoned') return 'Abandoned / interrupted';
  return text;
}

interface JourneysResponse {
  days: number;
  retentionDays: number;
  stats: {
    events: number;
    journeys: number;
    viewers: number;
    completed: number;
    abandoned: number;
    active: number;
    averageSteps: number;
    averageTimeMs: number;
    completionRate: number;
  };
  users: { userId: string; username: string }[] | null;
  features: { feature: string; uses: number; lastUsedAt: string }[] | null;
  actions: { category: string; action: string; events: number; journeys: number }[] | null;
  paths: { from: string; to: string; count: number }[] | null;
}

export function JourneysPage() {
  const [days, setDays] = useState(30);
  const [userId, setUserId] = useState('');
  const navigate = useNavigate();
  const path = useMemo(() => `/admin/api/journeys${query({ days, userId })}`, [days, userId]);
  const { data, error, loading } = useQuery<JourneysResponse>(path);

  const stats = data?.stats;
  const users = data?.users ?? [];
  const actions = data?.actions ?? [];
  const paths = data?.paths ?? [];
  const topPath = paths[0];

  const features = useMemo(() => {
    const used = new Map((data?.features ?? []).map((feature) => [feature.feature, feature]));
    const position = new Map(FEATURE_CATALOGUE.map((name, index) => [name, index]));
    return [...new Set([...FEATURE_CATALOGUE, ...used.keys()])]
      .map((name) => ({ name, stat: used.get(name) }))
      .sort((left, right) => {
        const byUse = (right.stat?.uses ?? 0) - (left.stat?.uses ?? 0);
        if (byUse) return byUse;
        return (
          (position.get(left.name) ?? Number.MAX_SAFE_INTEGER) -
          (position.get(right.name) ?? Number.MAX_SAFE_INTEGER)
        );
      });
  }, [data?.features]);

  // Individual visits are shown only for one person: across a household they are a wall
  // of cards with nothing to compare against, and the question they answer is always
  // "what did *they* do".
  return (
    <>
      <PageHead
        title="User journeys"
        intro="How viewers move through Memby, use features and complete flows."
      />
      <Banner message={error} />

      <Card
        title="Journey health"
        intro="Server-derived foreground visits, completion and interruption. Search text, content titles and setting values are never stored."
        icon="people"
        tone="info"
        actions={
          <>
            <Field label="Window">
              <select value={days} onChange={(event) => setDays(Number(event.target.value))}>
                <option value={1}>24 hours</option>
                <option value={7}>7 days</option>
                <option value={30}>30 days</option>
                <option value={90}>90 days</option>
              </select>
            </Field>
            <Field label="User">
              <select
                value={userId}
                onChange={(event) => {
                  const next = event.target.value;
                  setUserId(next);
                  if (next) navigate(`/admin/journeys/${encodeURIComponent(next)}`);
                }}
              >
                <option value="">All users</option>
                {users.map((user) => (
                  <option key={user.userId} value={user.userId}>
                    {user.username || user.userId}
                  </option>
                ))}
              </select>
            </Field>
          </>
        }
      >
        {loading ? (
          <Loading rows={1} />
        ) : (
          <>
            <Tiles
              tiles={[
                { label: 'journeys', value: num(stats?.journeys), icon: 'list', tone: 'data' },
                { label: 'viewers', value: num(stats?.viewers), icon: 'people', tone: 'info' },
                { label: 'completion', value: percent(stats?.completionRate), icon: 'check', tone: 'ok' },
                { label: 'abandoned', value: num(stats?.abandoned), icon: 'alert', tone: 'note' },
                { label: 'active now', value: num(stats?.active), icon: 'pulse', tone: 'info' },
                { label: 'average steps', value: (stats?.averageSteps ?? 0).toFixed(1), icon: 'chart' },
                { label: 'average visit', value: duration(stats?.averageTimeMs), small: true, icon: 'clock' },
                { label: 'history kept', value: `${data?.retentionDays ?? 90} days`, small: true, icon: 'clock' },
              ]}
            />

            <div className="summary-grid">
              <div className="summary">
                <div className="summary-head">
                  <b>Visit completion</b>
                  <strong>{percent(stats?.completionRate)}</strong>
                </div>
                <Meter value={stats?.completed ?? 0} total={stats?.journeys ?? 0} />
                <p>
                  {num(stats?.completed)} completed · {num(stats?.abandoned)} abandoned ·{' '}
                  {num(stats?.active)} active
                </p>
              </div>
              <div className="summary">
                <div className="summary-head">
                  <b>Most common route</b>
                </div>
                <strong style={undefined}>
                  {topPath ? `${label(topPath.from)} → ${label(topPath.to)}` : 'Not enough data'}
                </strong>
                <p>
                  {topPath
                    ? `${num(topPath.count)} times in this window`
                    : 'Journeys will appear here as viewers move through Memby.'}
                </p>
              </div>
            </div>
          </>
        )}
      </Card>

      <Grid cols="2">
        <Card
          title="What people do"
          intro="Actions show total use and how many separate visits included them."
          icon="chart"
          tone="info"
        >
          <TableWrap>
            <table>
              <thead>
                <tr>
                  <th>Action</th>
                  <th className="num">Uses</th>
                  <th className="num">Visits</th>
                </tr>
              </thead>
              <tbody>
                {actions.length === 0 ? (
                  <EmptyRow columns={3}>No significant actions in this window.</EmptyRow>
                ) : (
                  actions.map((action) => (
                    <tr key={`${action.category}:${action.action}`}>
                      <td>
                        <b>{label(action.action)}</b>
                        <span className="table-sub">{label(action.category)}</span>
                      </td>
                      <td className="num">{num(action.events)}</td>
                      <td className="num">{num(action.journeys)}</td>
                    </tr>
                  ))
                )}
              </tbody>
            </table>
          </TableWrap>
        </Card>

        <Card
          title="Where people go"
          intro="The most common steps between screens, including where quiet visits ended."
          icon="list"
          tone="note"
        >
          <TableWrap>
            <table>
              <thead>
                <tr>
                  <th>Route</th>
                  <th className="num">Times</th>
                </tr>
              </thead>
              <tbody>
                {paths.length === 0 ? (
                  <EmptyRow columns={2}>No repeated paths in this window.</EmptyRow>
                ) : (
                  paths.map((entry, index) => (
                    <tr key={`${entry.from}:${entry.to}:${index}`}>
                      <td>
                        {label(entry.from)} <span className="route-arrow">→</span> {label(entry.to)}
                      </td>
                      <td className="num">{num(entry.count)}</td>
                    </tr>
                  ))
                )}
              </tbody>
            </table>
          </TableWrap>
        </Card>
      </Grid>

      <Card
        title="Feature use"
        intro="Rare and unused features are shown against Memby's major feature catalogue."
        icon="pulse"
        tone="data"
      >
        <TableWrap>
          <table>
            <thead>
              <tr>
                <th>Feature</th>
                <th className="num">Uses</th>
                <th>Last used</th>
                <th>Status</th>
              </tr>
            </thead>
            <tbody>
              {features.map(({ name, stat }) => {
                const uses = stat?.uses ?? 0;
                return (
                  <tr key={name}>
                    <td>{label(name)}</td>
                    <td className="num">{num(uses)}</td>
                    <td className="muted nowrap">{stat ? when(stat.lastUsedAt) : '—'}</td>
                    <td>
                      {uses === 0 ? (
                        <Tag tone="warn">not used</Tag>
                      ) : uses < 3 ? (
                        <Tag tone="note">rare</Tag>
                      ) : (
                        <Tag tone="ok">used</Tag>
                      )}
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </TableWrap>
      </Card>

      {userId ? null : (
        <Card title="Inspect a viewer" intro="Choose a person above to open their dedicated session and viewing-journey timeline." icon="journey" tone="info">
          <p className="empty">A viewing journey follows one intent through to playback, so two films watched in a single app session appear as two separate journeys.</p>
        </Card>
      )}
    </>
  );
}
