<?php
namespace boru\boruai\Vtiger;

use boru\boruai\BoruAI;
use boru\boruai\Config;
use boru\query\Query;
use Exception;

class Vtiger {
    private static $schemaCache = [];
    private static $moduleCache = [];

    private static $vtigerConfigVariables = [];

    private $rootDirectory;

    private static $instance = null;

    public function __construct($rootDirectory=null) {
        if($rootDirectory !== null) {
            $this->rootDirectory = $rootDirectory;
        } else {
            $this->rootDirectory = static::rootDir();
        }
        static::$instance = $this;
        //static::$moduleCache = VtigerModule::listModules();
    }

    public static function instance() {
        if(static::$instance === null) {
            static::$instance = new Vtiger();
        }
        return static::$instance;
    }

    public function schema($module) {
        try {
            $module = $this->getModule($module);
        } catch(Exception $e) {
            return [];
        }
        if(!is_array($module) || empty($module) || !isset($module["tabid"])) {
            return [];
        }
        if(isset(static::$schemaCache[$module["tabid"]])) {
            return static::$schemaCache[$module["tabid"]];
        }
        $schema = [];
        $query = $this->makeQuery($module["name"]);
        if($query === false) {
            //no query object.
        } else {
            $schema["select"] = $this->makeQuery($module["name"])->toSql();
        }
        $schema["fields"] = $module["column_fields"];
        $schema["related_lists"] = $module["related_lists"];
        static::$schemaCache[$module["tabid"]] = $schema;
        return $schema;
    }

    /**
     * Get a query object for a module
     * @param string $module
     * @return Query
     */
    public function makeQuery($module,$selectFields="*") {
        $moduleData = $this->getModule($module);
        if(!is_array($moduleData) || empty($moduleData)) {
            return false;
        }
        if(!isset($moduleData["variables"]["tab_name_index"])) {
            $md = $moduleData["variables"];
            if(isset($md["table_name"]) && isset($md["table_index"])) {
                $tni = [];
                $tni["vtiger_crmentity"] = "crmid";
                $tni[$md["table_name"]] = $md["table_index"];
                if(isset($md["customFieldTable"]) && is_array($md["customFieldTable"]) && count($md["customFieldTable"]) == 2) {
                    $tni[$md["customFieldTable"][0]] = $md["customFieldTable"][1];
                }
                $moduleData["variables"]["tab_name_index"] = $tni;
            }
            if(!isset($moduleData["variables"]["tab_name_index"])) {
                print_r($moduleData["variables"]);
                throw new Exception("Module data does not contain tab_name_index");
            }
        }
        $tables = $moduleData["variables"]["tab_name_index"];

        //get the first table and field
        $firstTable = array_keys($tables)[0];
        $firstField = $tables[$firstTable];

        //build the query
        $query = Query::create()->select($selectFields)->from($firstTable);
        
        //add left joins for each table
        $joinType = "INNER JOIN";
        foreach($tables as $tableName=>$joinField) {
            if($tableName != $firstTable) {
                $query->join($tableName,["$firstTable.$firstField","=","$tableName.$joinField"],$joinType);
                $joinType = "LEFT JOIN";
            }
            
        }
        return $query;
    }

    public function getModule($tabIdOrModuleName) {
        if(!is_numeric($tabIdOrModuleName)) {
            $module = VtigerModule::getModuleByName($tabIdOrModuleName);
            if(!is_array($module)) {
                return [];
            }
            $tabId = $module['tabid'];
            $moduleName = $module['name'];
        } else {
            $tabId = $tabIdOrModuleName;
            //check cache just in case
            if(isset(static::$moduleCache[$tabId])) {
                return static::$moduleCache[$tabId];
            }
            $module = VtigerModule::getModuleById($tabId);
            $moduleName = $module['name'];
        }
        
        //check cache again for tabid
        if(isset(static::$moduleCache[$tabId])) {
            return static::$moduleCache[$tabId];
        }

        //extract module data from module file which is in modules/{module}/{module}.php (Vtiger 5.x to present as of December 2024)
        $moduleFileName = $moduleName;
        if($moduleFileName == "Calendar") {
            $data["table_name"] = "vtiger_activity";
            $data["table_index"] = "activityid";
            $data["customFieldTable"] = ["vtiger_activitycf","activityid"];
        } else {
            $modulePath = $this->rootDirectory."/modules/".$moduleFileName."/".$moduleFileName.".php";
            if(!file_exists($modulePath)) {
                throw new Exception("Module not found: $moduleFileName");
            }
            $data = static::extractVariablesFromModule($modulePath);
        }
        $module["column_fields"] = VtigerFields::getFields($moduleName);
        $module["related_lists"] = VtigerRelatedLists::getRelatedLists($moduleName);
        $module["variables"] = $data;
        $module["tablabel"] = static::translate($moduleName,$module["tablabel"]);
        static::$moduleCache[$tabId] = $module;
        return static::$moduleCache[$tabId];
    }

    public static function rootDir($rootDir=null,$save=false) {
        if($rootDir !== null) {
            Config::set("vtiger.root_dir",$rootDir);
            if($save) {
                Config::save();
            }
        }
        $dir = Config::get("vtiger.root_dir", false);
        if($dir === false) {
            $dir = static::findVtigerRoot();
            if($dir === false) {
                throw new Exception("Vtiger root directory not found. Please set it in config.json or use Vtiger::rootDir(\$dir) to set it.");
            }
            Config::set("vtiger.root_dir",$dir);
            if($save) {
                Config::save();
            }
        }
        return Config::get("vtiger.root_dir");
    }

