"use strict";
/**
 * Test Mission Manager
 *
 * Handles CRUD operations for test missions and execution history.
 * Stores missions in .mycontext/test-missions.json
 */
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.TestMissionManager = void 0;
const fs = __importStar(require("fs-extra"));
const path = __importStar(require("path"));
const uuid_1 = require("uuid");
class TestMissionManager {
    constructor(projectPath) {
        this.projectPath = projectPath;
        this.storageFile = path.join(projectPath, ".mycontext", "test-missions.json");
        this.storage = this.loadStorage();
    }
    /**
     * Load test missions from storage
     */
    loadStorage() {
        try {
            if (fs.existsSync(this.storageFile)) {
                return fs.readJsonSync(this.storageFile);
            }
        }
        catch (error) {
            console.warn("Failed to load test missions storage, creating new one");
        }
        // Return default storage structure
        return {
            version: "1.0.0",
            createdAt: new Date().toISOString(),
            updatedAt: new Date().toISOString(),
            missions: [],
            executionHistory: [],
        };
    }
    /**
     * Save storage to disk
     */
    async saveStorage() {
        this.storage.updatedAt = new Date().toISOString();
        await fs.ensureDir(path.dirname(this.storageFile));
        await fs.writeJson(this.storageFile, this.storage, { spaces: 2 });
    }
    /**
     * Create a new test mission
     */
    async createMission(config) {
        const now = new Date().toISOString();
        const newMission = {
            id: (0, uuid_1.v4)(),
            name: config.name,
            description: config.mission,
            mission: config.mission,
            expectedOutcome: config.expectedOutcome,
            validationRules: config.validationRules || [],
            tags: config.tags || [],
            createdAt: now,
            updatedAt: now,
        };
        this.storage.missions.push(newMission);
        await this.saveStorage();
        return newMission;
    }
    /**
     * Get a mission by ID or name
     */
    async getMission(idOrName) {
        const mission = this.storage.missions.find((m) => m.id === idOrName || m.name === idOrName);
        return mission || null;
    }
    /**
     * List all missions with optional filters
     */
    async listMissions(filters) {
        let missions = [...this.storage.missions];
        // Filter by tag if specified
        if (filters?.tag) {
            missions = missions.filter((m) => m.tags && m.tags.includes(filters.tag));
        }
        // Filter by last execution status if specified
        if (filters?.status && filters.status !== "all") {
            missions = missions.filter((m) => {
                const history = this.storage.executionHistory.find((h) => h.missionId === m.id);
                if (!history || history.executions.length === 0)
                    return false;
                const lastExecution = history.executions[history.executions.length - 1];
                if (!lastExecution)
                    return false;
                return filters.status === "passing"
                    ? lastExecution.status === "passed"
                    : lastExecution.status === "failed";
            });
        }
        return missions;
    }
    /**
     * Update a mission
     */
    async updateMission(id, updates) {
        const index = this.storage.missions.findIndex((m) => m.id === id);
        if (index === -1) {
            return null;
        }
        const updated = {
            ...this.storage.missions[index],
            ...updates,
            updatedAt: new Date().toISOString(),
        };
        this.storage.missions[index] = updated;
        await this.saveStorage();
        return this.storage.missions[index];
    }
    /**
     * Delete a mission
     */
    async deleteMission(id) {
        const index = this.storage.missions.findIndex((m) => m.id === id);
        if (index === -1) {
            return false;
        }
        this.storage.missions.splice(index, 1);
        // Also remove execution history
        const historyIndex = this.storage.executionHistory.findIndex((h) => h.missionId === id);
        if (historyIndex !== -1) {
            this.storage.executionHistory.splice(historyIndex, 1);
        }
        await this.saveStorage();
        return true;
    }
    /**
     * Save a test execution result
     */
    async saveExecution(result) {
        const historyIndex = this.storage.executionHistory.findIndex((h) => h.missionId === result.missionId);
        if (historyIndex === -1) {
            // Create new history entry
            this.storage.executionHistory.push({
                missionId: result.missionId,
                executions: [result],
            });
        }
        else {
            // Add to existing history
            const history = this.storage.executionHistory[historyIndex];
            if (history) {
                history.executions.push(result);
                // Keep only last 10 executions per mission
                if (history.executions.length > 10) {
                    history.executions = history.executions.slice(-10);
                }
            }
        }
        await this.saveStorage();
    }
    /**
     * Get execution history for a mission
     */
    async getExecutionHistory(missionId) {
        const history = this.storage.executionHistory.find((h) => h.missionId === missionId);
        return history ? history.executions : [];
    }
    /**
     * Get a specific execution by ID
     */
    async getExecution(executionId) {
        for (const history of this.storage.executionHistory) {
            const execution = history.executions.find((e) => e.executionId === executionId);
            if (execution) {
                return execution;
            }
        }
        return null;
    }
    /**
     * Get mission statistics
     */
    async getStatistics() {
        const totalMissions = this.storage.missions.length;
        const allExecutions = this.storage.executionHistory.flatMap((h) => h.executions);
        const totalExecutions = allExecutions.length;
        const passed = allExecutions.filter((e) => e.status === "passed").length;
        const passRate = totalExecutions > 0 ? (passed / totalExecutions) * 100 : 0;
        const durations = allExecutions
            .filter((e) => e.duration)
            .map((e) => e.duration);
        const averageDuration = durations.length > 0
            ? durations.reduce((sum, d) => sum + d, 0) / durations.length
            : 0;
        return {
            totalMissions,
            totalExecutions,
            passRate: Math.round(passRate),
            averageDuration: Math.round(averageDuration),
        };
    }
    /**
     * Import missions from MyContext user flows
     */
    async importFromUserFlows() {
        const userFlowsPath = path.join(this.projectPath, ".mycontext", "02-user-flows.md");
        if (!fs.existsSync(userFlowsPath)) {
            throw new Error("User flows file not found: 02-user-flows.md");
        }
        const content = await fs.readFile(userFlowsPath, "utf-8");
        const missions = [];
        // Simple parser to extract user flows
        // Format: Look for sections with steps
        const flowPattern = /###?\s+(.+)\n([\s\S]+?)(?=###|$)/g;
        let match;
        while ((match = flowPattern.exec(content)) !== null) {
            const [, title, body] = match;
            // Check if this section contains steps
            if (title && body && (body.includes("1.") || body.includes("- "))) {
                const mission = await this.createMission({
                    name: title.trim(),
                    mission: `Test the flow: ${title.trim()}`,
                    expectedOutcome: `User completes the ${title.trim()} flow successfully`,
                    tags: ["auto-generated", "from-user-flows"],
                });
                missions.push(mission);
            }
        }
        return missions;
    }
    /**
     * Import missions from a JSON file
     * Supports formats like tailor-cv-test-missions.json
     */
    async importFromJson(filePath) {
        // Resolve path relative to project root if not absolute
        const resolvedPath = path.isAbsolute(filePath)
            ? filePath
            : path.join(this.projectPath, filePath);
        if (!fs.existsSync(resolvedPath)) {
            throw new Error(`Test missions file not found: ${resolvedPath}`);
        }
        const data = await fs.readJson(resolvedPath);
        const missions = [];
        // Check if this is a missions collection file
        if (data.missions && Array.isArray(data.missions)) {
            // Import all missions from the collection
            for (const missionData of data.missions) {
                // Check if mission already exists (by ID or name)
                const existing = await this.getMission(missionData.id || missionData.name);
                if (existing) {
                    console.log(`Skipping duplicate mission: ${missionData.name}`);
                    continue;
                }
                const now = new Date().toISOString();
                const mission = {
                    id: missionData.id || (0, uuid_1.v4)(),
                    name: missionData.name,
                    description: missionData.description || missionData.mission,
                    mission: missionData.mission,
                    expectedOutcome: missionData.expectedOutcome,
                    validationRules: missionData.validationRules || [],
                    tags: missionData.tags || [],
                    createdAt: now,
                    updatedAt: now,
                    // Preserve additional metadata if present
                    ...(missionData.startUrl && { startUrl: missionData.startUrl }),
                    ...(missionData.testData && { testData: missionData.testData }),
                };
                this.storage.missions.push(mission);
                missions.push(mission);
            }
            await this.saveStorage();
            return missions;
        }
        // Handle single mission object
        if (data.name && data.mission) {
            const existing = await this.getMission(data.id || data.name);
            if (existing) {
                throw new Error(`Mission already exists: ${data.name}`);
            }
            const mission = await this.createMission({
                name: data.name,
                mission: data.mission,
                expectedOutcome: data.expectedOutcome || "Test completes successfully",
                validationRules: data.validationRules,
                startUrl: data.startUrl,
                tags: data.tags || ["imported"],
            });
            return [mission];
        }
        throw new Error("Invalid JSON format: Expected a mission object or a collection with 'missions' array");
    }
}
exports.TestMissionManager = TestMissionManager;
//# sourceMappingURL=test-mission-manager.js.map