#!/usr/bin/env node
/**
b * Multi-Agent Orchestrator MCP Server v2.0
 * 
 * Cursor Agent CLI를 활용한 멀티에이전트 시스템
 * - PM (Cursor IDE): 전체 조율
 * - Sub-agents (agent CLI): 전문가별 작업 수행
 * 
 * 모든 AI 호출이 Cursor Team Plan으로 처리됨!
 * API 키 불필요!
 */

import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import { spawn } from "child_process";
import { platform } from "os";
import { AGENT_CONFIGS } from "./agents/prompts.js";
import { AgentType, ParallelResult } from "./agents/types.js";
import { logger } from "./utils/logger.js";

// OS 감지
const isWindows = platform() === "win32";
logger.info(`Platform detected: ${platform()} (isWindows: ${isWindows})`);

// MCP 서버 생성
const server = new Server(
  {
    name: "agent-orchestrator",
    version: "2.0.0",
  },
  {
    capabilities: {
      tools: {},
    },
  }
);

/**
 * 유틸: ms만큼 대기
 */
function sleep(ms: number): Promise<void> {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

/**
 * Cursor Agent CLI 단일 호출 (내부용)
 * spawn + stdin 직접 전달
 */
function spawnAgentOnce(
  agentType: AgentType,
  fullPrompt: string,
  model: string
): Promise<string> {
  const agentPath = isWindows ? 'agent' : `${process.env.HOME}/.local/bin/agent`;

  return new Promise<string>((resolve, reject) => {
    let stdout = '';
    let stderr = '';
    let settled = false;

    const child = spawn(agentPath, ['--model', model, '--print'], {
      cwd: process.cwd(),
      env: {
        ...process.env,
        PATH: `${process.env.HOME}/.local/bin:${process.env.PATH}`,
      },
      stdio: ['pipe', 'pipe', 'pipe'],
    });

    child.stdout.on('data', (data: Buffer) => {
      stdout += data.toString();
    });

    child.stderr.on('data', (data: Buffer) => {
      stderr += data.toString();
    });

    child.on('error', (err: Error) => {
      if (!settled) {
        settled = true;
        reject(err);
      }
    });

    child.on('close', (code: number | null) => {
      if (settled) return;
      settled = true;

      if (stderr) {
        const significantStderr = stderr
          .split('\n')
          .filter((line: string) => line && !line.includes('warning') && !line.includes('info') && !line.includes('debug'))
          .join('\n');
        if (significantStderr) {
          logger.warn(`${agentType} agent stderr`, { stderr: significantStderr.substring(0, 500) });
        }
      }

      if (code === 0 || stdout.trim().length > 0) {
        resolve(stdout.trim());
      } else {
        reject(new Error(
          `Agent exited with code ${code}. stderr: ${stderr.substring(0, 1000)}`
        ));
      }
    });

    // 타임아웃 (5분)
    const timeout = setTimeout(() => {
      if (!settled) {
        settled = true;
        child.kill('SIGTERM');
        reject(new Error(`${agentType} agent timed out after 5 minutes`));
      }
    }, 300000);

    child.on('close', () => clearTimeout(timeout));

    // stdin으로 프롬프트 직접 전달
    child.stdin.write(fullPrompt);
    child.stdin.end();
  });
}

/**
 * Cursor Agent CLI를 통해 에이전트 호출 (재시도 포함)
 * 
 * - 최대 2회 재시도 (총 3회 시도)
 * - 재시도 간 2초 대기 (Cursor CLI 동시 실행 제한 대응)
 */
async function callAgentCLI(
  agentType: AgentType,
  task: string,
  context?: string
): Promise<string> {
  const config = AGENT_CONFIGS[agentType];
  const model = agentType === 'pm' ? 'opus-4.5' : 'sonnet-4.5';
  const maxRetries = 2;

  logger.info(`Calling ${agentType} agent via CLI (spawn+retry)`, {
    model,
    task: task.substring(0, 100),
  });

  const userMessage = context
    ? `${task}\n\n배경 정보:\n${context}`
    : task;
  const fullPrompt = `${config.systemPrompt}\n\n---\n\n${userMessage}`;

  let lastError: Error | null = null;

  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    try {
      if (attempt > 0) {
        const delay = attempt * 2000; // 2초, 4초
        logger.info(`${agentType} agent retry ${attempt}/${maxRetries} (waiting ${delay}ms)`);
        await sleep(delay);
      }

      const result = await spawnAgentOnce(agentType, fullPrompt, model);
      logger.info(`${agentType} agent completed (attempt ${attempt + 1})`);
      return result;
    } catch (error) {
      lastError = error instanceof Error ? error : new Error(String(error));
      logger.warn(`${agentType} agent attempt ${attempt + 1} failed`, {
        error: lastError.message.substring(0, 200),
      });
    }
  }

  // 모든 재시도 실패
  logger.error(`${agentType} agent failed after ${maxRetries + 1} attempts`);
  throw lastError!;
}

