/**
 * Shutdown Tool - Gracefully stop OpenChrome and close Chrome
 *
 * Provides "oc stop" functionality:
 * 1. Clean up all sessions and workers
 * 2. Shutdown connection pool (close all pooled pages)
 * 3. Disconnect CDP client
 * 4. Kill Chrome process if OpenChrome launched it
 */

import { MCPServer } from '../mcp-server';
import { MCPToolDefinition, MCPResult, ToolHandler } from '../types/mcp';
import { TOOL_ANNOTATIONS } from '../types/tool-annotations';
import { getSessionManager } from '../session-manager';
import { getCDPConnectionPool } from '../cdp/connection-pool';
import { getCDPClient } from '../cdp/client';
import { getChromeLauncher } from '../chrome/launcher';
import { shutdownHeadedFallback } from '../chrome/headed-fallback';
import { shouldOcStopKeepChromeByDefault } from '../broker/lifecycle';

const definition: MCPToolDefinition = {
  name: 'oc_stop',
  description: 'Shut down OpenChrome and close Chrome. Auto-relaunched on next tool call.',
  inputSchema: {
    type: 'object',
    properties: {
      keepChrome: {
        type: 'boolean',
        description: 'Keep Chrome running, just disconnect. Default: false in standalone mode, true when running in broker owner mode so shared clients are not impacted.',
      },
      dryRun: {
        type: 'boolean',
        default: false,
        description: 'Preview sessions/tabs and managed Chrome resources that oc_stop would shut down without mutating runtime state.',
      },
    },
    required: [],
  },
  annotations: TOOL_ANNOTATIONS.oc_stop,
};

const handler: ToolHandler = async (
  _sessionId: string,
  args: Record<string, unknown>
): Promise<MCPResult> => {
  const keepChrome = typeof args.keepChrome === 'boolean'
    ? (args.keepChrome as boolean)
    : shouldOcStopKeepChromeByDefault();
  const dryRun = args.dryRun === true;
  const steps: string[] = [];
  const startTime = Date.now();

  try {
    if (dryRun) {
      const sessionManager = getSessionManager();
      const sessions = sessionManager.getAllSessionInfos();
      const totalTabs = sessions.reduce((sum, session) => sum + session.targetCount, 0);
      const samples = sessions.slice(0, 10).map((session) => ({
        id: session.id,
        name: session.name,
        targetCount: session.targetCount,
        workerCount: session.workerCount,
      }));
      const wouldAffect = {
        count: sessions.length,
        samples,
        details: {
          sessions: sessions.length,
          tabs: totalTabs,
          keepChrome,
          headedFallback: true,
          connectionPool: true,
          cdpClient: true,
          chromeProcess: !keepChrome,
        },
      };
      return {
        content: [{
          type: 'text',
          text: JSON.stringify({
            action: 'oc_stop',
            dryRun: true,
            wouldAffect,
            message: `Would stop ${sessions.length} session(s) and ${totalTabs} tab(s)${keepChrome ? ', keeping Chrome running' : ', including managed Chrome shutdown'}.`,
          }),
        }],
        structuredContent: {
          dryRun: true,
          wouldAffect,
          guidance: 'Pass dryRun:false (or omit) to execute.',
        },
        isError: false,
      };
    }

    // Step 1: Clean up all sessions (closes workers, tabs, browser contexts)
    // Wrapped in its own try/catch so a broken CDP connection doesn't prevent
    // the remaining steps (pool shutdown, CDP disconnect, Chrome kill) from running.
    try {
      const sessionManager = getSessionManager();
      const sessionCount = await sessionManager.cleanupAllSessions();
      steps.push(`Cleaned up ${sessionCount} session(s)`);
    } catch (e) {
      steps.push(`Session cleanup failed: ${e instanceof Error ? e.message : 'error'} (skipped, continuing)`);
    }

    // Step 1.5: Shut down headed Chrome fallback if it was ever launched (#485)
    try {
      shutdownHeadedFallback();
      steps.push('Headed Chrome fallback terminated');
    } catch (e) {
      steps.push(`Headed Chrome fallback: ${e instanceof Error ? e.message : 'error'}`);
    }

    // Step 2: Shutdown connection pool (closes all pooled about:blank pages)
    try {
      const pool = getCDPConnectionPool();
      const stats = pool.getStats();
      await pool.shutdown();
      steps.push(`Shutdown connection pool (${stats.availablePages} pooled + ${stats.inUsePages} in-use pages closed)`);
    } catch (e) {
      steps.push(`Connection pool: ${e instanceof Error ? e.message : 'already shutdown'}`);
    }

    // Step 3: Disconnect CDP client
    try {
      const cdpClient = getCDPClient();
      if (cdpClient.isConnected()) {
        await cdpClient.disconnect();
        steps.push('Disconnected CDP client');
      } else {
        steps.push('CDP client: already disconnected');
      }
    } catch (e) {
      steps.push(`CDP client: ${e instanceof Error ? e.message : 'error'}`);
    }

    // Step 4: Close Chrome process (if OpenChrome launched it and keepChrome is false)
    if (!keepChrome) {
      try {
        const launcher = getChromeLauncher();
        if (launcher.isConnected()) {
          await launcher.close();
          steps.push('Chrome process terminated');
        } else {
          steps.push('Chrome: no OpenChrome-managed process to terminate');
        }
      } catch (e) {
        steps.push(`Chrome: ${e instanceof Error ? e.message : 'error'}`);
      }
    } else {
      steps.push('Chrome: kept running (keepChrome=true)');
    }

    const durationMs = Date.now() - startTime;

    return {
      content: [
        {
          type: 'text',
          text: [
            'OpenChrome stopped successfully.',
            '',
            'Shutdown steps:',
            ...steps.map((s, i) => `  ${i + 1}. ${s}`),
            '',
            `Total: ${durationMs}ms`,
            '',
            'Chrome will re-launch automatically on the next OpenChrome tool call.',
          ].join('\n'),
        },
      ],
    };
  } catch (error) {
    return {
      content: [
        {
          type: 'text',
          text: `Error during shutdown: ${error instanceof Error ? error.message : String(error)}\n\nPartial steps completed:\n${steps.map((s, i) => `  ${i + 1}. ${s}`).join('\n')}`,
        },
      ],
      isError: true,
    };
  }
};

export function registerShutdownTool(server: MCPServer): void {
  server.registerTool('oc_stop', handler, definition);
}
