'use strict';

/**
 * Fabius Workflow Generator & Distributor
 * 
 * Uses AI to generate agent workflow files for each threat,
 * then distributes them to managed repositories.
 */

const fs = require('fs');
const path = require('path');

class WorkflowManager {
  /**
   * @param {object} options
   * @param {import('../registry/db')} options.db
   * @param {import('../ai/provider')} options.ai
   */
  constructor(options) {
    this.db = options.db;
    this.ai = options.ai;

    // Load existing workflow as template reference
    this.templateWorkflow = '';
    try {
      const templatePath = path.resolve(__dirname, '../../../.agent/workflows/scan-glassworm.md');
      if (fs.existsSync(templatePath)) {
        this.templateWorkflow = fs.readFileSync(templatePath, 'utf-8');
      }
    } catch { /* ok */ }
  }

  /**
   * Generate scan and protect workflows for a threat
   * @param {string} threatId
   * @returns {Promise<{scan: object, protect: object}>}
   */
  async generateForThreat(threatId) {
    const threat = this.db.getThreat(threatId);
    if (!threat) throw new Error(`Threat not found: ${threatId}`);

    const slug = this._slugify(threat.name);
    const results = {};

    // 1. Generate scan workflow
    const scanContent = await this.ai.generateWorkflow(
      {
        name: threat.name,
        description: threat.description,
        severity: threat.severity,
        ecosystems: threat.ecosystems,
        affectedPackages: threat.affectedPackages,
        attack_vector: threat.attack_vector,
      },
      this.templateWorkflow
    );

    const scanFilename = `scan-${slug}.md`;
    const scanId = this.db.addWorkflow(threatId, scanFilename, scanContent, 'scan');
    results.scan = { id: scanId, filename: scanFilename, content: scanContent };

    // 2. Generate protect/add workflow
    const protectPrompt = `Generate a PROTECTION workflow (not scan) for this threat. 
The workflow should add protection hooks, pin safe versions, or install monitoring 
for the threat. Follow the same format as the scan workflow.`;

    const protectContent = await this.ai.generateWorkflow(
      {
        name: threat.name,
        description: threat.description + '\n\n' + protectPrompt,
        severity: threat.severity,
        ecosystems: threat.ecosystems,
        affectedPackages: threat.affectedPackages,
        attack_vector: threat.attack_vector,
      },
      this.templateWorkflow
    );

    const protectFilename = `add-${slug}.md`;
    const protectId = this.db.addWorkflow(threatId, protectFilename, protectContent, 'protect');
    results.protect = { id: protectId, filename: protectFilename, content: protectContent };

    return results;
  }

  /**
   * Generate detection code for a threat via AI
   * @param {string} threatId
   * @returns {Promise<{id: number, code: string}>}
   */
  async generateDetection(threatId) {
    const threat = this.db.getThreat(threatId);
    if (!threat) throw new Error(`Threat not found: ${threatId}`);

    // Load existing scanner as reference
    let referenceCode = '';
    try {
      const scannerPath = path.resolve(__dirname, '../../../src/scanner.js');
      if (fs.existsSync(scannerPath)) {
        referenceCode = fs.readFileSync(scannerPath, 'utf-8');
      }
    } catch { /* ok */ }

    const code = await this.ai.generateDetectionCode(
      {
        name: threat.name,
        description: threat.description,
        severity: threat.severity,
        affectedPackages: threat.affectedPackages,
        attack_vector: threat.attack_vector,
      },
      referenceCode
    );

    const detectionId = this.db.addDetection(threatId, code);
    return { id: detectionId, code };
  }

  /**
   * Distribute all latest workflows to a repository
   * @param {string} repoId
   */
  distributeToRepo(repoId) {
    const repo = this.db.getRepo(repoId);
    if (!repo) throw new Error(`Repository not found: ${repoId}`);

    const workflows = this.db.getAllLatestWorkflows();
    if (!workflows.length) return { distributed: 0 };

    const workflowDir = path.join(repo.path, '.agent', 'workflows');

    // Create directory if it doesn't exist
    if (!fs.existsSync(workflowDir)) {
      fs.mkdirSync(workflowDir, { recursive: true });
    }

    let distributed = 0;
    for (const wf of workflows) {
      try {
        const filePath = path.join(workflowDir, wf.filename);
        fs.writeFileSync(filePath, wf.content, 'utf-8');
        this.db.markWorkflowDistributed(wf.id, repoId);
        distributed++;
      } catch (err) {
        console.warn(`[Fabius Workflow] Failed to distribute ${wf.filename} to ${repo.name}: ${err.message}`);
      }
    }

    this.db.audit('workflows_distributed', 'repository', repoId, { count: distributed });
    return { distributed };
  }

  /**
   * Distribute all latest workflows to ALL managed repositories
   */
  distributeToAll() {
    const repos = this.db.listRepos();
    const results = [];
    for (const repo of repos) {
      try {
        const result = this.distributeToRepo(repo.id);
        results.push({ repoId: repo.id, repoName: repo.name, ...result });
      } catch (err) {
        results.push({ repoId: repo.id, repoName: repo.name, error: err.message });
      }
    }
    return results;
  }

  _slugify(text) {
    return text
      .toLowerCase()
      .replace(/[^a-z0-9]+/g, '-')
      .replace(/^-|-$/g, '')
      .slice(0, 40);
  }
}

module.exports = WorkflowManager;