/**
 * 도구 목록 핸들러
 */
server.setRequestHandler(ListToolsRequestSchema, async () => {
  return {
    tools: [
      {
        name: "ask_backend_agent",
        description: 
          "백엔드 전문가에게 질문하거나 작업을 요청합니다. " +
          "API 설계, 서비스 로직, 라우팅, 미들웨어 관련 작업에 사용하세요. " +
          "담당 폴더: backend-node/src/ (Cursor Agent CLI, sonnet-4.5 모델)" +
          "주의: 단순 파일 읽기/수정은 PM이 직접 처리하세요. 깊은 분석이 필요할 때만 호출!",
        inputSchema: {
          type: "object" as const,
          properties: {
            task: {
              type: "string",
              description: "백엔드 에이전트에게 요청할 작업 내용",
            },
            context: {
              type: "string",
              description: "작업에 필요한 배경 정보 (선택사항)",
            },
          },
          required: ["task"],
        },
      },
      {
        name: "ask_db_agent",
        description: 
          "DB 전문가에게 질문하거나 작업을 요청합니다. " +
          "스키마 설계, SQL 쿼리, 마이그레이션 관련 작업에 사용하세요. " +
          "담당 폴더: backend-node/src/, db/ (Cursor Agent CLI, sonnet-4.5 모델)" +
          "주의: 단순 스키마 확인은 PM이 직접 처리하세요. 복잡한 쿼리 설계/최적화 시에만 호출!",
        inputSchema: {
          type: "object" as const,
          properties: {
            task: {
              type: "string",
              description: "DB 에이전트에게 요청할 작업 내용",
            },
            context: {
              type: "string",
              description: "작업에 필요한 배경 정보 (선택사항)",
            },
          },
          required: ["task"],
        },
      },
      {
        name: "ask_frontend_agent",
        description: 
          "프론트엔드 전문가에게 질문하거나 작업을 요청합니다. " +
          "React 컴포넌트, 페이지, 스타일링, 상태관리 관련 작업에 사용하세요. " +
          "담당 폴더: frontend/ (Cursor Agent CLI, sonnet-4.5 모델)" +
          "주의: 단순 컴포넌트 읽기/수정은 PM이 직접 처리하세요. 구조 분석이 필요할 때만 호출!",
        inputSchema: {
          type: "object" as const,
          properties: {
            task: {
              type: "string",
              description: "프론트엔드 에이전트에게 요청할 작업 내용",
            },
            context: {
              type: "string",
              description: "작업에 필요한 배경 정보 (선택사항)",
            },
          },
          required: ["task"],
        },
      },
      {
        name: "parallel_ask",
        description: 
          "여러 전문가에게 동시에 질문합니다 (진짜 병렬 실행!). " +
          "3개 영역(FE+BE+DB) 크로스도메인 분석이 필요할 때만 사용하세요. " +
          "주의: 호출 시간이 오래 걸림! 단순 작업은 PM이 직접 처리하는 게 훨씬 빠릅니다. " +
          "적합한 경우: 전체 아키텍처 파악, 대규모 리팩토링 계획, 크로스도메인 영향 분석",
        inputSchema: {
          type: "object" as const,
          properties: {
            requests: {
              type: "array",
              description: "각 에이전트에게 보낼 요청 목록",
              items: {
                type: "object",
                properties: {
                  agent: {
                    type: "string",
                    enum: ["backend", "db", "frontend"],
                    description: "요청할 에이전트 타입",
                  },
                  task: {
                    type: "string",
                    description: "해당 에이전트에게 요청할 작업",
                  },
                  context: {
                    type: "string",
                    description: "배경 정보 (선택사항)",
                  },
                },
                required: ["agent", "task"],
              },
            },
          },
          required: ["requests"],
        },
      },
      {
        name: "get_agent_info",
        description: 
          "에이전트 시스템의 현재 상태와 사용 가능한 에이전트 정보를 확인합니다.",
        inputSchema: {
          type: "object" as const,
          properties: {},
        },
      },
    ],
  };
});

/**
 * 도구 호출 핸들러
 */
