// [nexus] Assistant home-state data aggregator (Phase 9).
//
// Composes existing APIs (agents, approvals, activity, projects) into the
// shape the AssistantHomeGreeting needs. Does NOT create new endpoints.
// If any source errors out, that slice gracefully degrades to an empty
// value and logs a single console.warn in development.
import { useMemo } from "react";
import { useQuery } from "@tanstack/react-query";
import type { Agent, Approval, Project, ActivityEvent } from "@paperclipai/shared";
import { agentsApi } from "../api/agents";
import { approvalsApi } from "../api/approvals";
import { activityApi } from "../api/activity";
import { projectsApi } from "../api/projects";

export interface PendingGate {
  id: string;
  projectName: string;
  gateName: string;
  href: string;
}

export interface RecentCompletion {
  id: string;
  projectName: string;
  summary: string;
  when: string;
}

export interface StaleProject {
  id: string;
  name: string;
  lastActivity: string;
  href: string;
}

export interface AssistantHomeStatus {
  activeAgents: number;
  pendingGates: PendingGate[];
  recentCompletions: RecentCompletion[];
  staleProjects: StaleProject[];
  loading: boolean;
  companyPrefix: string | null;
}

export interface UseAssistantHomeStatusOptions {
  companyId: string | null;
  companyPrefix?: string | null;
  /**
   * The current time. Exposed for deterministic testing — defaults to `Date.now()`.
   */
  now?: () => number;
  /**
   * Maximum number of stale projects to surface. Defaults to 3.
   */
  maxStaleProjects?: number;
  /**
   * Maximum number of recent completions to surface. Defaults to 3.
   */
  maxRecentCompletions?: number;
  /**
   * Staleness threshold in milliseconds. Defaults to 3 days.
   */
  staleThresholdMs?: number;
  /**
   * Window for "recent" completions, in milliseconds. Defaults to 24 hours.
   */
  recentWindowMs?: number;
}

const DEFAULT_STALE_THRESHOLD_MS = 3 * 24 * 60 * 60 * 1000;
const DEFAULT_RECENT_WINDOW_MS = 24 * 60 * 60 * 1000;

function toDateMs(value: Date | string | null | undefined): number | null {
  if (!value) return null;
  const t = value instanceof Date ? value.getTime() : Date.parse(value);
  return Number.isFinite(t) ? t : null;
}

function formatRelative(fromMs: number, nowMs: number): string {
  const delta = Math.max(0, nowMs - fromMs);
  const minutes = Math.floor(delta / 60_000);
  if (minutes < 60) return `${minutes}m ago`;
  const hours = Math.floor(minutes / 60);
  if (hours < 24) return `${hours}h ago`;
  const days = Math.floor(hours / 24);
  return `${days}d ago`;
}

function gateLabel(approval: Approval): string {
  const payload = approval.payload as Record<string, unknown> | null;
  if (payload && typeof payload === "object") {
    const title = payload["title"] ?? payload["name"] ?? payload["summary"];
    if (typeof title === "string" && title.trim()) return title.trim();
  }
  return String(approval.type ?? "Gate");
}

function completionSummary(event: ActivityEvent): string {
  const details = event.details ?? null;
  if (details && typeof details === "object") {
    const summary = (details as Record<string, unknown>)["summary"];
    if (typeof summary === "string" && summary.trim()) return summary.trim();
    const title = (details as Record<string, unknown>)["title"];
    if (typeof title === "string" && title.trim()) return title.trim();
  }
  return event.action;
}

/**
 * Given raw payloads from the four upstream APIs, produce the aggregated
 * home-status view used by the AssistantHomeGreeting. Pure: easy to unit test.
 */
