import * as fs from "fs";
import { ResourceTemplate, } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StateManager, getSessionFilePath, getRegisteredSessions, hasSessionData, getSessionData, normalizeRecommendationState, } from "../utils/AnalysisStateManager.js";
import { logger } from "../utils/logger.js";
import { AnalysisScope, } from "../types/RepositoryAnalysis.js";
export const ANALYSIS_URI_PREFIX = "skyramp://analysis";
/**
 * Register MCP Resources for analysis data access.
 *
 * Resources provide read-only, token-efficient access to analysis data
 * via sessionId. The state file is an internal backing store.
 *
 * URI scheme:
 *   skyramp://analysis/{sessionId}/summary
 *   skyramp://analysis/{sessionId}/endpoints
 *   skyramp://analysis/{sessionId}/endpoints/{+path}
 *   skyramp://analysis/{sessionId}/endpoints/{+path}/{method}
 *   skyramp://analysis/{sessionId}/scenarios
 *   skyramp://analysis/{sessionId}/diff
 */
export function registerAnalysisResources(server) {
    logger.info("Registering analysis resources");
    async function loadAnalysis(sessionId) {
        // Try process memory first (new flow — no state file needed)
        if (hasSessionData(sessionId)) {
            const memData = getSessionData(sessionId);
            if (memData?.analysis) {
                logger.debug("Loaded analysis from process memory for resource", { sessionId });
                return memData;
            }
        }
        logger.warning(`Session not found in memory (sessionId=${sessionId}) — server may have restarted; falling back to state file`);
        // Fall back to state file for backward compatibility.
        // Try both "analysis" and "recommendation" prefixes since the default changed.
        const registeredPath = getSessionFilePath(sessionId);
        let mgr;
        if (registeredPath) {
            mgr = StateManager.fromStatePath(registeredPath);
        }
        else {
            const analysisMgr = StateManager.fromSessionId(sessionId, "analysis");
            const recommendationMgr = StateManager.fromSessionId(sessionId, "recommendation");
            mgr = analysisMgr.exists() ? analysisMgr : recommendationMgr;
        }
        if (!mgr.exists()) {
            throw new Error(`Analysis session "${sessionId}" not found or expired.`);
        }
        const data = await mgr.readData();
        if (!data) {
            throw new Error(`Analysis session "${sessionId}" has no data.`);
        }
        const normalized = normalizeRecommendationState(data);
        if (!normalized.analysis) {
            throw new Error(`Analysis session "${sessionId}" has no analysis data.`);
        }
        return normalized;
    }
    /**
     * Shared list callback: returns resource URIs for sessions created by
     * this process only (via the in-memory registry). No filesystem scan —
     * eliminates cross-process leakage when multiple clients share /tmp.
     */
    function makeListCallback(suffix) {
        return async () => {
            const sessions = getRegisteredSessions();
            const available = Array.from(sessions.entries()).filter(([sessionId, filePath]) => hasSessionData(sessionId) || fs.existsSync(filePath));
            return {
                resources: available.map(([sessionId]) => ({
                    uri: `${ANALYSIS_URI_PREFIX}/${sessionId}/${suffix}`,
                    name: `Analysis ${suffix} (${sessionId})`,
                    mimeType: "application/json",
                })),
            };
        };
    }
    // ── Summary ──
    server.registerResource("analysis_summary", new ResourceTemplate(`${ANALYSIS_URI_PREFIX}/{sessionId}/summary`, {
        list: makeListCallback("summary"),
    }), {
        title: "Analysis Summary",
        description: "High-level overview: project type, tech stack, endpoint/scenario counts, coverage gaps.",
        mimeType: "application/json",
    }, async (uri, params) => {
        const sessionId = params.sessionId;
        const { analysis, repositoryPath, analysisScope } = await loadAnalysis(sessionId);
        const summary = {
            sessionId,
            repositoryPath,
            analysisScope: analysisScope || AnalysisScope.FullRepo,
            metadata: analysis.metadata,
            projectClassification: analysis.projectClassification,
            technologyStack: {
                languages: analysis.technologyStack.languages,
                frameworks: analysis.technologyStack.frameworks,
                runtime: analysis.technologyStack.runtime,
            },
            authentication: analysis.authentication,
            infrastructure: analysis.infrastructure,
            endpointStats: {
                totalPaths: analysis.apiEndpoints.endpoints.length,
                totalMethods: analysis.apiEndpoints.endpoints.reduce((sum, ep) => sum + ep.methods.length, 0),
                totalInteractions: analysis.apiEndpoints.endpoints.reduce((sum, ep) => sum +
                    ep.methods.reduce((msum, m) => msum + m.interactions.length, 0), 0),
                baseUrl: analysis.apiEndpoints.baseUrl,
            },
            scenarioCount: analysis.businessContext.draftedScenarios.length,
            existingTests: analysis.existingTests,
        };
        return {
            contents: [
                {
                    uri: uri.href,
                    mimeType: "application/json",
                    text: JSON.stringify(summary, null, 2),
                },
            ],
        };
    });
    // ── Endpoints (compact listing) ──
    server.registerResource("analysis_endpoints", new ResourceTemplate(`${ANALYSIS_URI_PREFIX}/{sessionId}/endpoints`, {
        list: makeListCallback("endpoints"),
    }), {
        title: "Endpoint Listing",
        description: "Compact listing of all endpoints (path, methods, interaction counts). Use path-specific resources for full detail.",
        mimeType: "application/json",
    }, async (uri, params) => {
        const sessionId = params.sessionId;
        const { analysis } = await loadAnalysis(sessionId);
        const compact = analysis.apiEndpoints.endpoints.map((ep) => ({
            path: ep.path,
            resourceGroup: ep.resourceGroup,
            pathParams: ep.pathParams.map((p) => p.name),
            methods: ep.methods.map((m) => ({
                method: m.method,
                authRequired: m.authRequired,
                interactionCount: m.interactions.length,
                interactionTypes: m.interactions.map((i) => i.type),
                hasCookies: m.interactions.some((i) => (i.response.cookies?.length ?? 0) > 0),
                hasResponseHeaders: m.interactions.some((i) => Object.keys(i.response.headers ?? {}).length > 0),
                createsResource: m.createsResource,
            })),
        }));
        return {
            contents: [
                {
                    uri: uri.href,
                    mimeType: "application/json",
                    text: JSON.stringify({ baseUrl: analysis.apiEndpoints.baseUrl, endpoints: compact }, null, 2),
                },
            ],
        };
    });
    // ── Single Path Detail ──
    // No list callback — these are parameterized drilldowns, not top-level resources.
    server.registerResource("analysis_endpoint_path", new ResourceTemplate(`${ANALYSIS_URI_PREFIX}/{sessionId}/endpoints/{+path}`, { list: undefined }), {
        title: "Endpoint Path Detail",
        description: "Full detail for a specific path: all methods, interactions, params.",
        mimeType: "application/json",
    }, async (uri, params) => {
        const sessionId = params.sessionId;
        const endpointPath = "/" + params.path;
        const { analysis } = await loadAnalysis(sessionId);
        const ep = analysis.apiEndpoints.endpoints.find((e) => e.path === endpointPath);
        if (!ep) {
            throw new Error(`Endpoint path "${endpointPath}" not found in session "${sessionId}".`);
        }
        return {
            contents: [
                {
                    uri: uri.href,
                    mimeType: "application/json",
                    text: JSON.stringify(ep, null, 2),
                },
            ],
        };
    });
    // ── Single Method Detail ──
    server.registerResource("analysis_endpoint_method", new ResourceTemplate(`${ANALYSIS_URI_PREFIX}/{sessionId}/endpoints/{+path}/{method}`, { list: undefined }), {
        title: "Endpoint Method Detail",
        description: "Full detail for a specific method on a path: interactions, params, auth.",
        mimeType: "application/json",
    }, async (uri, params) => {
        const sessionId = params.sessionId;
        const endpointPath = "/" + params.path;
        const method = params.method.toUpperCase();
        const { analysis } = await loadAnalysis(sessionId);
        const ep = analysis.apiEndpoints.endpoints.find((e) => e.path === endpointPath);
        if (!ep) {
            throw new Error(`Endpoint path "${endpointPath}" not found in session "${sessionId}".`);
        }
        const m = ep.methods.find((em) => em.method.toUpperCase() === method);
        if (!m) {
            throw new Error(`Method "${method}" not found on "${endpointPath}" in session "${sessionId}".`);
        }
        return {
            contents: [
                {
                    uri: uri.href,
                    mimeType: "application/json",
                    text: JSON.stringify({ path: ep.path, resourceGroup: ep.resourceGroup, pathParams: ep.pathParams, ...m }, null, 2),
                },
            ],
        };
    });
    // ── Scenarios ──
    server.registerResource("analysis_scenarios", new ResourceTemplate(`${ANALYSIS_URI_PREFIX}/{sessionId}/scenarios`, {
        list: makeListCallback("scenarios"),
    }), {
        title: "Drafted Scenarios",
        description: "All drafted user-flow scenarios with steps, chaining, and priority.",
        mimeType: "application/json",
    }, async (uri, params) => {
        const sessionId = params.sessionId;
        const { analysis } = await loadAnalysis(sessionId);
        return {
            contents: [
                {
                    uri: uri.href,
                    mimeType: "application/json",
                    text: JSON.stringify(analysis.businessContext.draftedScenarios, null, 2),
                },
            ],
        };
    });
    // ── Branch Diff ──
    server.registerResource("analysis_diff", new ResourceTemplate(`${ANALYSIS_URI_PREFIX}/{sessionId}/diff`, {
        list: makeListCallback("diff"),
    }), {
        title: "Branch Diff Context",
        description: "Branch diff context with new/modified endpoints (only present for current_branch_diff scope).",
        mimeType: "application/json",
    }, async (uri, params) => {
        const sessionId = params.sessionId;
        const { analysis } = await loadAnalysis(sessionId);
        if (!analysis.branchDiffContext) {
            return {
                contents: [
                    {
                        uri: uri.href,
                        mimeType: "application/json",
                        text: JSON.stringify({ message: "No branch diff context (analysis scope was full_repo)." }, null, 2),
                    },
                ],
            };
        }
        return {
            contents: [
                {
                    uri: uri.href,
                    mimeType: "application/json",
                    text: JSON.stringify(analysis.branchDiffContext, null, 2),
                },
            ],
        };
    });
    logger.info("Analysis resources registered successfully");
}
