<?php
/**
 * app/controllers/admin/tokens.php
 *
 * This is the admin app/user tokens controller.
 *
 * @version 5.0.1
 * @author  Joey Kimsey <Joey@thetempusproject.com>
 * @link    https://TheTempusProject.com
 * @license https://opensource.org/licenses/MIT [MIT LICENSE]
 */
namespace TheTempusProject\Controllers\Admin;

use TheTempusProject\Classes\Forms as TTPForms;
use TheTempusProject\Houdini\Classes\Views;
use TheTempusProject\Houdini\Classes\Issues;
use TheTempusProject\Houdini\Classes\Navigation;
use TheTempusProject\Houdini\Classes\Components;
use TheTempusProject\Houdini\Classes\Forms;
use TheTempusProject\Classes\AdminController;
use TheTempusProject\Models\Token;
use TheTempusProject\Bedrock\Functions\Input;
use TheTempusProject\Bedrock\Functions\Check;
use TheTempusProject\Hermes\Functions\Redirect;
use TheTempusProject\Bedrock\Functions\Session;
use TheTempusProject\Hermes\Functions\Route as Routes;
use TheTempusProject\Bedrock\Functions\Upload;
use RecursiveIteratorIterator;
use RecursiveDirectoryIterator;
use FilesystemIterator;

class Images extends AdminController {
    private $directories = [
        APP_ROOT_DIRECTORY . 'images',
        APP_ROOT_DIRECTORY . 'app/images',
        APP_ROOT_DIRECTORY . 'app/plugins'
    ];

    private $spacer = [];

    private $excludedDirectories = [
        '.',
        '..',
        'vendor',
        'docker',
        'logs',
        'gitlab',
        'uploads',
        'config',
    ];

    public function upload() {
        if ( Input::exists( 'submit' ) ) {
            $route = '';
            $destination = '';
            if ( !TTPForms::check( 'addImage' ) ) {
                Issues::add( 'error', [ 'There was an error with your image upload.' => Check::userErrors() ] );
            } else {
                $folder = Input::post( 'folderSelect' ) . DIRECTORY_SEPARATOR;
                // dv( $folder );
                $upload = Upload::image( 'uploadImage', $folder );
                if ( $upload ) {
                    $route = str_replace( APP_ROOT_DIRECTORY, '', $folder );
                    $destination = $route . Upload::last();
                    Issues::add( 'success', 'Image uploaded.' );
                } else {
                    Issues::add( 'error', [ 'There was an error with your image upload.' => Check::userErrors() ] );
                }
            }
        }

        $folders = $this->getDirectoriesRecursive( APP_ROOT_DIRECTORY );
        $folderHtml = $this->generateFolderHtml( $folders );
        Components::set( 'FOLDER_SELECT_ROOT', APP_ROOT_DIRECTORY );
        Components::set( 'FOLDER_SELECT', Views::simpleView( 'forms.folderSelect', $folderHtml ) );
        Views::view( 'admin.images.upload' );
    }












    







    private function getFolderObject( $folder, $subdirs = '' ) {
        $names = explode( DIRECTORY_SEPARATOR, $folder );
        $folderName = array_pop( $names );
        $out = [
            'spacer' => implode( '', $this->spacer ),
            'folderName' => $folderName,
            'location' => $folder,
            'subdirs' => $subdirs,
        ];
        if ( ! empty( $subdirs ) ) {
            $out['folderexpand'] = '<i class="fa fa-caret-down"></i>';
        } else {
            $out['folderexpand'] = '';
        }
        return (object) $out;
    }

    private function generateFolderHtml( $folders ) {
        $rows = [];
        foreach ( $folders as $top => $sub ) {
            $object = $this->getFolderObject( $top );
            if ( $top == $sub ) {
                $html = '';
            } else {
                $this->spacer[] = '-> ';
                $children = $this->generateFolderHtml( $sub );
                array_pop( $this->spacer );
                Components::set( 'parentfolderName', $object->folderName );
                $html = Views::simpleView( 'forms.folderSelectParent', $children );
                Components::set( 'parentfolderName', '' );
            }
            $rows[] = $this->getFolderObject( $top, $html );
        }
        return $rows;
    }

