<?php
namespace boru\boruai\Tools;

use ReflectionClass;
use Exception;

class Util {
    public static function globalIncludeFile($filePath) {
        if (file_exists($filePath)) {
            // Use an anonymous scope to capture the file's variables
            $variables = array();
            if (file_exists($filePath)) {
                // Use a function to create a local scope and capture variables
                $captureVars = function($file) {
                    include $file;
                    return get_defined_vars();
                };
                $variables = $captureVars($filePath);
            }
    
            // Extract the variables into the global scope
            foreach ($variables as $key => $value) {
                $GLOBALS[$key] = $value;
            }
        } else {
            throw new Exception("File '$filePath' does not exist.");
        }
    }
    public static function getClassFileContents(string $className) {
        try {
            echo "Getting class file contents for '$className'..." . PHP_EOL;
            // Resolve class name if it doesn't exist in the global namespace
            if (!class_exists($className) && !interface_exists($className) && !trait_exists($className)) {
                //if $className contains a single backslash, then we need to double it before resolving
                if(strpos($className, "\\") !== false) {
                    $className = str_replace("\\", "\\\\", $className);
                }
                $className = static::resolveNamespacedClassName($className);
            }

            echo "Resolved class name: '$className'" . PHP_EOL;
            // Check again if the resolved class exists
            if (!class_exists($className) && !interface_exists($className) && !trait_exists($className)) {
                throw new Exception("Class, interface, or trait '$className' does not exist.");
            }

            // Collect file contents from the given class and its dependencies
            $collectedFiles = [];

            // Recursive function to gather class/trait/interface files
            $collectFiles = function ($name) use (&$collectedFiles, &$collectFiles) {
                $reflection = new ReflectionClass($name);
                $filePath = $reflection->getFileName();

                if ($filePath && file_exists($filePath) && !in_array($filePath, $collectedFiles)) {
                    $collectedFiles[] = $filePath;
                }

                // Collect parent class
                $parentClass = $reflection->getParentClass();
                if ($parentClass) {
                    $collectFiles($parentClass->getName());
                }

                // Collect traits
                $traits = $reflection->getTraits();
                foreach ($traits as $trait) {
                    $collectFiles($trait->getName());
                }

                // Collect interfaces
                $interfaces = $reflection->getInterfaces();
                foreach ($interfaces as $interface) {
                    $collectFiles($interface->getName());
                }
            };

            // Start collecting files from the main class
            $collectFiles($className);

            // Concatenate the contents of all collected files
            $allContents = "";
            foreach ($collectedFiles as $file) {
                $allContents .= "\n--- File: $file ---\n";
                $allContents .= file_get_contents($file);
            }

            return $allContents;
        } catch (Exception $e) {
            // Handle any exceptions and return null if something goes wrong
            echo "Error: " . $e->getMessage() . PHP_EOL;
            return null;
        }
    }

    /**
     * Resolves a class name to its fully qualified name if it is namespaced.
     * @param string $className 
     * @return string 
     */
    public static function resolveNamespacedClassName(string $className) {
        foreach (get_declared_classes() as $declaredClass) {
            if (substr($declaredClass, -strlen($className)) === $className && 
                (strpos($declaredClass, "\\") !== false)) {
                return $declaredClass;
            }
        }

        foreach (get_declared_interfaces() as $declaredInterface) {
            if (substr($declaredInterface, -strlen($className)) === $className && 
                (strpos($declaredInterface, "\\") !== false)) {
                return $declaredInterface;
            }
        }

        foreach (get_declared_traits() as $declaredTrait) {
            if (substr($declaredTrait, -strlen($className)) === $className && 
                (strpos($declaredTrait, "\\") !== false)) {
                return $declaredTrait;
            }
        }

        return $className; // Fallback to the original name
    }

    public static function makeBase64url($pathToFile,$mimeType=null) {
        if($mimeType && !file_exists($pathToFile)) {
            $base64 = base64_encode($pathToFile);
        } else {
            if(!file_exists($pathToFile)) {
                throw new \Exception("File not found");
            }
            if(!$mimeType) {
                $mimeType = static::mimeTypeFromPath($pathToFile);
            }
            $fileContent = file_get_contents($pathToFile);
            $base64 = base64_encode($fileContent);
        }
        $base64String = "data:".$mimeType.";base64,".$base64;
        return $base64String;
    }

    private static function compressFileDataEntries($input) {
        $compressed = [];
        foreach ($input as $key => $value) {
            if (is_string($value)) {
                if(preg_match('#^data:.*;base64,#',$value)) {
                    $b64 = preg_replace('#^data:.*;base64,#','',$value);
                    $binary = base64_decode($b64);
                    $gzipped = gzencode($binary, 9, FORCE_GZIP);
                    $compressed[$key] = "";// "data:application/gzip;base64," . base64_encode($gzipped);
                } else {
                    $compressed[$key] = $value;
                }
            } elseif (is_array($value)) {
                $compressed[$key] = self::compressFileDataEntries($value);
            } else {
                $compressed[$key] = $value;
            }
        }
        return $compressed;
    }
    public static function compress($data,$level=9) {
        if(!is_array($data)) {
            $check = json_decode($data,true);
            if($check) {
                $data = $check;
            }
        }
        if (is_array($data)) {
            //$data = json_encode($data,JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE);
            $data = json_encode(static::compressFileDataEntries($data),JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE);
        }
        if (is_string($data)) {
            return base64_encode(gzencode($data, $level));
        }
        return null;
    }
    public static function decompress($data) {
        if (is_string($data)) {
            $data = base64_decode($data);
            return gzdecode($data);
        }
        return null;
    }
    public static function mimeTypeFromPath($pathToFile, $fallbackMimeType = null) {
        $extension = strtolower(pathinfo($pathToFile, PATHINFO_EXTENSION));
        $mimeMap = [
            'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
            'xls' => 'application/vnd.ms-excel',
            'csv' => 'text/csv',
            'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
            'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
        ];
        if ($extension && isset($mimeMap[$extension])) {
            return $mimeMap[$extension];
        }
        if ($fallbackMimeType) {
            return $fallbackMimeType;
        }
        return mime_content_type($pathToFile);
    }
}