server.setRequestHandler(CallToolRequestSchema, async (request) => {
  const { name, arguments: args } = request.params;

  logger.info(`Tool called: ${name}`);

  try {
    switch (name) {
      case "ask_backend_agent": {
        const { task, context } = args as { task: string; context?: string };
        const result = await callAgentCLI("backend", task, context);
        return {
          content: [{ type: "text" as const, text: result }],
        };
      }

      case "ask_db_agent": {
        const { task, context } = args as { task: string; context?: string };
        const result = await callAgentCLI("db", task, context);
        return {
          content: [{ type: "text" as const, text: result }],
        };
      }

      case "ask_frontend_agent": {
        const { task, context } = args as { task: string; context?: string };
        const result = await callAgentCLI("frontend", task, context);
        return {
          content: [{ type: "text" as const, text: result }],
        };
      }

      case "parallel_ask": {
        const { requests } = args as {
          requests: Array<{
            agent: "backend" | "db" | "frontend";
            task: string;
            context?: string;
          }>;
        };

        logger.info(`Parallel ask to ${requests.length} agents (STAGGERED PARALLEL)`);

        // 시차 병렬 실행: 각 에이전트를 500ms 간격으로 시작
        // Cursor Agent CLI 동시 실행 제한 대응
        const STAGGER_DELAY = 500; // ms

        const results: ParallelResult[] = await Promise.all(
          requests.map(async (req, index) => {
            try {
              // 시차 적용 (첫 번째는 즉시, 이후 500ms 간격)
              if (index > 0) {
                await sleep(index * STAGGER_DELAY);
              }
              const result = await callAgentCLI(req.agent, req.task, req.context);
              return { agent: req.agent, result };
            } catch (error) {
              return {
                agent: req.agent,
                result: "",
                error: error instanceof Error ? error.message : "Unknown error",
              };
            }
          })
        );

        // 결과를 보기 좋게 포맷팅
        const formattedResults = results.map((r) => {
          const header = `\n${"=".repeat(60)}\n## ${r.agent.toUpperCase()} Agent 응답\n${"=".repeat(60)}\n`;
          if (r.error) {
            return `${header}❌ 에러: ${r.error}`;
          }
          return `${header}${r.result}`;
        });

        return {
          content: [
            {
              type: "text" as const,
              text: formattedResults.join("\n"),
            },
          ],
        };
      }

      case "get_agent_info": {
        const info = {
          system: "Multi-Agent Orchestrator v2.0",
          version: "2.0.0",
          backend: "Cursor Agent CLI (Team Plan)",
          cliPath: `${process.env.HOME}/.local/bin/agent`,
          apiKey: "NOT REQUIRED! Using Cursor Team Plan credits",
          agents: {
            pm: {
              role: "Project Manager",
              model: "opus-4.5 (Cursor IDE에서 직접)",
              description: "전체 조율, 사용자 의도 파악, 작업 분배",
            },
            backend: {
              role: "Backend Specialist",
              model: "sonnet-4.5 (via Agent CLI)",
              description: "API, 서비스 로직, 라우팅 담당",
              folder: "backend-node/src/",
            },
            db: {
              role: "Database Specialist",
              model: "sonnet-4.5 (via Agent CLI)",
              description: "스키마, 쿼리, 마이그레이션 담당",
              folder: "backend-node/src/, db/",
            },
            frontend: {
              role: "Frontend Specialist",
              model: "sonnet-4.5 (via Agent CLI)",
              description: "컴포넌트, 페이지, 스타일링 담당",
              folder: "frontend/",
            },
          },
          features: {
            parallel_execution: true,
            cursor_team_plan: true,
            cursor_agent_cli: true,
            separate_api_key: false,
            cross_platform: true,
          },
          usage: {
            single_agent: "ask_backend_agent, ask_db_agent, ask_frontend_agent",
            parallel: "parallel_ask로 여러 에이전트 동시 호출",
            workflow: "1. parallel_ask로 정보 수집 → 2. 개별 에이전트로 작업 분배",
          },
        };

        return {
          content: [
            {
              type: "text" as const,
              text: JSON.stringify(info, null, 2),
            },
          ],
        };
      }

      default:
        throw new Error(`Unknown tool: ${name}`);
    }
  } catch (error) {
    logger.error(`Tool error: ${name}`, error);
    return {
      content: [
        {
          type: "text" as const,
          text: `❌ 에러 발생: ${error instanceof Error ? error.message : "Unknown error"}`,
        },
      ],
      isError: true,
    };
  }
});

/**
 * 서버 시작
 */
async function main() {
  logger.info("Starting Multi-Agent Orchestrator MCP Server v2.0...");
  logger.info(`Backend: Cursor Agent CLI (${process.env.HOME}/.local/bin/agent)`);
  logger.info("Credits: Cursor Team Plan - No API Key Required!");

  const transport = new StdioServerTransport();
  await server.connect(transport);

  logger.info("MCP Server connected and ready!");
}

main().catch((error) => {
  logger.error("Server failed to start", error);
  process.exit(1);
});