    private function getDirectoriesRecursive( $directory ) {
        $dirs = [];

        $directory = rtrim( $directory, DIRECTORY_SEPARATOR );
        $directory = $directory. DIRECTORY_SEPARATOR;

        $files = scandir( $directory );
        $filteredFiles = array_values( array_diff( $files, $this->excludedDirectories ) );

        foreach ( $filteredFiles as $key => $filename ) {
            $long_name = $directory . $filename;
            $is_dir = ( ( strpos( $filename, '.' ) === false ) && ( is_dir( $long_name ) === true ) );
            if ( $is_dir ) {
                $recursive_dirs = $this->getDirectoriesRecursive( $long_name );
                if ( empty( $recursive_dirs ) ) {
                    $recursive_dirs = $long_name;
                }
                $dirs[$long_name] = $recursive_dirs;
            }
        }

        return $dirs;
    }























    public function __construct() {
        parent::__construct();
        self::$title = 'Admin - Images';
    }

    public function create() {
        if ( Input::exists( 'submit' ) ) {
            if ( !TTPForms::check( 'addImage' ) ) {
                Issues::add( 'error', [ 'There was an error with your image.' => Check::userErrors() ] );
            }

            if ( Input::exists( 'folder' ) ) {
                $folder = Input::post('folder');
            } else {
                // IMAGE_DIRECTORY
                $folder = UPLOAD_DIRECTORY . App::$activeUser->username . DIRECTORY_SEPARATOR . 'images' . DIRECTORY_SEPARATOR;
            }

            $upload = Upload::image( 'upload', $folder );

            if ( $upload ) {
                $route = str_replace( APP_ROOT_DIRECTORY, '', $folder );
                $out = $route . Upload::last();
            } else {
                Debug::error( 'There was an error with your upload.');
                Issues::add( 'error', [ 'There was an error with your upload.' => Check::userErrors() ] );
            }









            // if ( self::$token->create(
            //     Input::post( 'name' ),
            //     Input::post( 'notes' ),
            //     Input::post( 'token_type' )
            // ) ) {
            //     Session::flash( 'success', 'Token Created' );
            //     Redirect::to( 'admin/images' );
            // }


        }
        Views::view( 'admin.images.create' );
    }

    public function delete() {
        if ( ! Input::exists( 'fileLocation' ) ) {
            Session::flash( 'warning', 'Unknown image.' );
            Redirect::to( 'admin/images' );
        }
    
        $fileLocation = Input::get('fileLocation');
    
        // Ensure the file exists
        if ( ! file_exists( $fileLocation ) ) {
            Session::flash('error', 'File does not exist.');
            Redirect::to('admin/images');
        }
    
        // Check if the file is an image
        $validMimeTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
        $fileMimeType = mime_content_type( $fileLocation );
    
        if ( ! in_array( $fileMimeType, $validMimeTypes ) ) {
            Session::flash('error', 'Invalid file type. Only images can be deleted.');
            Redirect::to('admin/images');
        }
    
        // Attempt to delete the file
        if (@unlink($fileLocation)) {
            Session::flash('success', 'Image deleted.');
        } else {
            Session::flash('error', 'Failed to delete the image.');
        }
    
        Redirect::to('admin/images');
    }

    public function rename() {
        
        if ( ! Input::exists( 'fileLocation' ) ) {
            Session::flash( 'warning', 'Unknown image.' );
            Redirect::to( 'admin/images' );
        }
        
        Components::set( 'filelocation', Input::get( 'fileLocation' ) );

        if ( Input::exists( 'submit' ) ) {
            if ( !TTPForms::check( 'renameIImage' ) ) {
                Issues::add( 'error', [ 'There was an error renaming the image.' => Check::userErrors() ] );
            } else {
                $result = $this->renameFile( Input::post( 'filelocation' ), Input::post( 'newname' ) );
                
                if ( ! empty( $result ) ) {
                    Session::flash( 'success', 'Image has been renamed.' );
                    Redirect::to( 'admin/images' );
                } else {
                    Issues::add( 'error', [ 'There was an error with the install.' => $this->installer->getErrors() ] );
                }
            }
        }
    
        return Views::view( 'admin.images.rename' );
    }

