"use strict";
/**
 * Context Validator Service
 *
 * Detects gaps in context files and tracks auto-generated features
 * to ensure user approval before proceeding with generation.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.ContextValidator = void 0;
class ContextValidator {
    constructor() {
        this.gaps = [];
        this.autoGeneratedFeatures = [];
    }
    /**
     * Validate context files for completeness and detect gaps
     */
    async validateContext(contextFiles) {
        this.gaps = [];
        this.autoGeneratedFeatures = [];
        // Analyze PRD for gaps
        if (contextFiles.prd) {
            this.analyzePRDGaps(contextFiles.prd);
        }
        // Analyze description for gaps
        if (contextFiles.description) {
            this.analyzeDescriptionGaps(contextFiles.description);
        }
        // Analyze tech stack for gaps
        if (contextFiles.techStack) {
            this.analyzeTechStackGaps(contextFiles.techStack);
        }
        // Deduplicate gaps by ID
        this.gaps = this.deduplicateGaps(this.gaps);
        // Deduplicate features by ID
        this.autoGeneratedFeatures = this.deduplicateFeatures(this.autoGeneratedFeatures);
        const hasCriticalGaps = this.gaps.some((gap) => gap.category === "critical");
        const canProceed = !hasCriticalGaps;
        return {
            gaps: this.gaps,
            autoGeneratedFeatures: this.autoGeneratedFeatures,
            hasCriticalGaps,
            canProceed,
        };
    }
    /**
     * Deduplicate gaps by ID
     */
    deduplicateGaps(gaps) {
        const seen = new Set();
        return gaps.filter((gap) => {
            if (seen.has(gap.id))
                return false;
            seen.add(gap.id);
            return true;
        });
    }
    /**
     * Deduplicate features by ID
     */
    deduplicateFeatures(features) {
        const seen = new Set();
        return features.filter((feature) => {
            if (seen.has(feature.id))
                return false;
            seen.add(feature.id);
            return true;
        });
    }
    /**
     * Analyze PRD for missing critical information
     */
    analyzePRDGaps(prd) {
        const prdLower = prd.toLowerCase();
        // Check for game-related gaps
        if (this.containsGameKeywords(prdLower)) {
            this.checkGameGaps(prdLower, "prd");
        }
        // Check for user authentication gaps
        if (this.mentionsUsers(prdLower) && !this.mentionsAuth(prdLower)) {
            this.gaps.push({
                id: "auth-method",
                category: "critical",
                question: "How should users authenticate?",
                context: "prd",
                suggestedAnswers: [
                    "Email/password",
                    "Social login (Google, GitHub)",
                    "Magic link",
                    "No authentication needed",
                ],
                reasoning: "PRD mentions users but no authentication method specified",
            });
        }
        // Check for database gaps
        if (this.mentionsDataPersistence(prdLower) &&
            !this.mentionsDatabase(prdLower)) {
            this.gaps.push({
                id: "database-choice",
                category: "critical",
                question: "What database should be used?",
                context: "prd",
                suggestedAnswers: [
                    "InstantDB (recommended)",
                    "PostgreSQL",
                    "MongoDB",
                    "SQLite",
                    "No database needed",
                ],
                reasoning: "PRD mentions data persistence but no database specified",
            });
        }
        // Check for payment gaps
        if (this.mentionsPayments(prdLower)) {
            this.gaps.push({
                id: "payment-method",
                category: "critical",
                question: "What payment method should be integrated?",
                context: "prd",
                suggestedAnswers: [
                    "Stripe",
                    "PayPal",
                    "Apple Pay",
                    "Google Pay",
                    "Other",
                ],
                reasoning: "PRD mentions payments but no payment method specified",
            });
        }
    }
    /**
     * Analyze initial description for gaps
     */
    analyzeDescriptionGaps(description) {
        const descLower = description.toLowerCase();
        // Check for vague game descriptions
        if (this.isVagueGameDescription(descLower)) {
            this.checkGameGaps(descLower, "description");
        }
        // Check for vague app descriptions
        if (this.isVagueAppDescription(descLower)) {
            this.gaps.push({
                id: "app-purpose",
                category: "critical",
                question: "What is the main purpose of this app?",
                context: "description",
                suggestedAnswers: [
                    "Productivity tool",
                    "Social platform",
                    "E-commerce store",
                    "Educational platform",
                    "Entertainment app",
                    "Other",
                ],
                reasoning: "Description is too vague to determine app purpose",
            });
        }
        // Check for missing target audience
        if (this.mentionsUsers(descLower) &&
            !this.mentionsTargetAudience(descLower)) {
            this.gaps.push({
                id: "target-audience",
                category: "important",
                question: "Who is the target audience?",
                context: "description",
                suggestedAnswers: [
                    "General public",
                    "Business professionals",
                    "Students",
                    "Developers",
                    "Specific industry",
                    "Other",
                ],
                reasoning: "App mentions users but target audience is unclear",
            });
        }
    }
    /**
     * Analyze tech stack for gaps
     */
    analyzeTechStackGaps(techStack) {
        const techLower = techStack.toLowerCase();
        // Check for missing deployment strategy
        if (!this.mentionsDeployment(techLower)) {
            this.gaps.push({
                id: "deployment-strategy",
                category: "important",
                question: "How should the app be deployed?",
                context: "tech-stack",
                suggestedAnswers: [
                    "Vercel (recommended for Next.js)",
                    "Netlify",
                    "AWS",
                    "Railway",
                    "Self-hosted",
                    "Other",
                ],
                reasoning: "Tech stack specified but no deployment strategy mentioned",
            });
        }
        // Check for missing environment configuration
        if (!this.mentionsEnvironmentConfig(techLower)) {
            this.gaps.push({
                id: "environment-config",
                category: "optional",
                question: "What environment variables are needed?",
                context: "tech-stack",
                reasoning: "Consider adding environment configuration for API keys and secrets",
            });
        }
    }
    /**
     * Check for game-specific gaps
     */
    checkGameGaps(text, context) {
        // Game type gap
        this.gaps.push({
            id: "game-type",
            category: "critical",
            question: "What type of game is this?",
            context: context,
            suggestedAnswers: [
                "Turn-based (Tic-tac-toe, Chess)",
                "Real-time (Racing, Shooting)",
                "Puzzle (Matching, Strategy)",
                "Card game",
                "Board game",
                "Other",
            ],
            reasoning: "Game mentioned but type not specified",
        });
        // Game rules gap
        this.gaps.push({
            id: "game-rules",
            category: "critical",
            question: "What are the core game rules?",
            context: context,
            reasoning: "Game rules need to be defined for proper implementation",
        });
        // Multiplayer gap
        if (this.mentionsMultiplayer(text)) {
            this.autoGeneratedFeatures.push({
                id: "realtime-multiplayer",
                feature: "Real-time multiplayer with Socket.io",
                reasoning: "User mentioned playing against each other",
                confidence: "medium",
                contextSource: "description",
            });
        }
    }
    /**
     * Helper methods for text analysis
     */
    containsGameKeywords(text) {
        const gameKeywords = [
            "game",
            "play",
            "player",
            "score",
            "win",
            "lose",
            "match",
            "tournament",
        ];
        return gameKeywords.some((keyword) => text.includes(keyword));
    }
    mentionsUsers(text) {
        const userKeywords = [
            "user",
            "users",
            "player",
            "players",
            "member",
            "members",
            "account",
            "accounts",
        ];
        return userKeywords.some((keyword) => text.includes(keyword));
    }
    mentionsAuth(text) {
        const authKeywords = [
            "login",
            "signin",
            "signup",
            "register",
            "authentication",
            "auth",
            "password",
            "oauth",
        ];
        return authKeywords.some((keyword) => text.includes(keyword));
    }
    mentionsDataPersistence(text) {
        const dataKeywords = [
            "save",
            "store",
            "data",
            "database",
            "persist",
            "memory",
            "history",
            "record",
        ];
        return dataKeywords.some((keyword) => text.includes(keyword));
    }
    mentionsDatabase(text) {
        const dbKeywords = [
            "database",
            "db",
            "postgres",
            "mysql",
            "mongodb",
            "sqlite",
            "instantdb",
            "supabase",
        ];
        return dbKeywords.some((keyword) => text.includes(keyword));
    }
    mentionsPayments(text) {
        const paymentKeywords = [
            "payment",
            "pay",
            "buy",
            "purchase",
            "subscription",
            "billing",
            "stripe",
            "paypal",
        ];
        return paymentKeywords.some((keyword) => text.includes(keyword));
    }
    isVagueGameDescription(text) {
        const vaguePatterns = [
            "fun game",
            "simple game",
            "game where",
            "play against",
            "multiplayer game",
        ];
        return vaguePatterns.some((pattern) => text.includes(pattern));
    }
    isVagueAppDescription(text) {
        const vaguePatterns = [
            "simple app",
            "basic app",
            "useful app",
            "helpful app",
            "cool app",
        ];
        return vaguePatterns.some((pattern) => text.includes(pattern));
    }
    mentionsTargetAudience(text) {
        const audienceKeywords = [
            "for",
            "target",
            "audience",
            "users",
            "people",
            "business",
            "students",
            "developers",
        ];
        return audienceKeywords.some((keyword) => text.includes(keyword));
    }
    mentionsMultiplayer(text) {
        const multiplayerKeywords = [
            "against each other",
            "multiplayer",
            "together",
            "compete",
            "versus",
            "vs",
        ];
        return multiplayerKeywords.some((keyword) => text.includes(keyword));
    }
    mentionsDeployment(text) {
        const deploymentKeywords = [
            "deploy",
            "hosting",
            "vercel",
            "netlify",
            "aws",
            "railway",
            "production",
        ];
        return deploymentKeywords.some((keyword) => text.includes(keyword));
    }
    mentionsEnvironmentConfig(text) {
        const envKeywords = [
            "environment",
            "env",
            "config",
            "variables",
            "secrets",
            "api key",
        ];
        return envKeywords.some((keyword) => text.includes(keyword));
    }
    /**
     * Get gaps by category
     */
    getGapsByCategory(category) {
        return this.gaps.filter((gap) => gap.category === category);
    }
    /**
     * Get auto-generated features by confidence
     */
    getFeaturesByConfidence(confidence) {
        return this.autoGeneratedFeatures.filter((feature) => feature.confidence === confidence);
    }
    /**
     * Add auto-generated feature
     */
    addAutoGeneratedFeature(feature) {
        const id = this.generateFeatureId(feature.feature);
        this.autoGeneratedFeatures.push({
            id,
            ...feature,
        });
    }
    /**
     * Generate unique ID for feature
     */
    generateFeatureId(feature) {
        return feature
            .toLowerCase()
            .replace(/[^a-z0-9\s]/g, "")
            .replace(/\s+/g, "-")
            .substring(0, 50);
    }
}
exports.ContextValidator = ContextValidator;
//# sourceMappingURL=ContextValidator.js.map