/**
 * VLCompile Tool - compiles the VL project via parsevl API
 * Reads gid from Config/ProjectConfig, then calls /api/compile.
 */
import fs from 'fs';
import path from 'path';

export function createVLCompileTool(config) {
  return {
    name: 'VLCompile',
    description: `Compile the VL project by calling the parsevl API. Reads the project gid from Config/ProjectConfig automatically. Returns preview URLs and any compile errors.`,
    parameters: {
      type: 'object',
      properties: {
        targetGid: { type: 'number', description: 'Project gid (optional — auto-read from Config/ProjectConfig if omitted)' },
        action: { type: 'string', enum: ['parsePjt', 'lintPjt'], description: 'Action: parsePjt (full compile) or lintPjt (lint only). Default: parsePjt' },
      },
      required: [],
    },
    execute: async (params = {}, runtime = {}) => {
      try {
        let targetGid = params.targetGid;
        runtime.info?.('VLCompile started', {
          action: params.action || 'parsePjt',
          targetGid: targetGid || null,
        });

        // Auto-read gid from Config/ProjectConfig
        if (!targetGid) {
          const configPath = path.join(config.workDir, 'Config', 'ProjectConfig');
          try {
            const content = fs.readFileSync(configPath, 'utf-8').trim();
            targetGid = parseInt(content, 10);
            if (isNaN(targetGid)) targetGid = null;
            else runtime.info?.('VLCompile resolved project gid from ProjectConfig', { targetGid });
          } catch { /* no ProjectConfig file */ }
        }

        // No GID = first-time compile; Lambda will create a new project and return the GID.

        const port = config.port || 3200;
        const res = await fetch(`http://localhost:${port}/api/compile`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            targetGid: targetGid || undefined,
            action: params.action || 'parsePjt',
            download: true,
          }),
        });

        // The compile endpoint returns SSE — collect all events
        const text = await res.text();
        const events = text.split('\n\n').filter(Boolean);
        let result = null;
        let error = null;
        let compilationStatus = null;

        for (const block of events) {
          const eventMatch = block.match(/^event:\s*(.+)/m);
          const dataMatch = block.match(/^data:\s*(.+)/m);
          if (!eventMatch || !dataMatch) continue;
          const eventType = eventMatch[1].trim();
          try {
            const data = JSON.parse(dataMatch[1]);
            if (eventType === 'status') {
              compilationStatus = data;
              runtime.progress?.('Compile status', data);
            }
            if (eventType === 'result') {
              result = data;
              runtime.info?.('Compile result received', {
                code: data?.code ?? null,
                success: data?.success ?? null,
              });
            }
            if (eventType === 'error') {
              error = data;
              runtime.error?.('Compile endpoint returned error event', data);
            }
          } catch {}
        }

        if (error) {
          runtime.error?.('VLCompile failed', {
            error: error.message || error,
          });
          return JSON.stringify({ success: false, error: error.message || error });
        }

        if (result) {
          const returnedGid = result.data?.gid || targetGid;
          // Auto-save GID to Config/ProjectConfig so subsequent compiles reuse this project
          if (returnedGid && !targetGid) {
            try {
              const configDir = path.join(config.workDir, 'Config');
              if (!fs.existsSync(configDir)) fs.mkdirSync(configDir, { recursive: true });
              fs.writeFileSync(path.join(configDir, 'ProjectConfig'), String(returnedGid));
              runtime.info?.('VLCompile persisted new project gid', { gid: returnedGid });
            } catch { /* non-fatal */ }
          }
          const diagnostics = Array.isArray(result.data?.errList) ? result.data.errList : [];
          const hardErrors = diagnostics.filter(item => String(item?.level || '').toLowerCase() !== 'warning');
          const warnings = diagnostics.filter(item => String(item?.level || '').toLowerCase() === 'warning');
          const errCount = hardErrors.length;
          const warningCount = warnings.length;
          // Only declare failure when there are real compile errors.
          const compiledOk = (compilationStatus?.status === 'success' || result.code === 0 || result.code === 200 || result.success === true) && errCount === 0;
          const out = {
            success: compiledOk,
            gid: returnedGid,
            errCount,
            warningCount,
          };
          if (!compiledOk && errCount === 0) {
            out.error = result.message || 'Compilation did not succeed';
          }
          if (compiledOk) {
            if (result.data?.apps?.frontends) {
              out.previewUrls = {};
              for (const [appFile, info] of Object.entries(result.data.apps.frontends)) {
                out.previewUrls[appFile] = info.previewUrl;
              }
            } else if (result.data?.appPreviewUrlMap) {
              out.previewUrls = result.data.appPreviewUrlMap;
            }
          }
          if (diagnostics.length > 0) {
            out.errList = diagnostics.slice(0, 20);
          }
          if (warningCount > 0) {
            runtime.warn?.('Compile produced warnings', {
              gid: returnedGid || null,
              warningCount,
              errCount,
            });
          }
          runtime.info?.('VLCompile finished', {
            gid: returnedGid || null,
            success: compiledOk,
            errCount,
            warningCount,
            previewCount: Object.keys(out.previewUrls || {}).length,
          });
          return JSON.stringify(out, null, 2);
        }

        runtime.error?.('VLCompile returned no result', {});
        return JSON.stringify({ success: false, error: 'No result received from compile endpoint' });
      } catch (e) {
        runtime.error?.('VLCompile crashed', { error: e.message });
        return JSON.stringify({ success: false, error: e.message });
      }
    },
  };
}
