<?php /** @noinspection PhpUnused */

namespace Grav\Plugin;

use Exception;
use Grav\Common\Grav;
use Grav\Common\Page\Page;
use Grav\Common\Page\Pages;
use Grav\Common\Plugin;
use Grav\Common\Uri;
use Symfony\Component\EventDispatcher\Event;



/**
 * Features:
 * - /sync   Cheap git-sync (did not knew about it at the time)
 * - /polyglot/<page-path>
 * - /lessons/<lesson-slug>
 *
 * The way GRAV works to define new routes is to listen to the onPageNotFound event.
 * This is expected to evolve as GRAV integrates more and more with Symfony components.
 *
 * Class M3P2Plugin
 * @package Grav\Plugin
 */
class M3P2Plugin extends Plugin
{
    /**
     * @return array
     *
     * The getSubscribedEvents() gives the core a list of events
     *     that the plugin wants to listen to. The key of each
     *     array section is the event that the plugin listens to
     *     and the value (in the form of an array) contains the
     *     callable (or function) as well as the priority. The
     *     higher the number the higher the priority.
     */
    public static function getSubscribedEvents()
    {
        return [
            'onPluginsInitialized' => ['onPluginsInitialized', 0]
        ];
    }

    /**
     * Initialize the plugin
     */
    public function onPluginsInitialized()
    {
        if ($this->isAdmin()) {
            return;  // Don't proceed if we are in the admin backend
        }

        $uri = $this->grav['uri'];
        $current_route = $uri->path();

        // /sync
        $route_sync = $this->config->get('plugins.m3-p2.routes.sync');
        if ($route_sync && $route_sync == $current_route) {
            $this->enable([
                'onPageInitialized' => ['onSyncPageInitialized', 0]
            ]);
        }

        $this->enable([
            'onTwigInitialized' => ['setupTwigGoodies', 0],
        ]);

        $this->enable([
            'onTwigInitialized' => ['setupWebIdeUrl', 0],
        ]);


//        $that_page_route = $uri->query('page');
//        if ($that_page_route) {
//            $this->enable([
//                'onPageNotFound' => ['setupQueryPage', 0],
//            ]);
//        }

        $priority = 1; // must be higher than the error plugin's

        $this->enable([
            'onPageNotFound' => ['perhapsDisplayPolyglotColumns', $priority],
        ]);

        $this->enable([
            'onPageNotFound' => ['perhapsDisplayLessonColumns', $priority],
        ]);

//        if ("" == $current_route) {
//            $this->enable([
//                'onPageInitialized' => ['onSyncPageInitialized', 0]
//            ]);
//        }

    }

    /**
     * Sync with the sources.
     */
    public function onSyncPageInitialized()
    {
        // shell cwd is project root
        $out = "";

        //$out = "Opening a fortune cookie…\n\n\n";
        //$out .= shell_exec("fortune") . "\n\n";
        //$out .= shell_exec("fortune | cowsay -e Oø -f dragon") . "\n";

        $out .= "Trying to sync content with GitLab…\n\n\n";
        $out .= shell_exec("cd user/pages && git pull --rebase --autostash origin master 2>&1") . "\n";

        $out .= "Done.";

        die("<pre>".$out."</pre>");  // This is all I could find to write to the page.
    }

    public function setupTwigGoodies()
    {
        /** @var Pages $pages */
        $pages = Grav::instance()['pages'];
        $this->grav['twig']->twig()->addGlobal('localized_pages', $pages);

        $this->grav['twig']->twig()->addFilter(
            new \Twig_SimpleFilter('to_page', [$this, 'getPageForPath'])
        );
    }

    public function setupWebIdeUrl()
    {
        $this->grav['twig']->twig()->addFilter(
            new \Twig_SimpleFilter('webide_url', [$this, 'getWebIdeUrlForPage'])
        );
        $this->grav['twig']->twig()->addFilter(
            new \Twig_SimpleFilter('translations', [$this, 'getTranslationsOfPage'])
        );
    }

//    public function setupQueryPage()
//    {
//        $that_page_route = $this->grav['uri']->query('page');
////        die($that_page_route);
//        var_dump($that_page_route);
//        $that_page = $this->grav['pages']->find($that_page_route);
//        var_dump($that_page);
//        $this->grav['twig']->twig()->addGlobal(
//            'that_page', $that_page
//        );
//    }

    public function getPageForPath($meta)
    {
        if (is_array($meta)) {
            if (isset($meta['path'])) {
                $path = $meta['path'];
            } else {
                trigger_error("Missing `path` in: ".print_r($meta, true));
            }
        } elseif (is_string($meta)) {
            $path = $meta;
        } else {
            trigger_error("Unrecognized page: ".print_r($meta, true));
        }

        /** @var Pages $pages */
        $pages = Grav::instance()['pages'];

        $page = $pages->find($path);

        if ( ! $page) {
            try {
                $page = $pages->get($path);
            } catch (Exception $e) {}
        }
        if ( ! $page) {
            try {
                $cwd = $pages->root()->filePath();  // ends with /
                if (0 === strpos($path, '/')) {
                    $page = $pages->get($cwd . substr($path, 1));
                } else {
                    $page = $pages->get($cwd . $path);
                }
            } catch (Exception $e) {}
        }

        return $page;
    }

