import subprocess
import json
import os
import sys
from pathlib import Path
from typing import Optional
from verilog_framework.verilogtoimage.logger import get_logger


def is_wsl_environment():
    return 'microsoft' in sys.platform.lower() or os.path.exists('/proc/version')


def is_windows():
    return sys.platform.lower() == 'win32'


def windows_to_wsl_path(windows_path: str) -> str:
    path = Path(windows_path).resolve()
    drive = path.drive.lower().replace(':', '')
    rest = str(path.relative_to(path.drive)).replace('\\', '/')
    return f"/mnt/{drive}/{rest}"


def find_executable(name: str, env_var: Optional[str] = None) -> Optional[str]:
    """Find executable in PATH or custom locations"""
    logger = get_logger()
    
    # Check environment variable first
    if env_var:
        env_path = os.getenv(env_var)
        if env_path:
            exe_path = Path(env_path) / "bin" / (name + ".exe" if is_windows() else name)
            if exe_path.exists():
                logger.debug(f"Found {name} via {env_var}: {exe_path}")
                return str(exe_path)
    
    # Check common Windows paths
    if is_windows():
        common_paths = [
            f"C:\\oss-cad-suite\\bin\\{name}.exe",
            f"C:\\Program Files\\{name}\\{name}.exe",
            f"C:\\Program Files (x86)\\{name}\\{name}.exe",
        ]
        for path in common_paths:
            if Path(path).exists():
                logger.debug(f"Found {name} at: {path}")
                return path
    
    # Try with.exe on Windows
    if is_windows():
        name = name + ".exe"
    
    # Use 'which' command
    try:
        result = subprocess.run(
            ["which" if not is_windows() else "where", name],
            capture_output=True,
            text=True
        )
        if result.returncode == 0:
            exe_path = result.stdout.strip().split('\n')[0]
            logger.debug(f"Found {name} in PATH: {exe_path}")
            return exe_path
    except:
        pass
    
    return None


class YosysConverter:
    def __init__(self, yosys_path: Optional[str] = None):
        self.logger = get_logger()
        self.in_wsl = is_wsl_environment()
        self.is_windows = is_windows()
        
        # Auto-detect Yosys
        if yosys_path:
            self.yosys_cmd = yosys_path
        elif self.is_windows and not self.in_wsl:
            # Try to find Windows native Yosys
            native_yosys = find_executable("yosys", "OSS_CAD_SUITE_HOME")
            if native_yosys:
                self.yosys_cmd = native_yosys
            else:
                self.yosys_cmd = "yosys"
        else:
            self.yosys_cmd = "yosys"
        
        self.logger.debug(f"Using Yosys: {self.yosys_cmd} (Windows: {self.is_windows}, WSL: {self.in_wsl})")
    
    def verilog_to_json(self, verilog_code: str, output_file: str = None) -> Optional[str]:
        self.logger.info("Starting Verilog to JSON conversion using Yosys")
        self.logger.debug(f"Running in WSL: {self.in_wsl}, Windows: {self.is_windows}")
        
        if output_file is None:
            output_file = "output.json"
        
        temp_v_file = Path("temp_input.v")
        
        try:
            temp_v_file.write_text(verilog_code)
            self.logger.debug(f"Temporary Verilog file created: {temp_v_file}")
            
            yosys_script = f"""read_verilog {temp_v_file.name}
synth_ice40 -json {output_file}
"""
            
            script_file = Path("yosys_script.ys")
            script_file.write_text(yosys_script)
            self.logger.debug(f"Yosys script created: {script_file}")
            
            # Use native Windows Yosys if available, otherwise WSL
            if self.is_windows and not self.in_wsl:
                cmd = [self.yosys_cmd, "-s", str(script_file.absolute())]
                self.logger.debug(f"Windows command: {' '.join(cmd)}")
            elif self.in_wsl:
                cmd = ["yosys", "-s", str(script_file.absolute())]
            else:
                script_path_wsl = windows_to_wsl_path(str(script_file.absolute()))

                cmd = ["wsl", "-d", "Ubuntu", "yosys", "-s", script_path_wsl]
            
            self.logger.info(f"Executing command: {' '.join(cmd)}")
            result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
            
            if result.returncode != 0:
                self.logger.error(f"Yosys execution failed: {result.stderr}")
                return None
            
            self.logger.info("Yosys conversion completed successfully")
            return str(output_file)
            
        except subprocess.TimeoutExpired:
            self.logger.error("Yosys conversion timed out")
            return None
        except Exception as e:
            self.logger.error(f"Error during Yosys conversion: {str(e)}")
            return None
        finally:
            if temp_v_file.exists():
                temp_v_file.unlink()
                self.logger.debug(f"Temporary file cleaned up: {temp_v_file}")


