const neo4j = require('neo4j-driver');
const { v4: uuidv4 } = require('uuid');

/**
 * Neo4j Namespace Service for Template Manager
 * Provides isolated Neo4j operations with TM (Template Manager) namespace
 * All nodes and relationships are prefixed with TM namespace to avoid conflicts
 */
class Neo4jNamespaceService {
  constructor(namespace = 'TM') {
    this.namespace = namespace;
    this.driver = neo4j.driver(
      process.env.NEO4J_URI || 'bolt://localhost:7687',
      neo4j.auth.basic(
        process.env.NEO4J_USERNAME || 'neo4j',
        process.env.NEO4J_PASSWORD || 'password'
      )
    );
  }

  /**
   * Get namespaced label for nodes
   */
  getNamespacedLabel(baseLabel) {
    return `${baseLabel}:${this.namespace}`;
  }

  /**
   * Get namespaced relationship type
   */
  getNamespacedRelationship(baseRelationship) {
    return `${baseRelationship}_${this.namespace}`;
  }

  /**
   * Execute a namespaced Neo4j query
   */
  async runQuery(query, parameters = {}) {
    try {
      const session = this.driver.session();
      const result = await session.run(query, parameters);
      await session.close();
      return result; // Return the full result object, not just records
    } catch (error) {
      console.error(`❌ Neo4j query error: ${error.message}`);
      throw error;
    }
  }

  /**
   * Test connection to Neo4j
   */
  async testConnection() {
    try {
      const session = this.driver.session();
      await session.run('RETURN 1');
      await session.close();
      console.log(`✅ Neo4j Namespace Service (${this.namespace}) connected successfully`);
      return true;
    } catch (error) {
      console.error(`❌ Neo4j connection failed: ${error.message}`);
      return false;
    }
  }

  /**
   * Clear all data for this namespace
   */
  async clearNamespaceData() {
    try {
      await this.runQuery(`
        MATCH (n)
        WHERE '${this.namespace}' IN labels(n)
        DETACH DELETE n
      `);
      console.log(`✅ Cleared all ${this.namespace} namespace data`);
      return true;
    } catch (error) {
      console.error(`❌ Error clearing namespace data: ${error.message}`);
      return false;
    }
  }

  /**
   * Get statistics for this namespace
   */
  async getNamespaceStats() {
    try {
      const stats = {};
      
      // Count nodes by type
      const nodeCounts = await this.runQuery(`
        MATCH (n)
        WHERE '${this.namespace}' IN labels(n)
        RETURN labels(n)[0] as node_type, count(n) as count
      `);
      
      nodeCounts.forEach(record => {
        stats[`${record.node_type}_count`] = record.count;
      });
      
      // Count relationships
      const relCounts = await this.runQuery(`
        MATCH ()-[r]->()
        WHERE type(r) CONTAINS '${this.namespace}'
        RETURN type(r) as rel_type, count(r) as count
      `);
      
      relCounts.forEach(record => {
        stats[`${record.rel_type}_count`] = record.count;
      });
      
      return stats;
    } catch (error) {
      console.error(`❌ Error getting namespace stats: ${error.message}`);
      return {};
    }
  }

  /**
   * Create a Template node with namespace
   */
  async createTemplateNode(templateData) {
    const templateId = templateData.id || uuidv4();
    
    const query = `
      MERGE (t:${this.getNamespacedLabel('Template')} {id: $id})
      SET t.type = $type,
          t.title = $title,
          t.description = $description,
          t.category = $category,
          t.complexity = $complexity,
          t.is_active = $is_active,
          t.created_at = datetime(),
          t.updated_at = datetime(),
          t.usage_count = $usage_count,
          t.success_rate = $success_rate
      RETURN t
    `;
    
    const parameters = {
      id: templateId,
      type: templateData.type,
      title: templateData.title,
      description: templateData.description,
      category: templateData.category,
      complexity: templateData.complexity || 'medium',
      is_active: templateData.is_active !== false,
      usage_count: templateData.usage_count || 0,
      success_rate: templateData.success_rate || 0
    };
    
    const result = await this.runQuery(query, parameters);
    return result[0]?.t;
  }

