import { z } from "zod";
import { logger } from "../../utils/logger.js";
import { StateManager, } from "../../utils/AnalysisStateManager.js";
import path from "path";
import { AnalyticsService } from "../../services/AnalyticsService.js";
import { buildDriftAnalysisPrompt } from "../../prompts/test-maintenance/drift-analysis-prompt.js";
import { TestSource } from "../../types/TestAnalysis.js";
import { toolError } from "../../utils/utils.js";
const TOOL_NAME = "skyramp_analyze_test_health";
export function registerAnalyzeTestHealthTool(server) {
    server.registerTool(TOOL_NAME, {
        annotations: {
            readOnlyHint: false, // deletes old state files via StateManager.cleanupOldFiles
            destructiveHint: false,
            idempotentHint: true,
            openWorldHint: false,
        },
        description: `Generate drift assessment instructions for existing tests — second step of the unified Test Health Analysis Flow.

**PREREQUISITE:** Call \`skyramp_analyze_changes\` first to get a stateFile.

Returns a structured prompt for the LLM to assess each existing test against the branch diff and assign one of: UPDATE / REGENERATE / VERIFY / DELETE / IGNORE.

Includes both Skyramp-generated tests and user-written (external) tests that are relevant to the PR's changed endpoints. For external tests, UPDATE is applied automatically; REGENERATE and DELETE are surfaced as report-only findings for the developer.

The LLM follows the returned prompt (Action Decision Tree pre-scan → Endpoint Existence → Response Shape → Additive Fields → Auth/AuthZ → Behavioral Contract → Assign Action → Update Execution Rules), then calls \`skyramp_actions\` with its \`recommendations[]\`.

(Optional) Execute tests using \`skyramp_execute_test\` with \`stateFile\` before \`skyramp_actions\` to validate live.`,
        inputSchema: {
            stateFile: z
                .string()
                .describe("Path to state file from skyramp_analyze_changes. Assessment results exist only in the LLM's reasoning context — this tool does not write back to the stateFile."),
        },
        outputSchema: {
            prompt: z.string().describe("LLM drift analysis prompt and assessment instructions."),
        },
    }, async (args) => {
        let errorResult;
        try {
            logger.info(`Analyzing test health from state file: ${args.stateFile}`);
            // Load UnifiedAnalysisState from state file
            const stateManager = StateManager.fromStatePath(args.stateFile);
            const stateData = await stateManager.readData();
            const fullState = await stateManager.readFullState();
            const repositoryPath = fullState?.metadata.repositoryPath || "";
            if (!stateData) {
                return toolError(`State file is empty or invalid: ${args.stateFile}. Call skyramp_analyze_changes first to generate a valid state file.`);
            }
            if (!repositoryPath || typeof repositoryPath !== "string") {
                return toolError(`repositoryPath not found in state file metadata. The state file was likely created by an older version — re-run skyramp_analyze_changes to regenerate it.`);
            }
            // Skyramp tests: full drift analysis + all actions permitted.
            // Relevant external tests (user-written, relevant to this PR's endpoints): drift analysis
            //   + UPDATE only — REGENERATE and DELETE are report-only (enforced in skyramp_actions).
            // Other external tests: excluded entirely (deduplication only, not analysed).
            // relevantExternalTestPaths are stored relative to repositoryPath in the state file.
            // Re-absolutize here so has() comparisons against t.testFile (absolute) work correctly.
            const relevantExternalPaths = new Set((stateData.repositoryAnalysis?.relevantExternalTestPaths ?? []).map((p) => path.isAbsolute(p) ? p : path.resolve(repositoryPath, p)));
            const existingTests = (stateData.existingTests || []).filter((t) => {
                if ((t.source ?? TestSource.Skyramp) !== TestSource.External)
                    return true;
                return relevantExternalPaths.has(t.testFile);
            });
            const skyrampCount = existingTests.filter((t) => (t.source ?? TestSource.Skyramp) !== TestSource.External).length;
            const externalCount = existingTests.length - skyrampCount;
            logger.info(`Loaded ${skyrampCount} Skyramp + ${externalCount} relevant external tests from state file`);
            const absoluteRepoPath = path.resolve(repositoryPath);
            const scannedEndpoints = stateData.repositoryAnalysis?.skeletonEndpoints || [];
            const routerMountContext = stateData.repositoryAnalysis?.routerMountContext;
            const candidateRouteFiles = stateData.repositoryAnalysis?.candidateRouteFiles;
            const diffFilePath = stateData.repositoryAnalysis?.diffFilePath;
            // Sweep stale diff files on this natural follow-up call so they don't accumulate.
            // Pass [] for stateTypes so only skyramp-diff-*.diff files are deleted — state files
            // (skyramp-analysis-*, skyramp-recommendation-*) must not be removed here because the
            // caller still needs args.stateFile to pass to skyramp_actions.
            try {
                await StateManager.cleanupOldFiles(24, undefined, []);
            }
            catch (error) {
                logger.warning(`Failed to cleanup old diff files: ${error.message}`);
            }
            const promptText = buildDriftAnalysisPrompt({
                existingTests,
                scannedEndpoints,
                repositoryPath: absoluteRepoPath,
                stateFile: stateManager.getStatePath(),
                routerMountContext,
                candidateRouteFiles,
                diffFilePath,
                relevantExternalTestPaths: [...relevantExternalPaths],
            });
            return {
                structuredContent: { prompt: promptText },
                content: [{ type: "text", text: "Drift analysis prompt generated. Follow the prompt field to assess each test." }],
            };
        }
        catch (error) {
            logger.error(`Test health analysis failed: ${error.message}`, error);
            errorResult = toolError(`Test health analysis failed: ${error.message}`);
            return errorResult;
        }
        finally {
            AnalyticsService.pushMCPToolEvent(TOOL_NAME, errorResult, {});
        }
    });
}
