<?php

namespace Pages\Controller;

use ArrayObject;

class Pages extends Controller {

    protected function before() {

        parent::before();

        $this->app->on('app.layout.assets', function(array &$assets) {
            $assets[] = 'pages:assets/css/pages.css';
        });
    }

    public function index() {

        $pageTypes = (array) $this->module('pages')->pageTypes();
        $settings = $this->module('pages')->settings();

        return $this->render('pages:views/pages/index.php', \compact('pageTypes', 'settings'));
    }

    public function load() {

        $this->helper('session')->close();
        $this->hasValidCsrfToken(true);

        $pId = $this->param('_pid', null);

        if (!$pId) {
            $pId = null;
        }

        $pages = $this->app->dataStorage->find('pages', [
            'fields' => ['data' => 0],
            'filter' => ['_pid' => $pId],
            'sort' => ['_o' => 1]
        ])->toArray();

        foreach ($pages as &$page) {
            $page['children'] = [];
            $page['_children'] = $this->app->dataStorage->count('pages', ['_pid' => $page['_id']]);
        }

        if (count($pages) && $this->param('locale')) {
            $pages = $this->helper('locales')->applyLocales($pages, $this->param('locale'));
        }

        return $pages;
    }


    public function page($id = null, $asData = false) {

        $pageTypes = $this->module('pages')->pageTypes();
        $type = $this->param('type', 'layout');

        if (!isset($pageTypes[$type])) {
            return $this->stop(['error' => 'Unknown page type'], 412);
        }

        $default = [
            'type' => $type,
            'title' => '',
            'slug' => '',
            'seo' => [
                'title' => null,
                'keywords' => null,
                'description' => null,
            ],
            'data' => new ArrayObject([]),
            '_meta' => new ArrayObject([]),
            '_locales' => new ArrayObject([]),
            '_state' => 0,
            '_r' => null,
            '_pid' => null,
            '_o' => 0
        ];

        $locales = $this->helper('locales')->locales();
        $locales[0]['visible'] = true;

        foreach ($locales as $locale) {

            if ($locale['i18n'] == 'default') continue;

            $default['title_'.$locale['i18n']] = null;
            $default['slug_'.$locale['i18n']] = null;
            $default['seo_'.$locale['i18n']] = $default['seo'];
            $default['_r_'.$locale['i18n']] = null;
        }

        if ($id) {

            $page = $this->app->dataStorage->findOne('pages', ['_id' => $id]);

            if (!$page) {
                return false;
            }

            if (!$asData) {
                $this->checkAndLockResource($id);
            }

            $page = array_replace_recursive($default, $page);

            $page['data'] = new ArrayObject($page['data']);

        } else {

            if ($this->param('pid') && $this->app->dataStorage->findOne('pages', ['_id' => $this->param('pid')], ['_id' => 1])) {
                $default['_pid'] = $this->param('pid');
            }

            $page = $default;
        }

        if (\is_array($page['_meta'])) {
            $page['_meta'] = new ArrayObject($page['_meta']);
        }

        if (\is_array($page['_locales'])) {
            $page['_locales'] = new ArrayObject($page['_locales']);
        }

        $settings = $this->module('pages')->settings();
        $pageType = $pageTypes[$page['type']] ?? null;

        foreach ($locales as &$loc) {
            $loc['isPublic'] = ($settings['locales'][$loc['i18n']] ?? true);
        }

        $this->app->trigger('pages.admin.page', [&$page, &$settings]);

        $fields = $pageType['data']
                    ? (is_callable($pageType['data']) ? $pageType['data']() : $pageType['data'])
                    : [];

        $globalFields = isset($settings['globalDataFields']) && is_array($settings['globalDataFields']) ? $settings['globalDataFields'] : [];

        $data = compact('page', 'locales', 'settings', 'pageType', 'fields', 'globalFields');

        if ($asData) {
            return $data;
        }

        return $this->render('pages:views/pages/page.php', $data);
    }

