<?php
namespace WPIDE\App;

use WPIDE\App\Classes\Freemius;
use WPIDE\App\Classes\Migrations;
use WPIDE\App\Classes\RecommendedPlugins;
use WPIDE\App\Classes\PromoNotice;
use WPIDE\App\Classes\ReviewNotice;
use WPIDE\App\Classes\Notices;
use WPIDE\App\Config\Config;
use WPIDE\App\Container\Container;
use WPIDE\App\Helpers\EmptyDir;
use WPIDE\App\Helpers\FileBackup;
use WPIDE\App\Helpers\ImageStateData;
use WPIDE\App\Kernel\Request;
use WPIDE\App\Kernel\Response;
use WPIDE\App\Kernel\StreamedResponse;
use WPIDE\App\Services\Services;
use WPIDE\App\Services\Storage\LocalFileSystem;
use const WPIDE\Constants\AUTHOR;
use const WPIDE\Constants\CONTENT_DIR;
use const WPIDE\Constants\DIR;
use const WPIDE\Constants\TMP_DIR;
use const WPIDE\Constants\ASSETS_URL;
use const WPIDE\Constants\FATAL_ERROR_DROPIN;
use const WPIDE\Constants\FATAL_ERROR_DROPIN_VERSION;
use const WPIDE\Constants\FATAL_ERROR_DROPIN_VERSION_OPT;
use const WPIDE\Constants\NAME;
use const WPIDE\Constants\SLUG;
use const WPIDE\Constants\PLUGIN_URL;
use const WPIDE\Constants\VERSION;

class App
{
    public static $_instance;

    private $container;
    private $dependencyNotice;
    private $isNetworkActive;

    protected $notices = [];
    public $services = [];

    public function __construct()
    {

        register_activation_hook(WPIDE_FILE, [$this, 'activate']);
        register_deactivation_hook(WPIDE_FILE, [$this, 'deactivate']);

        add_action( 'plugins_loaded', [$this, 'load']);

        $this->container = new Container();

    }

    public function activate() {
        $this->installDropIn();
    }

    public function deactivate() {
        $this->unInstallDropIn();
    }

    /**
     * @throws \DI\DependencyException
     * @throws \DI\NotFoundException
     */
    public function resolve($name)
    {
        return $this->container->get($name);
    }

    /**
     * @throws \DI\DependencyException
     * @throws \DI\NotFoundException
     */
    public function cache() {

        return $this->resolve('WPIDE\App\Services\Cache\Cache');
    }

    /**
     * @throws \DI\DependencyException
     * @throws \DI\NotFoundException
     */
    public function transient() {

        return $this->resolve('WPIDE\App\Services\Transient\Transient');
    }

    public function call($callable, array $parameters)
    {
        return $this->container->call($callable, $parameters);
    }

    public function prefix($suffix = null): string
    {
        return SLUG . (!empty($suffix) ? '_' . $suffix : '');
    }

    public function isLatestDropIn(): bool
    {

        $currentVersion = get_option(FATAL_ERROR_DROPIN_VERSION_OPT, null);

        return $currentVersion === FATAL_ERROR_DROPIN_VERSION;
    }

    public function dropInExists(): bool
    {
        $fs = LocalFileSystem::load(CONTENT_DIR);

        return $fs->fileExists(FATAL_ERROR_DROPIN);
    }

    public function installDropIn() {

        $fs = LocalFileSystem::load(CONTENT_DIR);

        if($fs->fileExists(FATAL_ERROR_DROPIN)) {
            $this->unInstallDropIn();
        }

        $fs->copyFile('plugins/'.basename(DIR).'/wp-content/'.FATAL_ERROR_DROPIN, './');

        update_option(FATAL_ERROR_DROPIN_VERSION_OPT, FATAL_ERROR_DROPIN_VERSION);
    }

    public function unInstallDropIn() {

        $fs = LocalFileSystem::load(CONTENT_DIR);

        if($fs->fileExists(FATAL_ERROR_DROPIN)) {
            $fs->deleteFile(FATAL_ERROR_DROPIN);
        }
    }

    /**
     * @throws \Exception
     */
    public function load()
    {

        if(!$this->dependencyCheck() || !is_admin()) {
            return;
        }

        if(!$this->dropInExists() || !$this->isLatestDropIn()) {
            $this->installDropIn();
        }

        $this->loadTextDomain();
        $this->loadHooks();

        Migrations::init();
        PromoNotice::init();
        if(!PromoNotice::enabled()) {
            ReviewNotice::init();
        }
        RecommendedPlugins::init();
    }

    protected function loadTextDomain() {

        load_plugin_textdomain(
            SLUG,
            false,
            basename( dirname( WPIDE_FILE ) ) . '/languages/'
        );
    }

    protected function dependencyCheck(): bool
    {

        if(!empty($this->dependencyNotice)) {
            echo $this->dependencyNotice;
        }

        // Perform checks here
        // $class = 'notice notice-error';
        // $message = '';
        // $this->dependencyNotice = sprintf( '<div class="%1$s"><p>%2$s</p></div>', esc_attr( $class ), $message);

        if(!empty($this->dependencyNotice)) {
            add_action('admin_notices', [$this, 'dependencyCheck']);
            return false;
        }

        return true;
    }

