'use client';

/**
 * AnalyticsPage — Tenant analytics dashboard for the SentryAgent portal.
 *
 * Displays:
 * - Token issuance trend (last 30 days) via TokenTrendChart (lazy-loaded)
 * - Agent activity by day-of-week via AgentHeatmap (lazy-loaded)
 * - Per-agent usage table for the current billing period
 *
 * All chart components are code-split via `next/dynamic` so that recharts
 * is excluded from the main bundle.
 *
 * Protected route: redirects to `/login` when no JWT is present (via useAuth).
 *
 * @module app/analytics/page
 */

import React, { useEffect, useState } from 'react';
import dynamic from 'next/dynamic';
import { useAuth } from '@/hooks/useAuth';
import type { TokenTrendDataPoint } from '@/components/charts/TokenTrendChart';
import type { AgentActivityBucket } from '@/components/charts/AgentHeatmap';

/* -------------------------------------------------------------------------
 * Lazy-loaded chart components (recharts stays out of the main bundle)
 * ---------------------------------------------------------------------- */

const TokenTrendChart = dynamic(
  () => import('@/components/charts/TokenTrendChart'),
  {
    ssr: false,
    loading: () => (
      <ChartSkeleton label="Loading token trend chart…" height={300} />
    ),
  },
);

const AgentHeatmap = dynamic(
  () => import('@/components/charts/AgentHeatmap'),
  {
    ssr: false,
    loading: () => (
      <ChartSkeleton label="Loading activity chart…" height={300} />
    ),
  },
);

/* -------------------------------------------------------------------------
 * API response types
 * ---------------------------------------------------------------------- */

/** A single entry from `GET /api/analytics/agents`. */
interface AgentUsageSummary {
  agent_id: string;
  name: string;
  token_count: number;
}

/** Root shape of `GET /api/analytics/agents/activity`. */
type AgentActivityResponse = AgentActivityBucket[];

/** Root shape of `GET /api/analytics/tokens`. */
type TokenTrendResponse = TokenTrendDataPoint[];

/** Root shape of `GET /api/analytics/agents`. */
type AgentUsageResponse = AgentUsageSummary[];

/* -------------------------------------------------------------------------
 * Page state
 * ---------------------------------------------------------------------- */

/** Loading / error / data state for a single async fetch. */
interface FetchState<T> {
  data: T | null;
  loading: boolean;
  error: string | null;
}

function initFetchState<T>(): FetchState<T> {
  return { data: null, loading: true, error: null };
}

/* -------------------------------------------------------------------------
 * Helpers
 * ---------------------------------------------------------------------- */

/**
 * Fetches a JSON endpoint with an Authorization bearer token.
 *
 * @param url - Absolute URL to fetch
 * @param token - JWT bearer token
 * @returns Parsed JSON of type T
 * @throws Error with a descriptive message on non-2xx or network failure
 */
async function fetchWithAuth<T>(url: string, token: string): Promise<T> {
  const res = await fetch(url, {
    headers: { Authorization: `Bearer ${token}` },
  });
  if (!res.ok) {
    const body = (await res.json().catch(() => ({}))) as { message?: string };
    throw new Error(body.message ?? `Request failed: ${res.status}`);
  }
  return res.json() as Promise<T>;
}

/* -------------------------------------------------------------------------
 * Sub-components
 * ---------------------------------------------------------------------- */

/** Props for ChartSkeleton. */
interface ChartSkeletonProps {
  label: string;
  height: number;
}

/**
 * Placeholder shown while a dynamic chart chunk is loading.
 *
 * @param props - ChartSkeletonProps
 * @returns JSX element
 */
function ChartSkeleton({ label, height }: ChartSkeletonProps): React.ReactElement {
  return (
    <div
      className="flex animate-pulse items-center justify-center rounded-xl bg-slate-100 text-sm text-slate-400"
      style={{ height }}
      aria-label={label}
    >
      {label}
    </div>
  );
}

/** Props for SectionCard. */
interface SectionCardProps {
  title: string;
  children: React.ReactNode;
}

/**
 * Simple card wrapper for dashboard sections.
 *
 * @param props - SectionCardProps
 * @returns JSX element
 */
function SectionCard({ title, children }: SectionCardProps): React.ReactElement {
  return (
    <div className="rounded-2xl border border-slate-200 bg-white p-6 shadow-sm">
      <h2 className="mb-4 text-lg font-semibold text-slate-900">{title}</h2>
      {children}
    </div>
  );
}

/** Props for ErrorBanner. */
interface ErrorBannerProps {
  message: string;
}

/**
 * Inline error banner for failed data fetches.
 *
 * @param props - ErrorBannerProps
 * @returns JSX element
 */
function ErrorBanner({ message }: ErrorBannerProps): React.ReactElement {
  return (
    <p className="rounded-lg bg-red-50 px-4 py-3 text-sm text-red-700">
      {message}
    </p>
  );
}

/* -------------------------------------------------------------------------
 * Page component
 * ---------------------------------------------------------------------- */

/**
 * Renders the analytics dashboard page.
 *
 * Checks authentication via `useAuth` (redirects to /login if no token).
 * Fetches analytics data from the AgentIdP API using the stored JWT.
 *
 * @returns JSX element
 */
