import re
import json
import subprocess
import sys
import requests
import time
import tempfile
from pathlib import Path
from contextlib import redirect_stdout

try:
    from importlib.metadata import distributions  # Python 3.8+
except ImportError:
    from importlib_metadata import distributions  # Python < 3.8

class ProgramGenerator:
    def __init__(self):
        self.model = 'qwen2.5-coder'
        self.api_url = "http://localhost:11434/api/generate"
        self.headers = {"Content-Type": "application/json"}
        self.temp_dir = Path(tempfile.gettempdir()) / "program_generator"
        self.temp_dir.mkdir(exist_ok=True)
        self.history_dir = self.temp_dir / "history"
        self.history_dir.mkdir(exist_ok=True)

    def install_missing_modules(self, code):
        """Detectează și instalează module lipsă din cod"""
        required_modules = re.findall(r'import ([^ \n.,]+)', code)
        required_modules.extend(re.findall(r'from ([^ \n.,]+)', code))
        
        installed_modules = {dist.metadata["Name"] for dist in distributions()}
        
        missing_modules = set(required_modules) - installed_modules
        for module in missing_modules:
            if module not in ['sys', 'os', 're', 'json', 'time']:  # Module standard
                print(f"\nInstalare modul {module}...")
                try:
                    subprocess.check_call([sys.executable, "-m", "pip", "install", module],
                                        stdout=subprocess.DEVNULL,
                                        stderr=subprocess.DEVNULL)
                    print(f"Modulul {module} a fost instalat cu succes!")
                except Exception as e:
                    print(f"Nu s-a putut instala modulul {module}: {str(e)}")

    def generate_filename(self, idea, temp=False, history=False):
        """Generează nume de fișier bazat pe idee"""
        filename = re.sub(r'[^a-zA-Z0-9\s]', '', idea.lower())
        filename = re.sub(r'\s+', '_', filename.strip())
        timestamp = time.strftime("%Y%m%d_%H%M%S")
        filename = f"{filename[:30]}_{timestamp}.py"
        
        if temp:
            return self.temp_dir / filename
        if history:
            return self.history_dir / filename
        return filename

    def format_response_line(self, line):
        try:
            data = json.loads(line)
            return data.get('response', '')
        except json.JSONDecodeError:
            return line

    def extract_python_code(self, text):
        patterns = [
            r"```python\n(.*?)\n```",
            r"```\n(.*?)\n```",
            r"```python(.*?)```",
            r"`{3,}(.*?)`{3,}"
        ]
        
        for pattern in patterns:
            match = re.search(pattern, text, re.DOTALL)
            if match:
                return match.group(1).strip()
        return text.strip()

    def generate_code(self, idea, is_correction=False):
        print("\nGenerare cod în progres...")
        sys.stdout.flush()
        
        prompt = idea if is_correction else f"Generează un program Python care să îndeplinească următoarea cerință: {idea}"
        payload = {
            "model": self.model,
            "prompt": prompt,
            "stream": True
        }

        try:
            response = requests.post(self.api_url, json=payload, headers=self.headers, stream=True)
            if response.status_code == 200:
                full_response = ""
                for line in response.iter_lines():
                    if line:
                        text = self.format_response_line(line.decode('utf-8'))
                        if text:
                            full_response += text
                
                code = self.extract_python_code(full_response)
                if code:
                    print("\nCod generat:")
                    print(code)
                    return code
            return ""

        except requests.exceptions.ConnectionError:
            print("Nu s-a putut conecta la serverul local Ollama")
        except Exception as e:
            print(f"Eroare la generarea codului: {str(e)}")
        return ""

    def run_code_safely(self, code, temp_file):
        """Rulează codul într-un fișier temporar cu gestiunea erorilor"""
        try:
            # Adaugă gestiunea erorilor în cod
            safe_code = f"""
try:
{chr(10).join('    ' + line for line in code.split(chr(10)))}
except Exception as e:
    print(f'Eroare: {{str(e)}}')
"""
            # Scrie codul în fișierul temporar
            with open(temp_file, 'w', encoding='utf-8') as f:
                f.write(safe_code)
            
            # Rulează codul
            result = subprocess.run([sys.executable, temp_file], 
                                  capture_output=True, 
                                  text=True)
            return result
        except Exception as e:
            print(f"Eroare la rularea codului: {str(e)}")
            return None

    def save_code(self, code, idea):
        filename = self.generate_filename(idea)
        history_filename = self.generate_filename(idea, history=True)
        try:
            with open(filename, 'w', encoding='utf-8') as f:
                f.write(code)
            with open(history_filename, 'w', encoding='utf-8') as f:
                f.write(code)
            print(f"\nCod salvat cu succes în fișierul: {filename}")
            return True
        except Exception as e:
            print(f"Eroare la salvarea fișierului: {str(e)}")
            return False

    def run_code(self, code, original_idea):
        print("\nRulare program...")
        max_attempts = 3
        attempt = 0
        
        # Verifică și instalează module lipsă înainte de rulare
        self.install_missing_modules(code)
        
        temp_file = self.generate_filename(original_idea, temp=True)
        
        while attempt < max_attempts:
            result = self.run_code_safely(code, temp_file)
            
            if result and result.returncode == 0:
                print("\nIeșire program:")
                print(result.stdout)
                self.save_code(code, original_idea)
                return True
            
            if result:
                print(f"\nEroare detectată: {result.stderr}")
                print("Încercare de corectare a codului...")
                
                corrected_code = self.generate_code(
                    f"Corectează acest cod Python care a dat eroarea: {result.stderr}\nCod de corectat:\n{code}",
                    is_correction=True
                )
                
                if corrected_code and corrected_code != code:
                    print("\nCod corectat:")
                    print(corrected_code)
                    code = corrected_code
                    attempt += 1
                    continue
            
            print("Nu s-a putut corecta codul")
            break

        try:
            temp_file.unlink()  # Șterge fișierul temporar
        except:
            pass
            
        return False

    def run(self):
        print("Generator de Programe Python v3.0")
        print("--------------------------------")
        while True:
            idea = input("\nIntrodu ideea ta de program (sau 'exit' pentru ieșire): ")
            if idea.lower() == 'exit':
                break
                
            if idea:
                code = self.generate_code(idea)
                if code:
                    self.run_code(code, idea)
            
            print("\n" + "="*50 + "\n")

def main():
    try:
        import requests
    except ImportError:
        subprocess.check_call([sys.executable, "-m", "pip", "install", "requests"])
    
    generator = ProgramGenerator()
    generator.run()

if __name__ == "__main__":
    main()