class NetlistSVGConverter:
    def __init__(self):
        self.logger = get_logger()
        self.in_wsl = is_wsl_environment()
    
    def json_to_svg(self, json_file: str, output_file: str = None) -> Optional[str]:
        self.logger.info("Starting JSON to SVG conversion using netlistsvg")
        self.logger.debug(f"Running in WSL: {self.in_wsl}")
        
        if output_file is None:
            output_file = "output.svg"
        
        try:
            if self.in_wsl:
                cmd = ["netlistsvg", str(json_file), "-o", str(output_file)]
            else:
                json_path_wsl = windows_to_wsl_path(str(Path(json_file).absolute()))
                output_path_wsl = windows_to_wsl_path(str(Path(output_file).absolute()))
                cmd = ["wsl", "-d", "Ubuntu", "netlistsvg", json_path_wsl, "-o", output_path_wsl]
            
            self.logger.info(f"Executing command: {' '.join(cmd)}")
            result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
            
            if result.returncode != 0:
                self.logger.error(f"netlistsvg execution failed: {result.stderr}")
                return None
            
            self.logger.info("netlistsvg conversion completed successfully")
            return str(output_file)
            
        except subprocess.TimeoutExpired:
            self.logger.error("netlistsvg conversion timed out")
            return None
        except Exception as e:
            self.logger.error(f"Error during netlistsvg conversion: {str(e)}")
            return None


class CairoSVGConverter:
    def __init__(self):
        self.logger = get_logger()
        self.in_wsl = is_wsl_environment()
    
    def svg_to_png(self, svg_file: str, output_file: str = None, dpi: int = 96) -> Optional[str]:
        self.logger.info(f"Starting SVG to PNG conversion using CairoSVG (DPI: {dpi})")
        self.logger.debug(f"Running in WSL: {self.in_wsl}")
        
        if output_file is None:
            output_file = "output.png"
        
        try:
            # Try using Python library first
            try:
                import cairosvg
                self.logger.info("Using Python cairosvg library")
                # Calculate scale based on DPI (default 96 DPI = 1.0 scale)
                scale = dpi / 96.0
                cairosvg.svg2png(url=svg_file, write_to=output_file, dpi=dpi)
                self.logger.info("CairoSVG conversion completed successfully")
                return str(output_file)
            except ImportError:
                self.logger.debug("CairoSVG Python library not available, trying command-line tool")
                # Fallback to command-line tool
                if self.in_wsl:
                    cmd = ["cairosvg", str(svg_file), "-o", str(output_file), "-d", str(dpi)]
                else:
                    svg_path_wsl = windows_to_wsl_path(str(Path(svg_file).absolute()))
                    output_path_wsl = windows_to_wsl_path(str(Path(output_file).absolute()))
                    cmd = ["wsl", "-d", "Ubuntu", "cairosvg", svg_path_wsl, "-o", output_path_wsl, "-d", str(dpi)]
                
                self.logger.info(f"Executing command: {' '.join(cmd)}")
                result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
                
                if result.returncode != 0:
                    self.logger.error(f"CairoSVG execution failed: {result.stderr}")
                    return None
                
                self.logger.info("CairoSVG conversion completed successfully")
                return str(output_file)
            
        except subprocess.TimeoutExpired:
            self.logger.error("CairoSVG conversion timed out")
            return None
        except Exception as e:
            self.logger.error(f"Error during CairoSVG conversion: {str(e)}")
            return None
