<?php

namespace WPIDE\App\Services\Storage;

use WPIDE\App\Classes\Freemius;
use const WPIDE\Constants\DIR;
use const WPIDE\Constants\CONTENT_DIR;
use const WPIDE\Constants\FATAL_ERROR_DROPIN;
use const WPIDE\Constants\IMAGE_DATA_DIR;
use const WPIDE\Constants\TMP_DIR;
use const WPIDE\Constants\WP_PATH;
use WPIDE\App\AppConfig;
use WPIDE\App\Services\Storage\Adapters\WPFileSystem;
use WPIDE\App\Services\Storage\Adapters\DefaultFileSystem;
class LocalFileSystem {
    public static function load( $root = null ) : Filesystem {
        $fs = new Filesystem();
        $fs->init( self::getConfig( $root ) );
        return $fs;
    }

    public static function getConfig( $root = null ) : array {
        if ( empty( $root ) ) {
            $root = self::getRootDir();
        }
        if ( !str_contains( $root, WP_PATH ) ) {
            $root = WP_PATH . $root;
        }
        $root .= '/';
        $root = wp_normalize_path( $root );
        $excluded = [
            'dirs'  => LocalFileSystem::excludedDirs(),
            'files' => LocalFileSystem::excludedFiles(),
        ];
        return [
            'root'           => $root,
            'separator'      => '/',
            'excluded_dirs'  => ( !empty( $excluded['dirs'] ) ? $excluded['dirs'] : [] ),
            'excluded_files' => ( !empty( $excluded['files'] ) ? $excluded['files'] : [] ),
            'config'         => [],
            'adapter'        => function () use($root) {
                $permissions = [
                    'file' => [
                        'public'  => ( defined( 'FS_CHMOD_FILE' ) ? FS_CHMOD_FILE : (( fileperms( WP_PATH . '/index.php' ) ? 0644 : 0777 )) ),
                        'private' => 0600,
                    ],
                    'dir'  => [
                        'public'  => ( defined( 'FS_CHMOD_DIR' ) ? FS_CHMOD_DIR : (( fileperms( WP_PATH ) ? 0755 : 0777 )) ),
                        'private' => 0700,
                    ],
                ];
                global $wp_filesystem;
                $use_wp_filesystem = false;
                // Try and use WP filesystem
                if ( function_exists( 'request_filesystem_credentials' ) ) {
                    if ( defined( 'FS_METHOD' ) ) {
                        if ( !defined( 'WPIDE_FS_METHOD_FORCED_ELSEWHERE' ) ) {
                            define( 'WPIDE_FS_METHOD_FORCED_ELSEWHERE', FS_METHOD );
                        }
                    } else {
                        define( 'FS_METHOD', 'direct' );
                    }
                    ob_start();
                    $credentials = request_filesystem_credentials( '', FS_METHOD );
                    ob_end_clean();
                    $use_wp_filesystem = !empty( $wp_filesystem ) && wp_filesystem( $credentials ) === true;
                }
                if ( $use_wp_filesystem ) {
                    return new WPFileSystem(
                        $root,
                        $wp_filesystem,
                        1,
                        $permissions
                    );
                } else {
                    return new DefaultFileSystem(
                        $root,
                        LOCK_EX,
                        1,
                        $permissions
                    );
                }
            },
        ];
    }

    public static function getRootDir() {
        return AppConfig::get( 'file.root', '/' );
    }

    public static function advancedModeEnabled() : bool {
        $advanced_mode = (bool) AppConfig::get( 'file.advanced_mode', false );
        if ( $advanced_mode ) {
            AppConfig::update( 'file.advanced_mode', false );
        }
        $rootDefault = AppConfig::getField( 'file.root.default' );
        if ( self::isRootExcluded() ) {
            AppConfig::update( 'file.root', $rootDefault );
        }
        return false;
    }

    public static function excludedEntries( $type ) : array {
        $entries = AppConfig::get( 'file.filter_entries', [] );
        $entries = ( is_array( $entries ) ? $entries : [] );
        return array_filter( $entries, function ( $entry ) use($type) {
            if ( $type === 'dir' ) {
                return substr( $entry, -1 ) === '/';
            } else {
                return substr( $entry, -1 ) !== '/';
            }
        } );
    }

    public static function excludedDirs( $forceSafeMode = false ) : array {
        $user_excluded_dirs = self::excludedEntries( 'dir' );
        $user_excluded_dirs = array_merge( [IMAGE_DATA_DIR, TMP_DIR], $user_excluded_dirs );
        if ( $forceSafeMode || !self::advancedModeEnabled() ) {
            $user_excluded_dirs = array_merge( [
                DIR,
                rtrim( DIR, '/' ) . '-pro/',
                wp_normalize_path( WP_PLUGIN_DIR . '/wpide/' ),
                wp_normalize_path( WP_PLUGIN_DIR . '/wpide-pro/' ),
                wp_normalize_path( WP_PATH . '/wp-admin/' ),
                wp_normalize_path( WP_PATH . '/wp-includes/' )
            ], $user_excluded_dirs );
        }
        return $user_excluded_dirs;
    }

    public static function excludedFiles( $forceSafeMode = false ) : array {
        $user_excluded_files = self::excludedEntries( 'file' );
        $user_excluded_files = array_merge( [CONTENT_DIR . '/' . FATAL_ERROR_DROPIN], $user_excluded_files );
        if ( $forceSafeMode || !self::advancedModeEnabled() ) {
            $user_excluded_files = array_merge( [wp_normalize_path( WP_PATH . '/wp-*.php' ), wp_normalize_path( WP_PATH . '/index.php' ), wp_normalize_path( WP_PATH . '/xmlrpc.php' )], $user_excluded_files );
        }
        return $user_excluded_files;
    }

    public static function isDirExcluded( $path ) : bool {
        if ( $path !== '/' ) {
            $path = wp_normalize_path( WP_PATH . '/' . $path . '/' );
            foreach ( self::excludedDirs( true ) as $excluded ) {
                if ( str_contains( $path, $excluded ) ) {
                    return true;
                }
            }
        }
        return false;
    }

    public static function isRootExcluded() : bool {
        $root = self::getRootDir();
        return self::isDirExcluded( $root );
    }

}