  /**
   * Create a Feature node with namespace
   */
  async createFeatureNode(featureData) {
    const featureId = featureData.id || uuidv4();
    
    const query = `
      MERGE (f:${this.getNamespacedLabel('Feature')} {id: $id})
      SET f.name = $name,
          f.description = $description,
          f.feature_type = $feature_type,
          f.complexity = $complexity,
          f.display_order = $display_order,
          f.usage_count = $usage_count,
          f.user_rating = $user_rating,
          f.is_default = $is_default,
          f.created_by_user = $created_by_user,
          f.dependencies = $dependencies,
          f.conflicts = $conflicts,
          f.created_at = datetime(),
          f.updated_at = datetime()
      RETURN f
    `;
    
    const parameters = {
      id: featureId,
      name: featureData.name,
      description: featureData.description,
      feature_type: featureData.feature_type || 'essential',
      complexity: featureData.complexity || 'medium',
      display_order: featureData.display_order || 0,
      usage_count: featureData.usage_count || 0,
      user_rating: featureData.user_rating || 0,
      is_default: featureData.is_default !== false,
      created_by_user: featureData.created_by_user || false,
      dependencies: JSON.stringify(featureData.dependencies || []),
      conflicts: JSON.stringify(featureData.conflicts || [])
    };
    
    const result = await this.runQuery(query, parameters);
    return result[0]?.f;
  }

  /**
   * Create a Technology node with namespace
   */
  async createTechnologyNode(technologyData) {
    const query = `
      MERGE (t:${this.getNamespacedLabel('Technology')} {name: $name})
      SET t.category = $category,
          t.type = $type,
          t.version = $version,
          t.popularity = $popularity,
          t.description = $description,
          t.website = $website,
          t.documentation = $documentation,
          t.compatibility = $compatibility,
          t.performance_score = $performance_score,
          t.learning_curve = $learning_curve,
          t.community_support = $community_support,
          t.cost = $cost,
          t.scalability = $scalability,
          t.security_score = $security_score
      RETURN t
    `;
    
    const parameters = {
      name: technologyData.name,
      category: technologyData.category,
      type: technologyData.type || 'framework',
      version: technologyData.version || 'latest',
      popularity: technologyData.popularity || 0,
      description: technologyData.description ?? '',
      website: technologyData.website ?? '',
      documentation: technologyData.documentation ?? '',
      compatibility: JSON.stringify(technologyData.compatibility || []),
      performance_score: technologyData.performance_score || 0,
      learning_curve: technologyData.learning_curve || 'medium',
      community_support: technologyData.community_support || 'medium',
      cost: technologyData.cost || 'free',
      scalability: technologyData.scalability || 'medium',
      security_score: technologyData.security_score || 0
    };
    
    const result = await this.runQuery(query, parameters);
    return result[0]?.t;
  }

  /**
   * Create a TechStack node with namespace
   */
  async createTechStackNode(techStackData) {
    const techStackId = techStackData.id || uuidv4();
    
    const query = `
      MERGE (ts:${this.getNamespacedLabel('TechStack')} {id: $id})
      SET ts.template_id = $template_id,
          ts.template_type = $template_type,
          ts.status = $status,
          ts.ai_model = $ai_model,
          ts.analysis_version = $analysis_version,
          ts.processing_time_ms = $processing_time_ms,
          ts.created_at = datetime(),
          ts.last_analyzed_at = datetime(),
          ts.confidence_scores = $confidence_scores,
          ts.reasoning = $reasoning,
          ts.frontend_tech = $frontend_tech,
          ts.backend_tech = $backend_tech,
          ts.database_tech = $database_tech,
          ts.devops_tech = $devops_tech,
          ts.mobile_tech = $mobile_tech,
          ts.cloud_tech = $cloud_tech,
          ts.testing_tech = $testing_tech,
          ts.ai_ml_tech = $ai_ml_tech,
          ts.tools_tech = $tools_tech
      RETURN ts
    `;
    
    const parameters = {
      id: techStackId,
      template_id: techStackData.template_id,
      template_type: techStackData.template_type,
      status: techStackData.status || 'active',
      ai_model: techStackData.ai_model || 'claude-3.5-sonnet',
      analysis_version: techStackData.analysis_version || '1.0',
      processing_time_ms: techStackData.processing_time_ms || 0,
      confidence_scores: JSON.stringify(techStackData.confidence_scores || {}),
      reasoning: JSON.stringify(techStackData.reasoning || {}),
      frontend_tech: JSON.stringify(techStackData.frontend_tech || []),
      backend_tech: JSON.stringify(techStackData.backend_tech || []),
      database_tech: JSON.stringify(techStackData.database_tech || []),
      devops_tech: JSON.stringify(techStackData.devops_tech || []),
      mobile_tech: JSON.stringify(techStackData.mobile_tech || []),
      cloud_tech: JSON.stringify(techStackData.cloud_tech || []),
      testing_tech: JSON.stringify(techStackData.testing_tech || []),
      ai_ml_tech: JSON.stringify(techStackData.ai_ml_tech || []),
      tools_tech: JSON.stringify(techStackData.tools_tech || [])
    };
    
    const result = await this.runQuery(query, parameters);
    return result[0]?.ts;
  }

