# ================================================================================================
# NEO4J NAMESPACE SERVICE FOR TECH-STACK-SELECTOR
# Provides isolated Neo4j operations with TSS (Tech Stack Selector) namespace
# ================================================================================================

import os
import json
from datetime import datetime
from typing import Dict, Any, Optional, List
from neo4j import GraphDatabase
from loguru import logger
import anthropic
import psycopg2
from psycopg2.extras import RealDictCursor

class Neo4jNamespaceService:
    """
    Neo4j service with namespace isolation for tech-stack-selector
    All nodes and relationships are prefixed with TSS (Tech Stack Selector) namespace
    """
    
    def __init__(self, uri, user, password, namespace="TSS"):
        self.namespace = namespace
        self.driver = GraphDatabase.driver(
            uri,
            auth=(user, password),
            connection_timeout=5
        )
        self.neo4j_healthy = False
        self.claude_service = None
        
        # Initialize services (will be set externally to avoid circular imports)
        self.postgres_service = None
        self.claude_service = None
        
        try:
            self.driver.verify_connectivity()
            logger.info(f"✅ Neo4j Namespace Service ({namespace}) connected successfully")
            self.neo4j_healthy = True
        except Exception as e:
            logger.error(f"❌ Neo4j connection failed: {e}")
            self.neo4j_healthy = False
    
    def close(self):
        if self.driver:
            self.driver.close()
    
    def is_neo4j_healthy(self):
        """Check if Neo4j is healthy and accessible"""
        try:
            with self.driver.session() as session:
                session.run("RETURN 1")
            self.neo4j_healthy = True
            return True
        except Exception as e:
            logger.warning(f"⚠️ Neo4j health check failed: {e}")
            self.neo4j_healthy = False
            return False

    def run_query(self, query: str, parameters: Optional[Dict[str, Any]] = None):
        """Execute a namespaced Neo4j query"""
        try:
            with self.driver.session() as session:
                result = session.run(query, parameters or {})
                return [record.data() for record in result]
        except Exception as e:
            logger.error(f"❌ Neo4j query error: {e}")
            raise e

    def get_namespaced_label(self, base_label: str) -> str:
        """Get namespaced label for nodes"""
        return f"{base_label}:{self.namespace}"

    def get_namespaced_relationship(self, base_relationship: str) -> str:
        """Get namespaced relationship type"""
        return f"{base_relationship}_{self.namespace}"

    # ================================================================================================
    # NAMESPACED QUERY METHODS
    # ================================================================================================

    def get_recommendations_by_budget(self, budget: float, domain: Optional[str] = None, preferred_techs: Optional[List[str]] = None):
        """Get professional, budget-appropriate, domain-specific recommendations from Knowledge Graph only"""
        
        # BUDGET VALIDATION: For very low budgets, use budget-aware static recommendations
        if budget <= 5:
            logger.info(f"Ultra-micro budget ${budget} detected - using budget-aware static recommendation")
            return [self._create_static_fallback_recommendation(budget, domain)]
        elif budget <= 10:
            logger.info(f"Micro budget ${budget} detected - using budget-aware static recommendation")
            return [self._create_static_fallback_recommendation(budget, domain)]
        elif budget <= 25:
            logger.info(f"Low budget ${budget} detected - using budget-aware static recommendation")
            return [self._create_static_fallback_recommendation(budget, domain)]
        
        # Normalize domain for better matching with intelligent variations
        normalized_domain = domain.lower().strip() if domain else None
        
        # Create comprehensive domain variations for robust matching
        domain_variations = []
        if normalized_domain:
            domain_variations.append(normalized_domain)
            if 'commerce' in normalized_domain or 'ecommerce' in normalized_domain:
                domain_variations.extend(['e-commerce', 'ecommerce', 'online stores', 'product catalogs', 'marketplaces', 'retail', 'shopping'])
            if 'saas' in normalized_domain:
                domain_variations.extend(['web apps', 'business tools', 'data management', 'software as a service', 'cloud applications'])
            if 'mobile' in normalized_domain:
                domain_variations.extend(['mobile apps', 'ios', 'android', 'cross-platform', 'native apps'])
            if 'ai' in normalized_domain or 'ml' in normalized_domain:
                domain_variations.extend(['artificial intelligence', 'machine learning', 'data science', 'ai applications'])
            if 'healthcare' in normalized_domain or 'health' in normalized_domain or 'medical' in normalized_domain:
                domain_variations.extend(['enterprise applications', 'saas applications', 'data management', 'business tools', 'mission-critical applications', 'enterprise platforms'])
            if 'finance' in normalized_domain:
                domain_variations.extend(['financial', 'banking', 'fintech', 'payment', 'trading', 'investment', 'enterprise', 'large enterprises', 'mission-critical'])
            if 'education' in normalized_domain:
                domain_variations.extend(['learning', 'elearning', 'educational', 'academic', 'training'])
            if 'gaming' in normalized_domain:
                domain_variations.extend(['games', 'entertainment', 'interactive', 'real-time'])
        
        logger.info(f"🎯 Knowledge Graph: Searching for professional tech stacks with budget ${budget} and domain '{domain}'")
        
        # Enhanced Knowledge Graph query with professional scoring and budget precision
        # Using namespaced labels for TSS data isolation
        existing_stacks = self.run_query(f"""
            MATCH (s:{self.get_namespaced_label('TechStack')})-[:{self.get_namespaced_relationship('BELONGS_TO_TIER')}]->(p:{self.get_namespaced_label('PriceTier')})
            WHERE p.min_price_usd <= $budget AND p.max_price_usd >= $budget
            AND ($domain IS NULL OR 
                 toLower(s.name) CONTAINS $normalized_domain OR
                 toLower(s.description) CONTAINS $normalized_domain OR
                 EXISTS {{ MATCH (d:{self.get_namespaced_label('Domain')})-[:{self.get_namespaced_relationship('RECOMMENDS')}]->(s) WHERE toLower(d.name) = $normalized_domain }} OR
                 EXISTS {{ MATCH (d:{self.get_namespaced_label('Domain')})-[:{self.get_namespaced_relationship('RECOMMENDS')}]->(s) WHERE toLower(d.name) CONTAINS $normalized_domain }} OR
                 ANY(rd IN s.recommended_domains WHERE toLower(rd) CONTAINS $normalized_domain) OR
                 ANY(rd IN s.recommended_domains WHERE toLower(rd) CONTAINS $normalized_domain + ' ' OR toLower(rd) CONTAINS ' ' + $normalized_domain) OR
                 ANY(rd IN s.recommended_domains WHERE ANY(variation IN $domain_variations WHERE toLower(rd) CONTAINS variation)))
            
            OPTIONAL MATCH (s)-[:{self.get_namespaced_relationship('USES_FRONTEND')}]->(frontend:{self.get_namespaced_label('Technology')})
            OPTIONAL MATCH (s)-[:{self.get_namespaced_relationship('USES_BACKEND')}]->(backend:{self.get_namespaced_label('Technology')})
            OPTIONAL MATCH (s)-[:{self.get_namespaced_relationship('USES_DATABASE')}]->(database:{self.get_namespaced_label('Technology')})
            OPTIONAL MATCH (s)-[:{self.get_namespaced_relationship('USES_CLOUD')}]->(cloud:{self.get_namespaced_label('Technology')})
            OPTIONAL MATCH (s)-[:{self.get_namespaced_relationship('USES_TESTING')}]->(testing:{self.get_namespaced_label('Technology')})
            OPTIONAL MATCH (s)-[:{self.get_namespaced_relationship('USES_MOBILE')}]->(mobile:{self.get_namespaced_label('Technology')})
            OPTIONAL MATCH (s)-[:{self.get_namespaced_relationship('USES_DEVOPS')}]->(devops:{self.get_namespaced_label('Technology')})
            OPTIONAL MATCH (s)-[:{self.get_namespaced_relationship('USES_AI_ML')}]->(ai_ml:{self.get_namespaced_label('Technology')})
            OPTIONAL MATCH (s)-[:{self.get_namespaced_relationship('BELONGS_TO_TIER')}]->(pt3:{self.get_namespaced_label('PriceTier')})<-[:{self.get_namespaced_relationship('BELONGS_TO_TIER')}]-(tool:{self.get_namespaced_label('Tool')})
            
            WITH s, p, frontend, backend, database, cloud, testing, mobile, devops, ai_ml, tool, 
                 // Use budget-based calculation only
                 ($budget * 0.6 / 12) AS calculated_monthly_cost,
                 ($budget * 0.4) AS calculated_setup_cost,
                 
                 // Base score from stack properties (use default if missing)
                 50 AS base_score,
                 
                 // Preference bonus for preferred technologies
                 CASE WHEN $preferred_techs IS NOT NULL THEN 
                     size([x IN $preferred_techs WHERE 
                         toLower(x) IN [toLower(frontend.name), toLower(backend.name), toLower(database.name), 
                                       toLower(cloud.name), toLower(testing.name), toLower(mobile.name), 
                                       toLower(devops.name), toLower(ai_ml.name)]]) * 8
                 ELSE 0 END AS preference_bonus,
                 
                 // Professional scoring based on technology maturity and domain fit
                 CASE 
                     WHEN COALESCE(frontend.maturity_score, 0) >= 80 AND COALESCE(backend.maturity_score, 0) >= 80 THEN 15
                     WHEN COALESCE(frontend.maturity_score, 0) >= 70 AND COALESCE(backend.maturity_score, 0) >= 70 THEN 10
                     ELSE 5
                 END AS maturity_bonus,
                 
                 // Domain-specific scoring
                 CASE 
                     WHEN $normalized_domain IS NOT NULL AND 
                          (toLower(s.name) CONTAINS $normalized_domain OR 
                           ANY(rd IN s.recommended_domains WHERE toLower(rd) CONTAINS $normalized_domain)) THEN 20
                     ELSE 0
                 END AS domain_bonus
            
            RETURN s.name AS stack_name,
                   calculated_monthly_cost AS monthly_cost,
                   calculated_setup_cost AS setup_cost,
                   s.team_size_range AS team_size,
                   s.development_time_months AS development_time,
                   s.satisfaction_score AS satisfaction,
                   s.success_rate AS success_rate,
                   p.tier_name AS price_tier,
                   s.recommended_domains AS recommended_domains,
                   s.description AS description,
                   s.pros AS pros,
                   s.cons AS cons,
                   COALESCE(frontend.name, s.frontend_tech) AS frontend,
                   COALESCE(backend.name, s.backend_tech) AS backend,
                   COALESCE(database.name, s.database_tech) AS database,
                   COALESCE(cloud.name, s.cloud_tech) AS cloud,
                   COALESCE(testing.name, s.testing_tech) AS testing,
                   COALESCE(mobile.name, s.mobile_tech) AS mobile,
                   COALESCE(devops.name, s.devops_tech) AS devops,
                   COALESCE(ai_ml.name, s.ai_ml_tech) AS ai_ml,
                   tool AS tool,
                   CASE WHEN (base_score + preference_bonus + maturity_bonus + domain_bonus) > 100 THEN 100 
                        ELSE (base_score + preference_bonus + maturity_bonus + domain_bonus) END AS recommendation_score
            ORDER BY recommendation_score DESC, 
                     // Secondary sort by budget efficiency
                     CASE WHEN (calculated_monthly_cost * 12 + calculated_setup_cost) <= $budget THEN 1 ELSE 2 END,
                     (calculated_monthly_cost * 12 + calculated_setup_cost) ASC
            LIMIT 20
        """, {
            "budget": budget,
            "domain": domain,
            "normalized_domain": normalized_domain,
            "domain_variations": domain_variations,
            "preferred_techs": preferred_techs or []
        })
        
        logger.info(f"📊 Found {len(existing_stacks)} existing stacks with relationships")
        
        if existing_stacks:
            return existing_stacks
        
        # If no existing stacks with domain filtering, try without domain filtering
        if domain:
            print(f"No stacks found for domain '{domain}', trying without domain filter...")
            existing_stacks_no_domain = self.run_query(f"""
                MATCH (s:{self.get_namespaced_label('TechStack')})-[:{self.get_namespaced_relationship('BELONGS_TO_TIER')}]->(p:{self.get_namespaced_label('PriceTier')})
                WHERE p.min_price_usd <= $budget AND p.max_price_usd >= $budget
                
                OPTIONAL MATCH (s)-[:{self.get_namespaced_relationship('USES_FRONTEND')}]->(frontend:{self.get_namespaced_label('Technology')})
                OPTIONAL MATCH (s)-[:{self.get_namespaced_relationship('USES_BACKEND')}]->(backend:{self.get_namespaced_label('Technology')})
                OPTIONAL MATCH (s)-[:{self.get_namespaced_relationship('USES_DATABASE')}]->(database:{self.get_namespaced_label('Technology')})
                OPTIONAL MATCH (s)-[:{self.get_namespaced_relationship('USES_CLOUD')}]->(cloud:{self.get_namespaced_label('Technology')})
                OPTIONAL MATCH (s)-[:{self.get_namespaced_relationship('USES_TESTING')}]->(testing:{self.get_namespaced_label('Technology')})
                OPTIONAL MATCH (s)-[:{self.get_namespaced_relationship('USES_MOBILE')}]->(mobile:{self.get_namespaced_label('Technology')})
                OPTIONAL MATCH (s)-[:{self.get_namespaced_relationship('USES_DEVOPS')}]->(devops:{self.get_namespaced_label('Technology')})
                OPTIONAL MATCH (s)-[:{self.get_namespaced_relationship('USES_AI_ML')}]->(ai_ml:{self.get_namespaced_label('Technology')})
                OPTIONAL MATCH (s)-[:{self.get_namespaced_relationship('BELONGS_TO_TIER')}]->(pt3:{self.get_namespaced_label('PriceTier')})<-[:{self.get_namespaced_relationship('BELONGS_TO_TIER')}]-(tool:{self.get_namespaced_label('Tool')})
                
                WITH s, p, frontend, backend, database, cloud, testing, mobile, devops, ai_ml, tool, 
                     COALESCE(frontend.monthly_cost_usd, 0) + 
                     COALESCE(backend.monthly_cost_usd, 0) + 
                     COALESCE(database.monthly_cost_usd, 0) + 
                     COALESCE(cloud.monthly_cost_usd, 0) + 
                     COALESCE(testing.monthly_cost_usd, 0) + 
                     COALESCE(mobile.monthly_cost_usd, 0) + 
                     COALESCE(devops.monthly_cost_usd, 0) + 
                     COALESCE(ai_ml.monthly_cost_usd, 0) + 
                     COALESCE(tool.monthly_cost_usd, 0) AS calculated_monthly_cost,
                     
                     COALESCE(frontend.setup_cost_usd, 0) + 
                     COALESCE(backend.setup_cost_usd, 0) + 
                     COALESCE(database.setup_cost_usd, 0) + 
                     COALESCE(cloud.setup_cost_usd, 0) + 
                     COALESCE(testing.setup_cost_usd, 0) + 
                     COALESCE(mobile.setup_cost_usd, 0) + 
                     COALESCE(devops.setup_cost_usd, 0) + 
                     COALESCE(ai_ml.setup_cost_usd, 0) + 
                     COALESCE(tool.setup_cost_usd, 0) AS calculated_setup_cost,
                     
                     50 AS base_score
                
                RETURN s.name AS stack_name,
                       calculated_monthly_cost AS monthly_cost,
                       calculated_setup_cost AS setup_cost,
                       s.team_size_range AS team_size,
                       s.development_time_months AS development_time,
                       s.satisfaction_score AS satisfaction,
                       s.success_rate AS success_rate,
                       p.tier_name AS price_tier,
                       s.recommended_domains AS recommended_domains,
                       s.description AS description,
                       s.pros AS pros,
                       s.cons AS cons,
                       COALESCE(frontend.name, s.frontend_tech) AS frontend,
                       COALESCE(backend.name, s.backend_tech) AS backend,
                       COALESCE(database.name, s.database_tech) AS database,
                       COALESCE(cloud.name, s.cloud_tech) AS cloud,
                       COALESCE(testing.name, s.testing_tech) AS testing,
                       COALESCE(mobile.name, s.mobile_tech) AS mobile,
                       COALESCE(devops.name, s.devops_tech) AS devops,
                       COALESCE(ai_ml.name, s.ai_ml_tech) AS ai_ml,
                       tool AS tool,
                       base_score AS recommendation_score
                ORDER BY recommendation_score DESC,
                         CASE WHEN (calculated_monthly_cost * 12 + calculated_setup_cost) <= $budget THEN 1 ELSE 2 END,
                         (calculated_monthly_cost * 12 + calculated_setup_cost) ASC
                LIMIT 20
            """, {"budget": budget})
            
            logger.info(f"📊 Found {len(existing_stacks_no_domain)} stacks without domain filtering")
            return existing_stacks_no_domain
        
        return []

    def _create_static_fallback_recommendation(self, budget: float, domain: Optional[str] = None):
        """Create a static fallback recommendation for very low budgets"""
        return {
            "stack_name": f"Budget-Friendly {domain.title() if domain else 'Development'} Stack",
            "monthly_cost": budget,
            "setup_cost": budget * 0.1,
            "team_size": "1-3",
            "development_time": 3,
            "satisfaction": 75,
            "success_rate": 80,
            "price_tier": "Micro",
            "recommended_domains": [domain] if domain else ["Small projects"],
            "description": f"Ultra-budget solution for {domain or 'small projects'}",
            "pros": ["Very affordable", "Quick setup", "Minimal complexity"],
            "cons": ["Limited scalability", "Basic features", "Manual processes"],
            "frontend": "HTML/CSS/JS",
            "backend": "Node.js",
            "database": "SQLite",
            "cloud": "Free tier",
            "testing": "Manual testing",
            "mobile": "Responsive web",
            "devops": "Manual deployment",
            "ai_ml": "None",
            "tool": "Free tools",
            "recommendation_score": 60
        }

    def get_single_recommendation_from_kg(self, budget: float, domain: Optional[str] = None, preferred_techs: Optional[List[str]] = None):
        """Get a single recommendation from the Knowledge Graph with enhanced scoring"""
        try:
            logger.info(f"🚀 UPDATED METHOD CALLED: get_single_recommendation_from_kg with budget=${budget}, domain={domain}")
            
            # Check if budget is above threshold for KG queries
            if budget <= 25:
                logger.info(f"🔍 DEBUG: Budget ${budget} is below threshold, using static recommendation")
                return self._create_static_fallback_recommendation(budget, domain)
            
            logger.info(f"🔍 DEBUG: Budget ${budget} is above threshold, proceeding to KG query")
            
            # Get recommendations from Knowledge Graph
            recommendations = self.get_recommendations_by_budget(budget, domain, preferred_techs)
            
            if recommendations:
                # Return the best recommendation
                best_rec = recommendations[0]
                logger.info(f"🎯 Found {len(recommendations)} recommendations from Knowledge Graph")
                return best_rec
            else:
                logger.warning("⚠️ No recommendations found in Knowledge Graph")
                return self._create_static_fallback_recommendation(budget, domain)
                
        except Exception as e:
            logger.error(f"❌ Error getting single recommendation from KG: {e}")
            return self._create_static_fallback_recommendation(budget, domain)

    # --------------------------------------------------------------------------------------------
    # Compatibility wrappers to match calls from main_migrated.py
    # --------------------------------------------------------------------------------------------
    def get_recommendations_with_fallback(self, budget: float, domain: Optional[str] = None, preferred_techs: Optional[List[str]] = None):
        """
        Returns a list of recommendations using KG when budget is sufficient,
        otherwise returns a single static fallback recommendation.
        """
        try:
            if budget <= 25:
                return [self._create_static_fallback_recommendation(budget, domain)]
            recs = self.get_recommendations_by_budget(budget, domain, preferred_techs)
            if recs and len(recs) > 0:
                return recs
            return [self._create_static_fallback_recommendation(budget, domain)]
        except Exception as e:
            logger.error(f"❌ Error in get_recommendations_with_fallback: {e}")
            return [self._create_static_fallback_recommendation(budget, domain)]

    def get_price_tier_analysis(self):
        """Return basic stats for price tiers within the namespace for admin/diagnostics"""
        try:
            results = self.run_query(f"""
                MATCH (p:{self.get_namespaced_label('PriceTier')})
                OPTIONAL MATCH (s:{self.get_namespaced_label('TechStack')})-[:{self.get_namespaced_relationship('BELONGS_TO_TIER')}]->(p)
                RETURN p.tier_name AS tier,
                       p.min_price_usd AS min_price,
                       p.max_price_usd AS max_price,
                       count(s) AS stack_count
                ORDER BY min_price ASC
            """)
            # Convert neo4j records to dicts
            return [{
                'tier': r['tier'],
                'min_price': r['min_price'],
                'max_price': r['max_price'],
                'stack_count': r['stack_count']
            } for r in results]
        except Exception as e:
            logger.error(f"❌ Error in get_price_tier_analysis: {e}")
            return []

    def clear_namespace_data(self):
        """Clear all data for this namespace"""
        try:
            # Clear all nodes with this namespace
            result = self.run_query(f"""
                MATCH (n)
                WHERE '{self.namespace}' IN labels(n)
                DETACH DELETE n
            """)
            logger.info(f"✅ Cleared all {self.namespace} namespace data")
            return True
        except Exception as e:
            logger.error(f"❌ Error clearing namespace data: {e}")
            return False

    def get_namespace_stats(self):
        """Get statistics for this namespace"""
        try:
            stats = {}
            
            # Count nodes by type
            node_counts = self.run_query(f"""
                MATCH (n)
                WHERE '{self.namespace}' IN labels(n)
                RETURN labels(n)[0] as node_type, count(n) as count
            """)
            
            for record in node_counts:
                stats[f"{record['node_type']}_count"] = record['count']
            
            # Count relationships
            rel_counts = self.run_query(f"""
                MATCH ()-[r]->()
                WHERE type(r) CONTAINS '{self.namespace}'
                RETURN type(r) as rel_type, count(r) as count
            """)
            
            for record in rel_counts:
                stats[f"{record['rel_type']}_count"] = record['count']
            
            return stats
        except Exception as e:
            logger.error(f"❌ Error getting namespace stats: {e}")
            return {}

    # ================================================================================================
    # METHODS FROM MIGRATED NEO4J SERVICE (WITH NAMESPACE SUPPORT)
    # ================================================================================================
    
    def get_recommendations_with_fallback(self, budget: float, domain: Optional[str] = None, preferred_techs: Optional[List[str]] = None):
        """Get recommendations with robust fallback mechanism"""
        logger.info(f"🔄 Getting recommendations for budget ${budget}, domain '{domain}'")
        
        # PRIMARY: Try Neo4j Knowledge Graph
        if self.is_neo4j_healthy():
            try:
                logger.info("🎯 Using PRIMARY: Neo4j Knowledge Graph")
                recommendations = self.get_recommendations_by_budget(budget, domain, preferred_techs)
                if recommendations:
                    logger.info(f"✅ Neo4j returned {len(recommendations)} recommendations")
                    return {
                        "recommendations": recommendations,
                        "count": len(recommendations),
                        "data_source": "neo4j_knowledge_graph",
                        "fallback_level": "primary"
                    }
            except Exception as e:
                logger.error(f"❌ Neo4j query failed: {e}")
                self.neo4j_healthy = False
        
        # SECONDARY: Try Claude AI
        if self.claude_service:
            try:
                logger.info("🤖 Using SECONDARY: Claude AI")
                claude_rec = self.claude_service.generate_tech_stack_recommendation(domain or "general", budget)
                if claude_rec:
                    logger.info("✅ Claude AI generated recommendation")
                    return {
                        "recommendations": [claude_rec],
                        "count": 1,
                        "data_source": "claude_ai",
                        "fallback_level": "secondary"
                    }
            except Exception as e:
                logger.error(f"❌ Claude AI failed: {e}")
        else:
            logger.warning("⚠️ Claude AI service not available - skipping to PostgreSQL fallback")
        
        # TERTIARY: Try PostgreSQL
        try:
            logger.info("🗄️ Using TERTIARY: PostgreSQL")
            postgres_recs = self.get_postgres_fallback_recommendations(budget, domain)
            if postgres_recs:
                logger.info(f"✅ PostgreSQL returned {len(postgres_recs)} recommendations")
                return {
                    "recommendations": postgres_recs,
                    "count": len(postgres_recs),
                    "data_source": "postgresql",
                    "fallback_level": "tertiary"
                }
        except Exception as e:
            logger.error(f"❌ PostgreSQL fallback failed: {e}")
        
        # FINAL FALLBACK: Static recommendation
        logger.warning("⚠️ All data sources failed - using static fallback")
        static_rec = self._create_static_fallback_recommendation(budget, domain)
        return {
            "recommendations": [static_rec],
            "count": 1,
            "data_source": "static_fallback",
            "fallback_level": "final"
        }

    def get_postgres_fallback_recommendations(self, budget: float, domain: Optional[str] = None):
        """Get recommendations from PostgreSQL as fallback"""
        if not self.postgres_service:
            return []
            
        try:
            if not self.postgres_service.connect():
                logger.error("❌ PostgreSQL connection failed")
                return []
            
            # Query PostgreSQL for tech stacks within budget
            query = """
                SELECT DISTINCT 
                    ts.name as stack_name,
                    ts.monthly_cost_usd,
                    ts.setup_cost_usd,
                    ts.team_size_range,
                    ts.development_time_months,
                    ts.satisfaction_score,
                    ts.success_rate,
                    pt.tier_name,
                    ts.recommended_domains,
                    ts.description,
                    ts.pros,
                    ts.cons,
                    ts.frontend_tech,
                    ts.backend_tech,
                    ts.database_tech,
                    ts.cloud_tech,
                    ts.testing_tech,
                    ts.mobile_tech,
                    ts.devops_tech,
                    ts.ai_ml_tech
                FROM tech_stacks ts
                JOIN price_tiers pt ON ts.price_tier_id = pt.id
                WHERE (ts.monthly_cost_usd * 12 + COALESCE(ts.setup_cost_usd, 0)) <= %s
                AND (%s IS NULL OR LOWER(ts.recommended_domains) LIKE LOWER(%s))
                ORDER BY ts.satisfaction_score DESC, ts.success_rate DESC
                LIMIT 5
            """
            
            domain_pattern = f"%{domain}%" if domain else None
            cursor = self.postgres_service.connection.cursor(cursor_factory=RealDictCursor)
            cursor.execute(query, (budget, domain, domain_pattern))
            results = cursor.fetchall()
            
            recommendations = []
            for row in results:
                rec = {
                    "stack_name": row['stack_name'],
                    "monthly_cost": float(row['monthly_cost_usd'] or 0),
                    "setup_cost": float(row['setup_cost_usd'] or 0),
                    "team_size": row['team_size_range'],
                    "development_time": row['development_time_months'],
                    "satisfaction": float(row['satisfaction_score'] or 0),
                    "success_rate": float(row['success_rate'] or 0),
                    "price_tier": row['tier_name'],
                    "recommended_domains": row['recommended_domains'],
                    "description": row['description'],
                    "pros": row['pros'],
                    "cons": row['cons'],
                    "frontend": row['frontend_tech'],
                    "backend": row['backend_tech'],
                    "database": row['database_tech'],
                    "cloud": row['cloud_tech'],
                    "testing": row['testing_tech'],
                    "mobile": row['mobile_tech'],
                    "devops": row['devops_tech'],
                    "ai_ml": row['ai_ml_tech'],
                    "recommendation_score": 75  # Default score for PostgreSQL results
                }
                recommendations.append(rec)
            
            return recommendations
            
        except Exception as e:
            logger.error(f"❌ PostgreSQL query failed: {e}")
            return []
        finally:
            if self.postgres_service:
                self.postgres_service.close()

    def _create_static_fallback_recommendation(self, budget: float, domain: Optional[str] = None):
        """Create a static fallback recommendation when all other sources fail"""
        
        # Budget-based technology selection
        if budget <= 10:
            tech_stack = {
                "frontend": "HTML/CSS/JavaScript",
                "backend": "Node.js Express",
                "database": "SQLite",
                "cloud": "Heroku Free Tier",
                "testing": "Jest",
                "mobile": "Progressive Web App",
                "devops": "Git + GitHub",
                "ai_ml": "TensorFlow.js"
            }
            monthly_cost = 0
            setup_cost = 0
        elif budget <= 50:
            tech_stack = {
                "frontend": "React",
                "backend": "Node.js Express",
                "database": "PostgreSQL",
                "cloud": "Vercel + Railway",
                "testing": "Jest + Cypress",
                "mobile": "React Native",
                "devops": "GitHub Actions",
                "ai_ml": "OpenAI API"
            }
            monthly_cost = 25
            setup_cost = 0
        elif budget <= 200:
            tech_stack = {
                "frontend": "React + TypeScript",
                "backend": "Node.js + Express",
                "database": "PostgreSQL + Redis",
                "cloud": "AWS (EC2 + RDS)",
                "testing": "Jest + Cypress + Playwright",
                "mobile": "React Native",
                "devops": "GitHub Actions + Docker",
                "ai_ml": "OpenAI API + Pinecone"
            }
            monthly_cost = 100
            setup_cost = 50
        else:
            tech_stack = {
                "frontend": "React + TypeScript + Next.js",
                "backend": "Node.js + Express + GraphQL",
                "database": "PostgreSQL + Redis + MongoDB",
                "cloud": "AWS (ECS + RDS + ElastiCache)",
                "testing": "Jest + Cypress + Playwright + K6",
                "mobile": "React Native + Expo",
                "devops": "GitHub Actions + Docker + Kubernetes",
                "ai_ml": "OpenAI API + Pinecone + Custom ML Pipeline"
            }
            monthly_cost = min(budget * 0.7, 500)
            setup_cost = min(budget * 0.3, 200)
        
        # Domain-specific adjustments
        if domain:
            domain_lower = domain.lower()
            if 'ecommerce' in domain_lower or 'commerce' in domain_lower:
                tech_stack["additional"] = "Stripe Payment, Inventory Management"
            elif 'saas' in domain_lower:
                tech_stack["additional"] = "Multi-tenancy, Subscription Management"
            elif 'mobile' in domain_lower:
                tech_stack["frontend"] = "React Native"
                tech_stack["mobile"] = "Native iOS/Android"
        
        return {
            "stack_name": f"Budget-Optimized {domain.title() if domain else 'General'} Stack",
            "monthly_cost": monthly_cost,
            "setup_cost": setup_cost,
            "team_size": "2-5 developers",
            "development_time": max(2, min(12, int(budget / 50))),
            "satisfaction": 75,
            "success_rate": 80,
            "price_tier": "Budget-Friendly",
            "recommended_domains": [domain] if domain else ["general"],
            "description": f"A carefully curated technology stack optimized for ${budget} budget",
            "pros": ["Cost-effective", "Proven technologies", "Good community support"],
            "cons": ["Limited scalability", "Basic features"],
            **tech_stack,
            "recommendation_score": 70
        }

    def get_available_domains(self):
        """Get all available domains from the knowledge graph"""
        try:
            query = f"""
                MATCH (d:{self.get_namespaced_label('Domain')})
                RETURN d.name as domain_name
                ORDER BY d.name
            """
            results = self.run_query(query)
            return [record['domain_name'] for record in results]
        except Exception as e:
            logger.error(f"❌ Error getting domains: {e}")
            return ["saas", "ecommerce", "healthcare", "finance", "education", "gaming"]

    def get_all_stacks(self):
        """Get all available tech stacks"""
        try:
            query = f"""
                MATCH (s:{self.get_namespaced_label('TechStack')})
                RETURN s.name as stack_name, s.description as description
                ORDER BY s.name
            """
            results = self.run_query(query)
            return [{"name": record['stack_name'], "description": record['description']} for record in results]
        except Exception as e:
            logger.error(f"❌ Error getting stacks: {e}")
            return []

    def get_technologies_by_price_tier(self, tier_name: str):
        """Get technologies by price tier"""
        try:
            query = f"""
                MATCH (t:{self.get_namespaced_label('Technology')})-[:{self.get_namespaced_relationship('BELONGS_TO_TIER')}]->(p:{self.get_namespaced_label('PriceTier')} {{tier_name: $tier_name}})
                RETURN t.name as name, t.category as category, t.monthly_cost_usd as monthly_cost
                ORDER BY t.category, t.name
            """
            results = self.run_query(query, {"tier_name": tier_name})
            return results
        except Exception as e:
            logger.error(f"❌ Error getting technologies by tier: {e}")
            return []

    def get_tools_by_price_tier(self, tier_name: str):
        """Get tools by price tier"""
        try:
            query = f"""
                MATCH (tool:{self.get_namespaced_label('Tool')})-[:{self.get_namespaced_relationship('BELONGS_TO_TIER')}]->(p:{self.get_namespaced_label('PriceTier')} {{tier_name: $tier_name}})
                RETURN tool.name as name, tool.category as category, tool.monthly_cost_usd as monthly_cost
                ORDER BY tool.category, tool.name
            """
            results = self.run_query(query, {"tier_name": tier_name})
            return results
        except Exception as e:
            logger.error(f"❌ Error getting tools by tier: {e}")
            return []

    def get_price_tier_analysis(self):
        """Get price tier analysis"""
        try:
            query = f"""
                MATCH (p:{self.get_namespaced_label('PriceTier')})
                OPTIONAL MATCH (p)<-[:{self.get_namespaced_relationship('BELONGS_TO_TIER')}]-(t:{self.get_namespaced_label('Technology')})
                OPTIONAL MATCH (p)<-[:{self.get_namespaced_relationship('BELONGS_TO_TIER')}]-(tool:{self.get_namespaced_label('Tool')})
                OPTIONAL MATCH (p)<-[:{self.get_namespaced_relationship('BELONGS_TO_TIER')}]-(s:{self.get_namespaced_label('TechStack')})
                RETURN p.tier_name as tier_name, 
                       p.min_price_usd as min_price, 
                       p.max_price_usd as max_price,
                       count(DISTINCT t) as technology_count,
                       count(DISTINCT tool) as tool_count,
                       count(DISTINCT s) as stack_count
                ORDER BY p.min_price_usd
            """
            results = self.run_query(query)
            return results
        except Exception as e:
            logger.error(f"❌ Error getting price tier analysis: {e}")
            return []

    def get_optimal_combinations(self, budget: float, category: str):
        """Get optimal technology combinations"""
        try:
            query = f"""
                MATCH (t:{self.get_namespaced_label('Technology')} {{category: $category}})-[:{self.get_namespaced_relationship('BELONGS_TO_TIER')}]->(p:{self.get_namespaced_label('PriceTier')})
                WHERE p.min_price_usd <= $budget AND p.max_price_usd >= $budget
                RETURN t.name as name, t.monthly_cost_usd as monthly_cost, t.popularity_score as popularity
                ORDER BY t.popularity_score DESC, t.monthly_cost_usd ASC
                LIMIT 10
            """
            results = self.run_query(query, {"budget": budget, "category": category})
            return results
        except Exception as e:
            logger.error(f"❌ Error getting optimal combinations: {e}")
            return []

    def get_compatibility_analysis(self, tech_name: str):
        """Get compatibility analysis for a technology"""
        try:
            query = f"""
                MATCH (t:{self.get_namespaced_label('Technology')} {{name: $tech_name}})-[r:{self.get_namespaced_relationship('COMPATIBLE_WITH')}]-(compatible:{self.get_namespaced_label('Technology')})
                RETURN compatible.name as compatible_tech, 
                       compatible.category as category,
                       r.compatibility_score as score
                ORDER BY r.compatibility_score DESC
            """
            results = self.run_query(query, {"tech_name": tech_name})
            return results
        except Exception as e:
            logger.error(f"❌ Error getting compatibility analysis: {e}")
            return []

    def validate_data_integrity(self):
        """Validate data integrity in the knowledge graph"""
        try:
            # Check for orphaned nodes, missing relationships, etc.
            integrity_checks = {
                "total_nodes": 0,
                "total_relationships": 0,
                "orphaned_nodes": 0,
                "missing_price_tiers": 0
            }
            
            # Count total nodes with namespace
            node_query = f"""
                MATCH (n)
                WHERE '{self.namespace}' IN labels(n)
                RETURN count(n) as count
            """
            result = self.run_query(node_query)
            integrity_checks["total_nodes"] = result[0]['count'] if result else 0
            
            # Count total relationships with namespace
            rel_query = f"""
                MATCH ()-[r]->()
                WHERE type(r) CONTAINS '{self.namespace}'
                RETURN count(r) as count
            """
            result = self.run_query(rel_query)
            integrity_checks["total_relationships"] = result[0]['count'] if result else 0
            
            return integrity_checks
        except Exception as e:
            logger.error(f"❌ Error validating data integrity: {e}")
            return {"error": str(e)}

    def get_single_recommendation_from_kg(self, budget: float, domain: str):
        """Get single recommendation from knowledge graph"""
        logger.info(f"🚀 UPDATED METHOD CALLED: get_single_recommendation_from_kg with budget=${budget}, domain={domain}")
        
        try:
            recommendations = self.get_recommendations_by_budget(budget, domain)
            if recommendations:
                return recommendations[0]  # Return the top recommendation
            else:
                return self._create_static_fallback_recommendation(budget, domain)
        except Exception as e:
            logger.error(f"❌ Error getting single recommendation: {e}")
            return self._create_static_fallback_recommendation(budget, domain)

