/**
 * BrainOverflowAgent — A2A pipeline for MindLyst brain capacity management.
 *
 * Agent roster (3 steps):
 *   1. BrainInventoryAgent    — list all brains; query item counts per brain
 *   2. OverflowDetectorAgent  — flag brains above itemThreshold with no acted-on items in staleDays
 *   3. OverflowReportAgent    — assemble report with archive / reassign suggestions per overflowed brain
 *
 * MCP tools:
 *   mindlyst.brains.checkOverflow(itemThreshold?, staleDays?) — run pipeline
 */

import { randomUUID } from 'node:crypto';
import { z } from 'zod';
import { registerTool } from '../tools/registry.js';
import type { McpToolRequest } from '../tools/types.js';
import {
  mindlystBrainsList,
  mindlystMemoryList,
  type BrainDoc,
} from '../../lib/mindlyst-client.js';
import { config } from '../../lib/config.js';

// ── Types ──────────────────────────────────────────────────────────────────────

type OverflowSuggestion = 'archive' | 'reassign' | 'review' | 'none';

interface BrainCapacityResult {
  brainId: string;
  brainName: string;
  totalItems: number;
  actedOnItems: number;
  pendingItems: number;
  mostRecentActedOnAt: string | null;
  staleDaysWithoutAction: number | null;
  isOverflowed: boolean;
  suggestion: OverflowSuggestion;
  suggestionReason: string;
}

export interface BrainOverflowReport {
  runId: string;
  productId: 'mindlyst';
  itemThreshold: number;
  staleDays: number;
  brainsScanned: number;
  overflowedCount: number;
  healthyCount: number;
  perBrain: BrainCapacityResult[];
  summary: string;
  generatedAt: string;
}

// ── Step 1: BrainInventoryAgent ───────────────────────────────────────────────

async function inventoryBrains(opts: { token?: string; requestId?: string }): Promise<BrainDoc[]> {
  try {
    const result = await mindlystBrainsList({ limit: config.QUERY_MAX_LIMIT }, opts);
    return result.items;
  } catch {
    return [];
  }
}

// ── Step 2: OverflowDetectorAgent ─────────────────────────────────────────────

async function checkBrainCapacity(
  brain: BrainDoc,
  itemThreshold: number,
  staleDays: number,
  opts: { token?: string; requestId?: string }
): Promise<BrainCapacityResult> {
  let totalItems = 0;
  let actedOnItems = 0;
  let pendingItems = 0;
  let mostRecentActedOnAt: string | null = null;

  try {
    const result = await mindlystMemoryList(
      { brainId: brain.id, limit: config.QUERY_MAX_LIMIT },
      opts
    );

    totalItems = result.items.length;
    actedOnItems = result.items.filter(i => i.actedOn).length;
    pendingItems = totalItems - actedOnItems;

    const actedDates = result.items
      .filter(i => i.actedOn && i.actedOnAt)
      .map(i => i.actedOnAt as string)
      .sort()
      .reverse();
    mostRecentActedOnAt = actedDates[0] ?? null;
  } catch {
    // best-effort
  }

  const staleDaysWithoutAction = mostRecentActedOnAt
    ? Math.floor((Date.now() - new Date(mostRecentActedOnAt).getTime()) / (1000 * 60 * 60 * 24))
    : null;

  const isTooFull = totalItems >= itemThreshold;
  const isStale =
    staleDaysWithoutAction === null ? pendingItems > 0 : staleDaysWithoutAction >= staleDays;

  const isOverflowed = isTooFull && isStale;

  let suggestion: OverflowSuggestion = 'none';
  let suggestionReason = 'Brain is healthy.';

  if (isOverflowed) {
    if (actedOnItems === 0 && totalItems >= itemThreshold) {
      suggestion = 'archive';
      suggestionReason = `${totalItems} items, none acted on — brain may be abandoned. Consider archiving.`;
    } else if (pendingItems > actedOnItems * 2) {
      suggestion = 'reassign';
      suggestionReason = `${pendingItems} pending vs ${actedOnItems} acted-on, stale for ${staleDaysWithoutAction ?? '?'} days. Reassign pending items to active brains.`;
    } else {
      suggestion = 'review';
      suggestionReason = `${totalItems} items with ${staleDaysWithoutAction ?? '?'} days since last action. Manual review recommended.`;
    }
  } else if (isTooFull) {
    suggestion = 'review';
    suggestionReason = `${totalItems} items (above threshold ${itemThreshold}) but recently active. Consider splitting into sub-brains.`;
  }

  return {
    brainId: brain.id,
    brainName: brain.name,
    totalItems,
    actedOnItems,
    pendingItems,
    mostRecentActedOnAt,
    staleDaysWithoutAction,
    isOverflowed,
    suggestion,
    suggestionReason,
  };
}