export default function AnalyticsPage(): React.ReactElement {
  const { token, loading: authLoading } = useAuth(true);

  const apiUrl = process.env.NEXT_PUBLIC_API_URL ?? 'http://localhost:3000';

  const [tokenTrend, setTokenTrend] =
    useState<FetchState<TokenTrendResponse>>(initFetchState);
  const [agentActivity, setAgentActivity] =
    useState<FetchState<AgentActivityResponse>>(initFetchState);
  const [agentUsage, setAgentUsage] =
    useState<FetchState<AgentUsageResponse>>(initFetchState);

  useEffect(() => {
    // Wait until auth state is resolved and token is available
    if (authLoading || token === null) return;

    void fetchWithAuth<TokenTrendResponse>(
      `${apiUrl}/api/analytics/tokens?days=30`,
      token,
    )
      .then((data) => setTokenTrend({ data, loading: false, error: null }))
      .catch((err: unknown) =>
        setTokenTrend({
          data: null,
          loading: false,
          error: err instanceof Error ? err.message : 'Failed to load token trend',
        }),
      );

    void fetchWithAuth<AgentActivityResponse>(
      `${apiUrl}/api/analytics/agents/activity`,
      token,
    )
      .then((data) => setAgentActivity({ data, loading: false, error: null }))
      .catch((err: unknown) =>
        setAgentActivity({
          data: null,
          loading: false,
          error: err instanceof Error ? err.message : 'Failed to load agent activity',
        }),
      );

    void fetchWithAuth<AgentUsageResponse>(
      `${apiUrl}/api/analytics/agents`,
      token,
    )
      .then((data) => setAgentUsage({ data, loading: false, error: null }))
      .catch((err: unknown) =>
        setAgentUsage({
          data: null,
          loading: false,
          error: err instanceof Error ? err.message : 'Failed to load agent usage',
        }),
      );
  }, [authLoading, token, apiUrl]);

  // While auth state is being resolved, show a full-page loading state
  if (authLoading) {
    return (
      <div className="flex min-h-[60vh] items-center justify-center">
        <p className="text-slate-500">Loading…</p>
      </div>
    );
  }

  // token === null means useAuth is redirecting to /login; render nothing
  if (token === null) {
    return <></>;
  }

  return (
    <div className="px-6 py-16">
      <div className="mx-auto max-w-6xl">
        {/* Page header */}
        <div className="mb-10">
          <h1 className="text-4xl font-extrabold text-slate-900">Analytics</h1>
          <p className="mt-2 text-slate-600">
            Token issuance and agent activity for the last 30 days
          </p>
        </div>

        <div className="grid gap-8">
          {/* Token Trend */}
          <SectionCard title="Token Issuance Trend (Last 30 Days)">
            {tokenTrend.error !== null && (
              <ErrorBanner message={tokenTrend.error} />
            )}
            {tokenTrend.loading && tokenTrend.error === null && (
              <ChartSkeleton label="Loading token trend chart…" height={300} />
            )}
            {tokenTrend.data !== null && (
              <TokenTrendChart data={tokenTrend.data} />
            )}
          </SectionCard>

          {/* Agent Activity Heatmap */}
          <SectionCard title="Agent Activity by Day of Week (Last 30 Days)">
            {agentActivity.error !== null && (
              <ErrorBanner message={agentActivity.error} />
            )}
            {agentActivity.loading && agentActivity.error === null && (
              <ChartSkeleton label="Loading activity chart…" height={300} />
            )}
            {agentActivity.data !== null && (
              <AgentHeatmap data={agentActivity.data} />
            )}
          </SectionCard>

          {/* Per-Agent Usage Table */}
          <SectionCard title="Per-Agent Usage (Current Month)">
            {agentUsage.error !== null && (
              <ErrorBanner message={agentUsage.error} />
            )}
            {agentUsage.loading && agentUsage.error === null && (
              <div className="animate-pulse space-y-2">
                {[1, 2, 3].map((n) => (
                  <div key={n} className="h-10 rounded bg-slate-100" />
                ))}
              </div>
            )}
            {agentUsage.data !== null && agentUsage.data.length === 0 && (
              <p className="text-sm text-slate-500">
                No agents have issued tokens this month.
              </p>
            )}
            {agentUsage.data !== null && agentUsage.data.length > 0 && (
              <div className="overflow-hidden rounded-xl border border-slate-200">
                <table className="w-full text-sm">
                  <thead>
                    <tr className="bg-slate-50">
                      <th className="px-4 py-3 text-left font-semibold text-slate-700">
                        Agent
                      </th>
                      <th className="px-4 py-3 text-right font-semibold text-slate-700">
                        Tokens Issued
                      </th>
                    </tr>
                  </thead>
                  <tbody>
                    {agentUsage.data.map(({ agent_id, name, token_count }, i) => (
                      <tr
                        key={agent_id}
                        className={i % 2 === 0 ? 'bg-white' : 'bg-slate-50'}
                      >
                        <td className="px-4 py-3 text-slate-700">
                          <span className="font-medium">{name}</span>
                          <span className="ml-2 font-mono text-xs text-slate-400">
                            {agent_id}
                          </span>
                        </td>
                        <td className="px-4 py-3 text-right font-medium tabular-nums text-slate-900">
                          {token_count.toLocaleString()}
                        </td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              </div>
            )}
          </SectionCard>
        </div>
      </div>
    </div>
  );
}
