"use strict";
/**
 * Voice-Over Script Extractor Agent
 *
 * Extracts text from screenshots and generates professional narration scripts
 * with timestamps. Supports multiple narration styles and optional TTS integration.
 *
 * Communicates via Living Brain (context.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;
    };
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.VOScriptExtractorAgent = void 0;
const gemini_vision_1 = require("../../services/gemini-vision");
const ContextService_1 = require("../../services/ContextService");
const AICore_1 = require("../../core/ai/AICore");
const uuid_1 = require("uuid");
const fs = __importStar(require("fs-extra"));
const path = __importStar(require("path"));
const chalk_1 = __importDefault(require("chalk"));
class VOScriptExtractorAgent {
    constructor() {
        this.name = "VOScriptExtractorAgent";
        this.description = "Extracts text from screenshots and generates professional narration scripts";
        this.personality = `You are a professional voice-over artist and scriptwriter.
You write engaging, clear narration that guides viewers through demos smoothly. Your scripts
are natural, informative, and adapt to different audiences - from technical developers to
business stakeholders.`;
        this.llmProvider = "gemini-vision";
        this.expertise = [
            "Script writing",
            "Text extraction",
            "Narration generation",
            "Timing coordination",
            "TTS integration",
        ];
        this.visionService = new gemini_vision_1.GeminiVisionService();
    }
    async run(input) {
        const { steps, missionName, missionDescription, narrationStyle = "technical", projectPath, outputPath, generateAudio, ttsConfig, } = input;
        // Initialize context service
        this.contextService = new ContextService_1.ContextService(projectPath);
        await this.contextService.initialize();
        console.log(chalk_1.default.blue(`\n🎙️  ${this.name} generating narration...`));
        console.log(chalk_1.default.gray(`Style: ${narrationStyle}`));
        console.log(chalk_1.default.gray(`Steps: ${steps.length}`));
        try {
            // Generate VO segments for each step
            const segments = [];
            let totalDuration = 0;
            for (let i = 0; i < steps.length; i++) {
                const step = steps[i];
                if (!step)
                    continue;
                console.log(chalk_1.default.cyan(`\n  📝 Segment ${i + 1}/${steps.length}`));
                const segment = await this.generateSegment(step, i, narrationStyle, totalDuration);
                segments.push(segment);
                totalDuration += segment.duration;
                console.log(chalk_1.default.gray(`     "${segment.narration}"`));
            }
            // Build full script
            const fullScript = this.buildFullScript(segments, missionName, missionDescription, narrationStyle);
            // Create VOScript object
            const voScript = {
                title: missionName,
                totalDuration,
                segments,
                fullScript,
            };
            // Save script to file
            await fs.ensureDir(path.dirname(outputPath));
            await fs.writeFile(outputPath, JSON.stringify(voScript, null, 2), "utf-8");
            // Also save as human-readable markdown
            const mdPath = outputPath.replace(".json", ".md");
            await fs.writeFile(mdPath, fullScript, "utf-8");
            console.log(chalk_1.default.green(`\n  ✓ Script saved to ${outputPath}`));
            // Generate audio if requested
            let audioPath;
            if (generateAudio && ttsConfig) {
                console.log(chalk_1.default.cyan(`\n  🔊 Generating audio...`));
                audioPath = await this.generateAudio(voScript, ttsConfig, outputPath);
                console.log(chalk_1.default.green(`  ✓ Audio saved to ${audioPath}`));
            }
            // Write to Living Brain
            await this.writeLivingBrain({
                timestamp: new Date().toISOString(),
                agentName: this.name,
                updateType: "demo-generated",
                data: {
                    scriptPath: outputPath,
                    audioPath,
                    segmentCount: segments.length,
                    totalDuration,
                },
            });
            console.log(chalk_1.default.blue(`\n🎉 Narration script complete!`));
            return {
                script: voScript,
                scriptPath: outputPath,
                audioPath,
                success: true,
            };
        }
        catch (error) {
            console.error(chalk_1.default.red(`\n❌ Script generation error: ${error.message}`));
            // Write error to Living Brain
            await this.writeLivingBrain({
                timestamp: new Date().toISOString(),
                agentName: this.name,
                updateType: "error",
                data: {
                    error: error.message,
                    stack: error.stack,
                },
            });
            return {
                script: {
                    title: missionName,
                    totalDuration: 0,
                    segments: [],
                    fullScript: "",
                },
                scriptPath: outputPath,
                success: false,
                error: error.message,
            };
        }
    }
    /**
     * Generate a single narration segment
     */
    async generateSegment(step, index, narrationStyle, currentTime) {
        try {
            // Extract text from screenshot if available
            let textOnScreen = [];
            let uiState = "UI state unknown";
            if (step.screenshot && (await fs.pathExists(step.screenshot))) {
                const extracted = await this.extractTextFromScreenshot(step.screenshot);
                textOnScreen = extracted.textElements;
                uiState = extracted.summary;
            }
            else if (step.visualAnalysis) {
                textOnScreen = step.visualAnalysis.textContent || [];
                uiState = step.visualAnalysis.interactiveElements.join(", ");
            }
            // Generate narration based on style
            const narration = await this.generateNarration(step, textOnScreen, uiState, narrationStyle);
            // Estimate duration (roughly 150 words per minute)
            const wordCount = narration.split(/\s+/).length;
            const duration = (wordCount / 150) * 60; // seconds
            const segment = {
                id: (0, uuid_1.v4)(),
                timestamp: currentTime,
                duration: Math.max(duration, 3), // Minimum 3 seconds per segment
                narration,
                action: step.action,
                screenshot: step.screenshot,
                metadata: {
                    step: index + 1,
                    uiState,
                    textOnScreen,
                },
            };
            return segment;
        }
        catch (error) {
            // Fallback segment
            return {
                id: (0, uuid_1.v4)(),
                timestamp: currentTime,
                duration: 3,
                narration: `Step ${index + 1}: ${step.action}`,
                action: step.action,
                screenshot: step.screenshot,
                metadata: {
                    step: index + 1,
                    uiState: "unknown",
                    textOnScreen: [],
                },
            };
        }
    }
    /**
     * Extract text from screenshot using vision AI
     */
    async extractTextFromScreenshot(screenshotPath) {
        try {
            // Use Gemini Vision to extract text
            const imageData = await fs.readFile(screenshotPath);
            const base64Image = imageData.toString("base64");
            const { GoogleGenerativeAI } = require("@google/generative-ai");
            const apiKey = process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY;
            if (!apiKey) {
                throw new Error("Gemini API key not found");
            }
            const genAI = new GoogleGenerativeAI(apiKey);
            const model = genAI.getGenerativeModel({ model: "gemini-2.0-flash" });
            const prompt = `Extract all visible text from this screenshot.

Return JSON:
{
  "textElements": ["text 1", "text 2", ...],
  "summary": "Brief description of what's on screen"
}`;
            const result = await model.generateContent([
                prompt,
                {
                    inlineData: {
                        data: base64Image,
                        mimeType: "image/png",
                    },
                },
            ]);
            const response = await result.response;
            const text = response.text();
            // Extract JSON
            const jsonMatch = text.match(/```json\n([\s\S]*?)\n```/);
            const jsonText = jsonMatch ? jsonMatch[1] : text;
            const parsed = JSON.parse(jsonText);
            return parsed;
        }
        catch (error) {
            console.warn("Text extraction failed:", error);
            return {
                textElements: [],
                summary: "Could not extract text",
            };
        }
    }
    /**
     * Generate narration for a step
     */
    async generateNarration(step, textOnScreen, uiState, style) {
        const styleGuidance = {
            technical: "Use precise, technical language. Focus on actions and outcomes.",
            casual: "Use conversational, friendly language. Make it relatable and easy to follow.",
            marketing: "Use persuasive, benefit-focused language. Highlight features and value.",
            educational: "Use clear, instructive language. Explain why and how things work.",
        };
        const prompt = `You are writing voice-over narration for a demo video.

**Style**: ${style} - ${styleGuidance[style] || styleGuidance.technical}

**Current Step**: ${step.action}
**Intent**: ${step.intent}
${step.visionDecision ? `**Reasoning**: ${step.visionDecision.reasoning}` : ""}

**UI State**: ${uiState}
**Text visible on screen**: ${textOnScreen.join(", ") || "None"}

Write 1-2 sentences of narration for this step. Be natural and engaging.
Do NOT include any formatting, just the plain narration text.`;
        try {
            const aiCore = AICore_1.AICore.getInstance();
            const narration = await aiCore.generateText(prompt, {
                temperature: 0.7,
            });
            return narration.trim();
        }
        catch (error) {
            console.warn("Narration generation failed, using fallback:", error);
            return this.generateFallbackNarration(step, style);
        }
    }
    /**
     * Generate fallback narration
     */
    generateFallbackNarration(step, style) {
        const templates = {
            technical: `Now we ${step.action.toLowerCase()}. ${step.intent}`,
            casual: `Let's ${step.action.toLowerCase()}. ${step.intent}`,
            marketing: `Watch as we ${step.action.toLowerCase()}, ${step.intent}`,
            educational: `In this step, we'll ${step.action.toLowerCase()}. ${step.intent}`,
        };
        return (templates[style] || templates.technical);
    }
    /**
     * Build full script markdown
     */
    buildFullScript(segments, title, description, style) {
        const lines = [
            `# ${title} - Voice-Over Script`,
            "",
            description || "",
            "",
            `**Style**: ${style || "technical"}`,
            `**Duration**: ${this.formatDuration(segments.reduce((sum, s) => sum + s.duration, 0))}`,
            `**Segments**: ${segments.length}`,
            "",
            "---",
            "",
            "## Narration",
            "",
        ];
        segments.forEach((segment, index) => {
            lines.push(`### Segment ${index + 1} [${this.formatTimestamp(segment.timestamp)}]`);
            lines.push("");
            lines.push(`**Action**: ${segment.action}`);
            lines.push(`**Duration**: ${segment.duration.toFixed(1)}s`);
            lines.push("");
            lines.push(segment.narration);
            lines.push("");
            lines.push("---");
            lines.push("");
        });
        return lines.join("\n");
    }
    /**
     * Generate audio using TTS
     */
    async generateAudio(script, ttsConfig, outputPath) {
        // Placeholder for TTS integration
        // In production, would integrate with:
        // - Google Cloud Text-to-Speech
        // - ElevenLabs API
        // - Local TTS engines
        const audioPath = outputPath.replace(".json", ".mp3");
        console.log(chalk_1.default.yellow(`    ℹ️  Audio generation not yet implemented. Would use ${ttsConfig?.provider}`));
        // For now, just create an empty placeholder file
        await fs.writeFile(audioPath, "Audio generation placeholder", "utf-8");
        return audioPath;
    }
    /**
     * Format timestamp as MM:SS
     */
    formatTimestamp(seconds) {
        const mins = Math.floor(seconds / 60);
        const secs = Math.floor(seconds % 60);
        return `${mins.toString().padStart(2, "0")}:${secs.toString().padStart(2, "0")}`;
    }
    /**
     * Format duration as human-readable string
     */
    formatDuration(seconds) {
        const mins = Math.floor(seconds / 60);
        const secs = Math.floor(seconds % 60);
        if (mins > 0) {
            return `${mins}m ${secs}s`;
        }
        return `${secs}s`;
    }
    /**
     * Write update to Living Brain
     */
    async writeLivingBrain(update) {
        try {
            // Read current context using AICore
            const aiCore = AICore_1.AICore.getInstance();
            const currentContext = (await aiCore.getLivingContext()) || {};
            if (!currentContext.testExecutionHistory) {
                currentContext.testExecutionHistory = [];
            }
            currentContext.testExecutionHistory.push(update);
            if (currentContext.testExecutionHistory.length > 100) {
                currentContext.testExecutionHistory = currentContext.testExecutionHistory.slice(-100);
            }
            // Save back to context.json using AICore
            await aiCore.saveLivingContext(currentContext);
        }
        catch (error) {
            console.warn("Failed to write to Living Brain:", error);
        }
    }
    async validate(input) {
        return !!(input.steps &&
            input.missionName &&
            input.projectPath &&
            input.outputPath);
    }
    async getStatus() {
        return {
            name: this.name,
            status: "idle",
            errorCount: 0,
            successCount: 0,
        };
    }
}
exports.VOScriptExtractorAgent = VOScriptExtractorAgent;
//# sourceMappingURL=VOScriptExtractorAgent.js.map