    public static function languageContainer() {
        return static::$languageContainer;
    }

    public static function translate($module,$key,$language="en_us") {
        try {
            $lang = static::loadLanguageStrings($module,$language);
        } catch(Exception $e) {
            try {
                $lang = static::loadLanguageStrings("Vtiger",$language);
            } catch(Exception $e) {
                $lang = [];
            }
        }
        if(isset($lang[$key])) {
            return $lang[$key];
        } elseif($module != "Vtiger") {
            return static::translate("Vtiger",$key,$language);
        }
        return $key;
    }

    private static $languageContainer = [];
    public static function loadLanguageStrings($module,$language="en_us") {
        if(!isset(static::$languageContainer[$language][$module])) {
            $jsLanguageStrings = [];
            $langFile = static::rootDir()."/languages/$language/$module.php";
            $langFile2 = static::rootDir()."/modules/$module/languages/$language.lang.php";
            if(file_exists($langFile)) {
                include($langFile);
                if(isset($languageStrings)) {
                    static::$languageContainer[$language][$module] = $languageStrings;
                } elseif(isset($mod_strings)) {
                    static::$languageContainer[$language][$module] = $mod_strings;
                }
            } elseif(file_exists($langFile2)) {
                include($langFile2);
                if(isset($languageStrings)) {
                    static::$languageContainer[$language][$module] = $languageStrings;
                } elseif(isset($mod_strings)) {
                    static::$languageContainer[$language][$module] = $mod_strings;
                }
            }else {
                throw new Exception("Language file not found: $langFile");
            }
        }
        return isset(static::$languageContainer[$language][$module]) ? static::$languageContainer[$language][$module] : [];

    }

    public static function extractVariablesFromModule($filePath) {
        // Check if the file exists
        if (!file_exists($filePath)) {
            die("File not found: $filePath\n");
        }
    
        // Read the file content
        $fileContent = file_get_contents($filePath);
    
        // Match all class variables (supports public, protected, and private)
        preg_match_all(
            '/var\s+\$([a-zA-Z0-9_]+)\s*=\s*(.*?);/m',
            $fileContent,
            $matches,
            PREG_SET_ORDER
        );
    
        // Parse the matched variables
        $variables = [];
        foreach ($matches as $match) {
            $name = $match[1];
            $value = trim($match[2]);
    
            // Try to parse the value as JSON or string, or leave as is
            if (substr($value, 0, 1) === '[' || substr($value, 0, 1) === '{') {
                $decoded = json_decode($value, true);
                $value = $decoded !== null ? $decoded : $value;
            } elseif (preg_match('/^["\'].*["\']$/', $value)) {
                $value = trim($value, '"\''); // Remove surrounding quotes
            }
            if(substr($value,0, 6) == "Array(" || substr($value,0, 6) == "array(") {
                $value = eval("return $value;");
            }
            $variables[$name] = $value;
        }
    
        return $variables;
    }

    private static function findVtigerRoot($directory=null) {
        if(is_null($directory) || empty($directory)) {
            $directory = __DIR__;
        }
        $dirParts = explode(DIRECTORY_SEPARATOR,$directory);
                
        if(($dir = static::checkIsVtigerDirectory($directory)) !== false) {
            //config.inc.php exists in this directory.. weird but ok..
            return $dir;
        }

        $continue=true;
        while($continue) {
            $dropoff = array_pop($dirParts);
            if(empty($dirParts)) {
                $continue=false;
                break;
            }
            $dirPath = implode(DIRECTORY_SEPARATOR,$dirParts);
            if(($dir = static::checkIsVtigerDirectory($dirPath)) !== false) {
                return $dir;
            }
        }
        return false;
    }
    private static function checkIsVtigerDirectory($directory) {
        $filesRequiredForVtiger = [
            "config.inc.php",
            "index.php",
            "vtigerversion.php",
            "config.php",
            "tabdata.php",
        ];
        foreach($filesRequiredForVtiger as $file) {
            if(!file_exists($directory.DIRECTORY_SEPARATOR.$file)) {
                return false;
            }
        }
        return true;
    }
    public static function site_URL() {
        $siteURL = static::getVtigerConfigVariables();
        if(isset($siteURL["site_URL"])) {
            return $siteURL["site_URL"];
        }
        return false;
    }
    public static function getVtigerConfigVariables() {
        if(empty(static::$vtigerConfigVariables)) {
            $configFile = static::rootDir().DIRECTORY_SEPARATOR."config.inc.php";
            if(!file_exists($configFile)) {
                return false;
            }
            //$variables = static::extractVariablesFromModule($configFile);
            //need a similar function to extract variables from config.inc.php
            $variables = [];
            $configContent = file_get_contents($configFile);
            preg_match_all(
                '/\$([a-zA-Z0-9_]+)\s*=\s*(.*?);/m',
                $configContent,
                $matches,
                PREG_SET_ORDER
            );
            foreach ($matches as $match) {
                $name = $match[1];
                $value = trim($match[2]);
                if (substr($value, 0, 1) === '[' || substr($value, 0, 1) === '{') {
                    $decoded = json_decode($value, true);
                    $value = $decoded !== null ? $decoded : $value;
                } elseif (preg_match('/^["\'].*["\']$/', $value)) {
                    $value = trim($value, '"\''); // Remove surrounding quotes
                }
                if(substr($value,0, 6) == "Array(" || substr($value,0, 6) == "array(") {
                    $value = eval("return $value;");
                }
                $variables[$name] = $value;
            }

            static::$vtigerConfigVariables = $variables;
        }
        return static::$vtigerConfigVariables;
    }
}