    protected function loadHooks()
    {

        if($this->showAdminMenu()) {
            add_action('admin_menu', [$this, 'adminMenu' ]);
            add_action('network_admin_menu', [$this, 'adminMenu']);
        }

        add_action("wp_ajax_wpide_request", [$this, "ajaxRequest"]);
        add_action("admin_init", [$this, "registerTasks"]);
        add_action('admin_enqueue_scripts', [ $this, 'enqueueCommonAssets' ]);

        if($this->isPluginScreen()) {

            // When network active, If trying to load plugin admin url, redirect back to network root
            if(!$this->showAdminMenu() && !$this->isFreemiusScreen() && !Freemius::sdk()->is_activation_mode() && !Freemius::showSubmenus()) {
                wp_redirect(network_admin_url());
                die();
            }

            add_filter('admin_title', [$this, 'setAdminTitle']);

            add_action('network_admin_menu', [$this, 'addAdminFavicon']);
            add_action("network_admin_menu", [$this, "setCurrentScreen"], -1);
            add_action('network_admin_menu', [Notices::class, 'init']);

            add_action('admin_head', [$this, 'addAdminFavicon']);
            add_action("admin_menu", [$this, "setCurrentScreen"], -1);
            add_action('admin_menu', [Notices::class, 'init']);

            add_filter('screen_options_show_screen', '__return_false');
            add_action('admin_enqueue_scripts', [ $this, 'deregisterWpStyles' ]);
        }
    }

    public function registerTasks() {

        //TestTask::register();
    }

    public function setCurrentScreen() {

        set_current_screen(SLUG);
    }

    public function canManage(): bool
    {
        return current_user_can('manage_options');
    }

    public function showAdminMenu(): bool
    {

        if(fs_is_network_admin()) {

            return $this->isNetworkActive() && (WP_FS__SHOW_NETWORK_EVEN_WHEN_DELEGATED || !Freemius::sdk()->is_network_delegated_connection());
        }

        return true;
    }

    public function adminMenu()
    {

        $menuTopItems = apply_filters('wpide_admin_menu_top_items', [
            [
                'title' => __( 'File Manager', 'wpide' ),
                'slug' => SLUG.'#/file-manager',
                'callback' => [$this, 'bootstrap'],
                'position' => 10
            ],
            [
                'title' => __( 'File Editor', 'wpide' ),
                'slug' => SLUG.'#/file-editor',
                'callback' => [$this, 'bootstrap'],
                'position' => 20
            ],
            [
                'title' => __( 'Image Editor', 'wpide' ),
                'slug' => SLUG.'#/image-editor',
                'callback' => [$this, 'bootstrap'],
                'position' => 20
            ],
            [
                'title' => __( 'DB Manager', 'wpide' ),
                'slug' => SLUG.'#/db-manager',
                'callback' => [$this, 'bootstrap'],
                'position' => 30
            ],
            [
                'title' => __( 'Config Manager', 'wpide' ),
                'slug' => SLUG.'#/config-manager',
                'callback' => [$this, 'bootstrap'],
                'position' => 30
            ],
            [
                'title' => __( 'Settings', 'wpide' ),
                'slug' => SLUG.'#/settings',
                'callback' => [$this, 'bootstrap'],
                'position' => 40
            ]
        ]);

        $menuBottomItems = apply_filters('wpide_admin_menu_bottom_items', []);

        add_menu_page(
            NAME,
            NAME,
            'manage_options',
            SLUG,
            [$this, 'bootstrap'],
            'dashicons-editor-code'
        );

        $highestPosition = 0;
        foreach ($menuTopItems as $item) {
            add_submenu_page(
                SLUG,
                $item['title'],
                $item['title'],
                'manage_options',
                $item['slug'],
                $item['callback'],
                $item['position']
            );

            if ($item['position'] > $highestPosition) {
                $highestPosition = $item['position'];
            }
        }

        add_submenu_page(
            SLUG,
            '',
            '',
            'manage_options',
            '#divider',
            '',
            $highestPosition + 10
        );

        foreach ($menuBottomItems as $item) {
            add_submenu_page(
                SLUG,
                $item['title'],
                $item['title'],
                'manage_options',
                $item['slug'],
                $item['callback'],
                $item['position']
            );
        }

        remove_submenu_page(SLUG, SLUG);

        do_action('wpide_admin_menu');

    }