// ── Step 3: OverflowReportAgent ───────────────────────────────────────────────

function assembleOverflowReport(
  runId: string,
  itemThreshold: number,
  staleDays: number,
  results: BrainCapacityResult[]
): BrainOverflowReport {
  const overflowedCount = results.filter(r => r.isOverflowed).length;
  const healthyCount = results.filter(r => !r.isOverflowed).length;

  const summary =
    results.length === 0
      ? 'No brains found.'
      : overflowedCount === 0
        ? `All ${results.length} brains are within capacity thresholds.`
        : `${overflowedCount}/${results.length} brains flagged for overflow (>${itemThreshold} items, stale >${staleDays} days). ${results.filter(r => r.suggestion === 'archive').length} archive, ${results.filter(r => r.suggestion === 'reassign').length} reassign, ${results.filter(r => r.suggestion === 'review').length} review.`;

  return {
    runId,
    productId: 'mindlyst',
    itemThreshold,
    staleDays,
    brainsScanned: results.length,
    overflowedCount,
    healthyCount,
    perBrain: results,
    summary,
    generatedAt: new Date().toISOString(),
  };
}

// ── Pipeline runner ────────────────────────────────────────────────────────────

async function runBrainOverflowPipeline(
  itemThreshold: number,
  staleDays: number,
  req: McpToolRequest
): Promise<BrainOverflowReport> {
  const runId = randomUUID();
  const opts = { token: req.headers.authorization?.slice(7), requestId: req.id };

  req.log.info({ runId, stepId: 'inventory' }, 'BrainInventoryAgent start');
  const brains = await inventoryBrains(opts);
  req.log.info(
    { runId, stepId: 'inventory', brainCount: brains.length },
    'BrainInventoryAgent done'
  );

  req.log.info(
    { runId, stepId: 'detect', itemThreshold, staleDays },
    'OverflowDetectorAgent start'
  );
  const results: BrainCapacityResult[] = [];
  for (const brain of brains) {
    const result = await checkBrainCapacity(brain, itemThreshold, staleDays, opts);
    results.push(result);
  }
  req.log.info(
    { runId, stepId: 'detect', overflowedCount: results.filter(r => r.isOverflowed).length },
    'OverflowDetectorAgent done'
  );

  req.log.info({ runId, stepId: 'report' }, 'OverflowReportAgent start');
  const report = assembleOverflowReport(runId, itemThreshold, staleDays, results);
  req.log.info({ runId, stepId: 'report', summary: report.summary }, 'OverflowReportAgent done');

  return report;
}

// ── MCP tool registration ─────────────────────────────────────────────────────

registerTool({
  name: 'mindlyst.brains.checkOverflow',
  description:
    'A2A pipeline: scans all MindLyst brains for capacity overflow — brains above a configured item count with no acted-on items in N days. Classifies each overflowed brain as archive, reassign, or review, and returns a capacity health report. Requires admin role.',
  requiredRole: 'admin',
  inputSchema: z.object({
    itemThreshold: z.coerce
      .number()
      .int()
      .min(1)
      .default(50)
      .describe('Item count above which a brain is considered full (default 50)'),
    staleDays: z.coerce
      .number()
      .int()
      .min(1)
      .default(14)
      .describe('Days without action before a full brain is flagged as overflowed (default 14)'),
  }),
  async execute(args, req) {
    return runBrainOverflowPipeline(args.itemThreshold, args.staleDays, req);
  },
});