export function composeHomeStatus(args: {
  agents: Agent[];
  approvals: Approval[];
  activity: ActivityEvent[];
  projects: Project[];
  nowMs: number;
  companyPrefix: string | null;
  maxStaleProjects: number;
  maxRecentCompletions: number;
  staleThresholdMs: number;
  recentWindowMs: number;
}): Omit<AssistantHomeStatus, "loading"> {
  const {
    agents,
    approvals,
    activity,
    projects,
    nowMs,
    companyPrefix,
    maxStaleProjects,
    maxRecentCompletions,
    staleThresholdMs,
    recentWindowMs,
  } = args;

  const activeAgents = agents.filter((a) => a.status === "running").length;

  const projectNameById = new Map<string, string>();
  for (const project of projects) {
    projectNameById.set(project.id, project.name);
  }

  const pendingGates: PendingGate[] = approvals
    .filter((a) => a.status === "pending")
    .map((a) => {
      const payload = a.payload as Record<string, unknown> | null;
      const projectId =
        payload && typeof payload === "object" && typeof payload["projectId"] === "string"
          ? (payload["projectId"] as string)
          : null;
      const projectName = projectId ? projectNameById.get(projectId) ?? "" : "";
      return {
        id: a.id,
        projectName,
        gateName: gateLabel(a),
        href: companyPrefix ? `/${companyPrefix}/approvals/${a.id}` : `/approvals/${a.id}`,
      } satisfies PendingGate;
    });

  const recentCompletions: RecentCompletion[] = activity
    .filter((e) => {
      if (!/completed|completion|done|finished/i.test(e.action)) return false;
      const createdMs = toDateMs(e.createdAt);
      if (createdMs === null) return false;
      return nowMs - createdMs <= recentWindowMs;
    })
    .sort((a, b) => {
      const aMs = toDateMs(a.createdAt) ?? 0;
      const bMs = toDateMs(b.createdAt) ?? 0;
      return bMs - aMs;
    })
    .slice(0, maxRecentCompletions)
    .map((e) => {
      const projectId = e.entityType === "project" ? e.entityId : null;
      const projectName = projectId ? projectNameById.get(projectId) ?? "" : "";
      const createdMs = toDateMs(e.createdAt) ?? nowMs;
      return {
        id: e.id,
        projectName,
        summary: completionSummary(e),
        when: formatRelative(createdMs, nowMs),
      } satisfies RecentCompletion;
    });

  const staleProjects: StaleProject[] = projects
    .filter((p) => p.status !== "archived")
    .map((p) => {
      const lastMs = toDateMs(p.updatedAt) ?? toDateMs(p.createdAt) ?? 0;
      return { project: p, lastMs };
    })
    .filter(({ lastMs }) => lastMs > 0 && nowMs - lastMs > staleThresholdMs)
    .sort((a, b) => a.lastMs - b.lastMs)
    .slice(0, maxStaleProjects)
    .map(({ project, lastMs }) => ({
      id: project.id,
      name: project.name,
      lastActivity: formatRelative(lastMs, nowMs),
      href: companyPrefix
        ? `/${companyPrefix}/projects/${project.urlKey || project.id}`
        : `/projects/${project.urlKey || project.id}`,
    }));

  return { activeAgents, pendingGates, recentCompletions, staleProjects, companyPrefix };
}

function warnOnce(key: string, err: unknown) {
  if (typeof window === "undefined") return;
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  const bag = (window as any).__nexusHomeStatusWarned__ ?? new Set<string>();
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  (window as any).__nexusHomeStatusWarned__ = bag;
  if (bag.has(key)) return;
  bag.add(key);
  console.warn(`[useAssistantHomeStatus] ${key} unavailable, degrading to empty`, err);
}

export function useAssistantHomeStatus(
  options: UseAssistantHomeStatusOptions,
): AssistantHomeStatus {
  const {
    companyId,
    companyPrefix = null,
    now = () => Date.now(),
    maxStaleProjects = 3,
    maxRecentCompletions = 3,
    staleThresholdMs = DEFAULT_STALE_THRESHOLD_MS,
    recentWindowMs = DEFAULT_RECENT_WINDOW_MS,
  } = options;

  const enabled = !!companyId;

  const agentsQuery = useQuery<Agent[]>({
    queryKey: ["assistant-home", "agents", companyId],
    queryFn: async () => {
      try {
        return await agentsApi.list(companyId!);
      } catch (err) {
        warnOnce("agents", err);
        return [];
      }
    },
    enabled,
    staleTime: 30_000,
  });

  const approvalsQuery = useQuery<Approval[]>({
    queryKey: ["assistant-home", "approvals", companyId],
    queryFn: async () => {
      try {
        return await approvalsApi.list(companyId!, "pending");
      } catch (err) {
        warnOnce("approvals", err);
        return [];
      }
    },
    enabled,
    staleTime: 30_000,
  });

  const activityQuery = useQuery<ActivityEvent[]>({
    queryKey: ["assistant-home", "activity", companyId],
    queryFn: async () => {
      try {
        return await activityApi.list(companyId!);
      } catch (err) {
        warnOnce("activity", err);
        return [];
      }
    },
    enabled,
    staleTime: 30_000,
  });

  const projectsQuery = useQuery<Project[]>({
    queryKey: ["assistant-home", "projects", companyId],
    queryFn: async () => {
      try {
        return await projectsApi.list(companyId!);
      } catch (err) {
        warnOnce("projects", err);
        return [];
      }
    },
    enabled,
    staleTime: 30_000,
  });

  const loading =
    enabled &&
    (agentsQuery.isLoading ||
      approvalsQuery.isLoading ||
      activityQuery.isLoading ||
      projectsQuery.isLoading);

  return useMemo(() => {
    const composed = composeHomeStatus({
      agents: agentsQuery.data ?? [],
      approvals: approvalsQuery.data ?? [],
      activity: activityQuery.data ?? [],
      projects: projectsQuery.data ?? [],
      nowMs: now(),
      companyPrefix,
      maxStaleProjects,
      maxRecentCompletions,
      staleThresholdMs,
      recentWindowMs,
    });
    return { ...composed, loading };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [
    agentsQuery.data,
    approvalsQuery.data,
    activityQuery.data,
    projectsQuery.data,
    loading,
    companyPrefix,
    maxStaleProjects,
    maxRecentCompletions,
    staleThresholdMs,
    recentWindowMs,
  ]);
}