    public function bootstrap() {

        FileBackup::init();
        ImageStateData::init();
        EmptyDir::create(TMP_DIR);

        $config = AppConfig::load();
        $services = AppServices::load();
        $request = Request::createFromGlobals();
        $response = new Response();
        $sresponse = new StreamedResponse();

        $this->container->set(Config::class, $config);
        $this->container->set(Services::class, $services);
        $this->container->set(Container::class, $this->container);
        $this->container->set(Request::class, $request);
        $this->container->set(Response::class, $response);
        $this->container->set(StreamedResponse::class, $sresponse);

        $this->services = [];
        foreach ($services->get() as $key => $service) {
            if(empty($service['handler'])) {
                continue;
            }
            $this->container->set($key, $this->container->get($service['handler']));
            $this->container->get($key)->init(isset($service['config']) ? $service['config'] : []);
            $this->services[$key] = $this->container->get($key);
        }

        if(!defined('WPIDE_DOING_TASK')) {
            if (wp_doing_ajax()) {
                $response->send();
            } else {
                $response->sendContent();
            }
        }
    }

    public function deregisterWpStyles()
    {

        wp_deregister_style('color');
        wp_deregister_style('forms');
        wp_deregister_style('dashboard');
        wp_deregister_style('list-tables');
        wp_deregister_style('edit');
        wp_deregister_style('revisions');
        wp_deregister_style('media');
        wp_deregister_style('themes');
        wp_deregister_style('about');
        wp_deregister_style('nav-menus');
        wp_deregister_style('widgets');
        wp_deregister_style('l10n');
        wp_deregister_style('site-icon');

        wp_register_style('color', '');
        wp_register_style('forms', '');
        wp_register_style('dashboard', '');
        wp_register_style('list-tables', '');
        wp_register_style('edit', '');
        wp_register_style('revisions', '');
        wp_register_style('media', '');
        wp_register_style('themes', '');
        wp_register_style('about', '');
        wp_register_style('nav-menus', '');
        wp_register_style('widgets', '');
        wp_register_style('l10n', '');
        wp_register_style('site-icon', '');

    }

    public function enqueueCommonAssets()
    {

        wp_enqueue_style(SLUG.'-fs-notices', ASSETS_URL.'global/css/global.css', [], VERSION);
    }

    public function ajaxRequest()
    {
        if(!$this->canManage()) {
            die(esc_html__('Restricted Access', 'wpide'));
        }

        $this->bootstrap();
        die();
    }

    public function isPluginScreen($section = null): bool
    {

        $screen = function_exists('get_current_screen') ? get_current_screen() : null;

        $slug = SLUG;

        if(!empty($section)) {
            $slug .= '-'. $section;
        }

        if(!empty($screen)) {
            return strpos($screen->base, 'page_' . $slug) !== false;
        }

        if(!empty($_GET['page'])) {
            $page = sanitize_text_field($_GET['page']);
            return strpos($page, $slug) !== false;
        }

        return false;
    }

    public function isFreemiusScreen($section = null): bool
    {

        if($section) {
            return $this->isPluginScreen($section);
        }

        if(
            $this->isPluginScreen('account') ||
            $this->isPluginScreen('pricing') ||
            $this->isPluginScreen('contact') ||
            $this->isPluginScreen('affiliates')
        ) {
            return true;
        }

        return false;
    }

    public function isNetworkActive(): bool
    {

        if(!isset($this->isNetworkActive)) {

            $plugin = basename(WPIDE_DIR) . '/' . basename(WPIDE_FILE);
            $this->isNetworkActive = is_plugin_active_for_network($plugin);
        }

        return $this->isNetworkActive;
    }

    public function getAdminUrl($section = null, $network = false): string {

        $admin_url_function = $network ? 'network_admin_url' : 'admin_url';

        $url = 'admin.php?page='.SLUG;
        if(!empty($section)) {
            $url .= '#/'.$section;
        }
        return $admin_url_function( $url );
    }

    public function getAjaxUrl($req = ''): string
    {
        return admin_url('admin-ajax.php').'?action=wpide_request&req='.$req;
    }

    /**
     * Get external url with utm campaign / content
     *
     * @param string|null $utm_content
     * @param string|null $url
     *
     * @return string $link;
     * @since     1.0.0
     */
    public function getExternalUrl(string $utm_content = null, string $url = null): string
    {

        $url = !empty($url) ? $url : PLUGIN_URL;

        if(!empty($utm_content)) {
            $url .= '?utm_source='.AUTHOR.'&utm_medium=Plugin&utm_campaign='.SLUG.'&utm_content='.$utm_content;
        }

        return $url;
    }

    /**
     * Filter admin page title
     */
    public function setAdminTitle(): string
    {
        return NAME;
    }

    /**
     * render backend favicon
     */
    public function addAdminFavicon () {

        echo '<link rel="shortcut icon" type="image/svg+xml" href="' . ASSETS_URL. '/img/favicon.svg">',"\n";
        echo '<link rel="shortcut icon" type="image/x-icon" href="' . ASSETS_URL. '/img/favicon.ico">',"\n";
        echo '<link rel="shortcut icon" type="image/png" href="' . ASSETS_URL. '/img/favicon.png">',"\n";
        echo '<meta name="theme-color" content="#ffffff">',"\n";
    }


    /**
     * @return App
     */
    public static function instance(): App
    {
        if ( is_null( self::$_instance ) ) {
            self::$_instance = new self();
        }

        return self::$_instance;
    }

}