  /**
   * Create Template-Feature relationship with namespace
   */
  async createTemplateFeatureRelationship(templateId, featureId) {
    const query = `
      MATCH (t:${this.getNamespacedLabel('Template')} {id: $templateId})
      MATCH (f:${this.getNamespacedLabel('Feature')} {id: $featureId})
      MERGE (t)-[:${this.getNamespacedRelationship('HAS_FEATURE')}]->(f)
      RETURN t, f
    `;
    
    const parameters = {
      templateId: templateId,
      featureId: featureId
    };
    
    const result = await this.runQuery(query, parameters);
    return result[0];
  }

  /**
   * Create Feature-Technology relationship with namespace
   */
  async createFeatureTechnologyRelationship(featureId, technologyName, confidence = 0.8) {
    const query = `
      MATCH (f:${this.getNamespacedLabel('Feature')} {id: $featureId})
      MATCH (t:${this.getNamespacedLabel('Technology')} {name: $technologyName})
      MERGE (f)-[:${this.getNamespacedRelationship('REQUIRES_TECHNOLOGY')} {confidence: $confidence}]->(t)
      RETURN f, t
    `;
    
    const parameters = {
      featureId: featureId,
      technologyName: technologyName,
      confidence: confidence
    };
    
    const result = await this.runQuery(query, parameters);
    return result[0];
  }

  /**
   * Create Template-TechStack relationship with namespace
   */
  async createTemplateTechStackRelationship(templateId, techStackId) {
    const query = `
      MATCH (t:${this.getNamespacedLabel('Template')} {id: $templateId})
      MATCH (ts:${this.getNamespacedLabel('TechStack')} {id: $techStackId})
      MERGE (t)-[:${this.getNamespacedRelationship('HAS_TECH_STACK')}]->(ts)
      RETURN t, ts
    `;
    
    const parameters = {
      templateId: templateId,
      techStackId: techStackId
    };
    
    const result = await this.runQuery(query, parameters);
    return result[0];
  }

  /**
   * Create TechStack-Technology relationship with namespace
   */
  async createTechStackTechnologyRelationship(techStackId, technologyName, category, confidence = 0.8) {
    const query = `
      MATCH (ts:${this.getNamespacedLabel('TechStack')} {id: $techStackId})
      MATCH (t:${this.getNamespacedLabel('Technology')} {name: $technologyName})
      MERGE (ts)-[:${this.getNamespacedRelationship('RECOMMENDS_TECHNOLOGY')} {category: $category, confidence: $confidence}]->(t)
      RETURN ts, t
    `;
    
    const parameters = {
      techStackId: techStackId,
      technologyName: technologyName,
      category: category,
      confidence: confidence
    };
    
    const result = await this.runQuery(query, parameters);
    return result[0];
  }

  /**
   * Get template with its features and tech stack
   */
  async getTemplateWithDetails(templateId) {
    const query = `
      MATCH (t:${this.getNamespacedLabel('Template')} {id: $templateId})
      OPTIONAL MATCH (t)-[:${this.getNamespacedRelationship('HAS_FEATURE')}]->(f:${this.getNamespacedLabel('Feature')})
      OPTIONAL MATCH (t)-[:${this.getNamespacedRelationship('HAS_TECH_STACK')}]->(ts:${this.getNamespacedLabel('TechStack')})
      RETURN t, collect(DISTINCT f) as features, collect(DISTINCT ts) as techStacks
    `;
    
    const parameters = {
      templateId: templateId
    };
    
    const result = await this.runQuery(query, parameters);
    return result[0];
  }

  /**
   * Get all templates with namespace
   */
  async getAllTemplates() {
    const query = `
      MATCH (t:${this.getNamespacedLabel('Template')})
      RETURN t
      ORDER BY t.created_at DESC
    `;
    
    const result = await this.runQuery(query);
    return result.map(record => record.t);
  }

  /**
   * Close the Neo4j driver
   */
  async close() {
    if (this.driver) {
      await this.driver.close();
      console.log(`🔌 Neo4j Namespace Service (${this.namespace}) connection closed`);
    }
  }
}

module.exports = Neo4jNamespaceService;