    public function getWebIdeUrlForPage(Page $page)
    {
        $url = "https://gitlab.m3p2.com/-/ide/project/m3p2/courses/edit/master/-/";  # todo: move to YAML config
        $url .= substr($page->filePathClean(), 11); // 11==strlen('/user/pages')

        return $url;
    }

//    public function getPage($route)
//    {
//        $page = null;
////        $translation_path = $page->path() . DS . $page_name_without_ext . '.' . $language . '.md';
//        if (file_exists($translation_path)) {
//            $page = new Page();
//            $page->init(new \SplFileInfo($page_path), $language . '.md');
//        }
//
//        return $page;
//    }

    public function getTranslationsOfPage(Page $page)
    {
        $languages = $this->config->get('system.languages.supported');
//        die(print_r($languages));
        $route_suffix = $page->rawRoute();
        $translations = array();
        $current_language = $page->language();

        $page_name_without_ext = substr($page->name(), 0, -(strlen($page->extension())));
        foreach ($languages as $language) {
//            $route = '/' . $language . $route_suffix;
//            $route = $route_suffix;

            // Nope. language-selector does this the hard way, by instantiating Page objects
            //$translation = $page->find($route);

            // … so we're falling back on the old school too
            $translation_path = $page->path() . DS . $page_name_without_ext . '.' . $language . '.md';
            if ( ! file_exists($translation_path)) {
                continue;
            }
            $translation = new Page();
            $translation->init(new \SplFileInfo($translation_path), $language . '.md');

            if ($language == $current_language) {
                array_unshift($translations, $translation);
            } else {
                array_push($translations, $translation);
            }
        }

        return $translations;
    }

    public function perhapsDisplayPolyglotColumns(Event $event)
    {
        /** @var Uri $uri */
        $uri = $this->grav['uri'];
//        var_dump($uri); // best doc ftw

        if ("polyglot" != $uri->paths(0)) {
            return; // perhaps not
        }

        /** @var Pages $pages */
        $pages = $this->grav['pages'];

        $that_page_route = "/" . join("/", array_slice($uri->paths(), 1));

        $target_page = $pages->find($that_page_route, true);

        if ( ! $target_page) {
            return;
        }

        $this->grav['twig']->twig()->addGlobal('target_page', $target_page);
        $this->grav['twig']->twig()->addGlobal('disable_multilingual', true);

        $page = new Page;
        $page->init(new \SplFileInfo(__DIR__ . '/pages/polyglot-columns.md'));

        // here: perhaps add a title and other metadata

        $event->page = $page;
        $event->stopPropagation();
    }

    public function perhapsDisplayLessonColumns(Event $event)
    {
        /** @var Uri $uri */
        $uri = $this->grav['uri'];
//        var_dump($uri); // best doc ftw

        // GRAV's routing makes us hook 404 pages and do the URL match ourselves
        if ("lessons" != $uri->paths(0)) {
            return; // perhaps not
        }

        if (count($uri->paths()) < 2) {
            // user is toying with URI, probably, visiting `/lessons`.
            // idea: display an index of the lessons here todo
            return;
        }

        $lesson_slug = $uri->paths(1);

        /** @var Pages $pages */
        $pages = $this->grav['pages'];

        $target_pages = array_filter($pages->instances(), function (Page $p) use ($lesson_slug) {

            $page_config = $p->header();
            if ( ! isset($page_config->lessons) || empty($page_config->lessons)) {
                return false;
            }

            foreach ($page_config->lessons as $lesson) {

                if ( ! isset($lesson['slug'])) {
                    trigger_error(
                        "Misconfigured lesson (missing a slug) in ".($p->filePathClean()),
                        E_USER_WARNING
                    );
                    continue;
                }

                if ($lesson_slug == $lesson['slug']) {
                    return true; // yay, this page is part of the lesson
                }
            }

            return false;
        });

        usort($target_pages, function (Page $a, Page $b) use ($lesson_slug) {
            $la = 0;
            $lb = 0;

            $ha = $a->header();
            $hb = $b->header();

            $fdp = function ($lesson) use ($lesson_slug) {
                return trim($lesson["slug"]) === $lesson_slug;
            };

            $mar = array_filter($ha->lessons, $fdp);
            assert($mar && !empty($mar), "No lesson found for $lesson_slug in page ".$a->url());
            $ma = array_shift($mar);

            $mbr = array_filter($hb->lessons, $fdp);
            assert($mbr && !empty($mbr), "No lesson found for $lesson_slug in page ".$b->url());
            $mb = array_shift($mbr);

            if ($ma && isset($ma['order'])) {
                $la = floor($ma['order']);
            }
            if ($mb && isset($mb['order'])) {
                $lb = floor($mb['order']);
            }

            return $la - $lb;
        });

        if (empty($target_pages)) {
            return;
        }

        $this->grav['twig']->twig()->addGlobal('target_pages', $target_pages);
        $this->grav['twig']->twig()->addGlobal('disable_multilingual', true);

        // hotfix until we know how to fetch the appropriate translation
        $this->grav['twig']->twig()->addGlobal('disable_language_selector', true);

        $page = new Page;
        $page->init(new \SplFileInfo(__DIR__ . '/pages/lesson-columns.md'));

        // here: perhaps add a title and other metadata

        $event->page = $page;
        $event->stopPropagation();
    }
}