    public function index() {
        return Views::view( 'admin.images.list.combined', $this->getAllImageDetails() );
    }

    public function view() {
        if ( Input::exists( 'fileLocation' ) ) {
            return Views::view( 'admin.images.view', $this->getImageByLocation( Input::get( 'fileLocation' ) ) );
        }
        return $this->index();
    }

    private function getAllImages() {
        $files = [];
        foreach ($this->directories as $dir) {
            if ($dir === 'app/plugins') {
                $pluginDirs = glob($dir . '/*', GLOB_ONLYDIR);
                foreach ($pluginDirs as $pluginDir) {
                    $imageDir = $pluginDir . '/images';
                    if (is_dir($imageDir)) {
                        $files = array_merge($files, $this->scanDirectoryRecursively($imageDir));
                    }
                }
            } else {
                $files = array_merge($files, $this->scanDirectory($dir));
            }
        }
        return $files;
    }

    private function scanDirectory($path) {
        return glob($path . '/*.{jpg,jpeg,png,gif,webp}', GLOB_BRACE) ?: [];
    }

    private function scanDirectoryRecursively($path) {
        $files = [];
        $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS));

        foreach ($iterator as $file) {
            if (preg_match('/\.(jpg|jpeg|png|gif|webp)$/i', $file->getFilename())) {
                $files[] = $file->getPathname();
            }
        }

        return $files;
    }

    private function getAllImageDetails() {
        $images = [];
        $files = $this->getAllImages();
        foreach ( $files as $file ) {
            $images[] = $this->getImageByLocation( $file );
        }
        return $images;
    }

    private function getImageByLocation( $location ) {
        $realPath = realpath( $location );
        
        return (object) [
            'filename'     => basename( $location ),
            'extension'    => pathinfo( $location , PATHINFO_EXTENSION),
            'fileSize'     => $this->formatFileSize(filesize( $location )),
            'location'     => $realPath,
            'locationSafe' => urlencode( $realPath ),
            'url'          => Routes::getAddress() . str_replace( APP_ROOT_DIRECTORY, '', $realPath ),
            'folder'       => dirname( $location )
        ];
    }

    private function formatFileSize($size) {
        $units = ['B', 'KB', 'MB', 'GB', 'TB'];
        $i = 0;
        while ($size >= 1024 && $i < count($units) - 1) {
            $size /= 1024;
            $i++;
        }
        return round($size, 2) . ' ' . $units[$i];
    }

    private function renameFile( $currentLocation, $newFilename ) {
        // Ensure the file exists
        if (!file_exists($currentLocation)) {
            throw new \Exception("File does not exist: $currentLocation");
        }
    
        // Extract directory and current extension
        $directory = dirname($currentLocation);
        $currentExtension = pathinfo($currentLocation, PATHINFO_EXTENSION);
        $newExtension = pathinfo($newFilename, PATHINFO_EXTENSION);
    
        // Ensure the file extension has not changed
        if (strcasecmp($currentExtension, $newExtension) !== 0) {
            throw new \Exception("File extension cannot be changed.");
        }
    
        // Construct the new file path
        $newLocation = $directory . DIRECTORY_SEPARATOR . $newFilename;
    
        // Ensure the new file name does not already exist
        if (file_exists($newLocation)) {
            throw new \Exception("A file with the new name already exists: $newFilename");
        }
    
        // Attempt to rename the file
        if (!rename($currentLocation, $newLocation)) {
            throw new \Exception("Failed to rename file.");
        }
        return true;
    }
}