    public function save() {

        $this->hasValidCsrfToken(true);

        $page = $this->param('page');

        if (!$page) {
            return $this->stop(['error' => 'Page paramater is missing'], 412);
        }

        $state    = $page['_state'] ?? null;
        $isUpdate = isset($page['_id']);
        $settings = $this->module('pages')->settings();

        $page['_modified'] = time();
        $page['_mby'] = $this->user['_id'];

        if (!$isUpdate) {

            $page['_created'] = $page['_modified'];
            $page['_cby'] = $this->user['_id'];
            $page['_pid'] = $page['_pid'] ?? null;
            $page['_o'] = $this->app->dataStorage->count('pages', ['_pid' => $page['_pid']]);

        } else {
            unset($page['_pid'], $page['_o']);
        }

        $page['_meta'] = new ArrayObject($page['_meta']);

        $locales = $this->helper('locales')->locales();

        foreach ($locales as $locale) {

            $suffix = "_{$locale['i18n']}";

            if ($locale['i18n'] == 'default') {
                $suffix = '';
            }

            $title = "title{$suffix}";
            $slug = "slug{$suffix}";
            $seo = "seo{$suffix}";

            if (!trim($page[$slug] ?? '')) {

                $slugTitle = $page[$seo]['title'] ? $page[$seo]['title'] : $page[$title];

                if ($slugTitle && trim($slugTitle)) {
                    $page[$slug] = $this->helper('utils')->sluggify(trim($slugTitle));
                }
            } else {
                // clean slug, just to be aware of crazy user inputs
                $page[$slug] = \strtolower(preg_replace('/[^A-Za-z0-9\-]/', '', str_replace(' ', '-', $page[$slug])));
            }
        }

        if ($this->app->module('assets')) {
            $page = $this->app->helper('asset')->updateRefs($page);
        }

        // check if parent still exists on save
        if (isset($page['_pid']) && $page['_pid'] && !$this->app->dataStorage->findOne('pages', ['_id' => $page['_pid']])) {
            $page['_pid'] = null;
        }

        // add version to revisions
        if ($isUpdate && $state === 1 && ($settings['revisions'] ?? false)) {

            $current = $this->app->dataStorage->findOne('pages', ['_id' => $page['_id']]);

            if ($current) {

                $this->app->helper('revisions')->add(
                    id: $page['_id'],
                    data: $current,
                    meta: "pages",
                    by: $this->user['_id'],
                    created: $current['_modified'],
                    ref: $page
                );
            }
        }

        $this->app->dataStorage->save('pages', $page);
        $this->app->helper('pages')->updateRoutes($page['_id']);

        $page = $this->app->dataStorage->findOne('pages', ['_id' => $page['_id']]);

        $this->app->trigger('pages.page.save', [$page, $isUpdate]);

        $page['data'] = new ArrayObject($page['data']);
        $page['_meta'] = new ArrayObject($page['_meta']);

        return $page;
    }

    public function clone($id = null) {

        if (!$id) {
            return false;
        }

        $page = $this->app->dataStorage->findOne('pages', ['_id' => $id]);

        if (!$page) {
            return false;
        }

        unset($page['_id']);

        $pageTypes = $this->module('pages')->pageTypes();
        $settings = $this->module('pages')->settings();
        $pageType = $pageTypes[$page['type']] ?? null;

        $locales = $this->helper('locales')->locales();
        $locales[0]['visible'] = true;

        foreach ($locales as &$loc) {
            $loc['isPublic'] = ($settings['locales'][$loc['i18n']] ?? true);
        }

        $this->app->trigger('pages.admin.page', [&$page, &$settings]);

        $data = compact('page', 'locales', 'settings', 'pageType');

        return $this->render('pages:views/pages/page.php', $data);

    }

    public function remove() {

        $this->hasValidCsrfToken(true);

        $page = $this->param('page');

        if (!$page) {
            return $this->stop(['error' => 'Page paramater is missing'], 412);
        }

        $this->helper('pages')->remove($page['_id']);

        return ['success' => true];
    }

    /**
     * Used mainly for page preview
     *
     * @return page array
     */
    public function resolve() {

        $this->helper('session')->close();
        $this->hasValidCsrfToken(true);

        $locale = $this->param('locale', 'default');
        $page = $this->param('page', []);

        $page = $this->app->helper('pages')->processPage($page, ['locale' => $locale, 'populate' => 10]);

        return $page;
    }

}
