<?php
namespace admin\Controllers;

use Domain\Pages\PagesRepository;
use Domain\Languages\LanguagesRepository;
use Domain\Layouts\LayoutsRepository;
use admin\ViewModels\Forms\FormAction;
use admin\ViewModels\Forms\FormEditViewModel;
use admin\ViewModels\Forms\FormField;
use admin\ViewModels\Forms\FormTab;

class PagesController
{
    private PagesRepository $repository;
    private LanguagesRepository $languagesRepository;
    private LayoutsRepository $layoutsRepository;

    public function __construct(
        PagesRepository $repository,
        LanguagesRepository $languagesRepository,
        LayoutsRepository $layoutsRepository
    ) {
        $this->repository = $repository;
        $this->languagesRepository = $languagesRepository;
        $this->layoutsRepository = $layoutsRepository;
    }

    public function list(): string
    {
        return \Shared\Tpl\Tpl::view('pages/pages-list', [
            'menus' => $this->repository->menusWithPages(),
            'cookie_pages' => $this->cookieState('cookie_pages'),
            'cookie_menus' => $this->cookieState('cookie_menus'),
        ]);
    }

    public function browseList(): string
    {
        $menus = $this->repository->menusWithPages();
        $defaultLanguage = $this->languagesRepository->defaultLanguageId();

        foreach ($menus as $index => $menu) {
            $menus[$index]['pages'] = $this->withPreviewUrls($menu['pages'] ?? [], $defaultLanguage);
        }

        return \Shared\Tpl\Tpl::view('pages/pages-browse-list', [
            'menus' => $menus,
            'modal' => \Shared\Helpers\Helpers::get('modal'),
            'cookie_pages' => $this->cookieState('cookie_pages'),
            'cookie_menus' => $this->cookieState('cookie_menus'),
        ]);
    }

    public function pagesUrlBrowser(): string
    {
        return $this->browseList();
    }

    public function menuEdit(): string
    {
        $menu = $this->repository->menuDetails((int)\Shared\Helpers\Helpers::get('id')) ?: [];

        return \Shared\Tpl\Tpl::view('pages/menu-edit', [
            'form' => $this->buildMenuFormViewModel($menu),
        ]);
    }

    public function menuSave(): void
    {
        $legacyValues = \Shared\Helpers\Helpers::get('values');
        if ($legacyValues) {
            $response = ['status' => 'error', 'msg' => 'Podczas zapisywania menu wystapil blad. Prosze sprobowac ponownie.'];
            $values = json_decode((string)$legacyValues, true);

            if (is_array($values) && $this->repository->menuSave(
                (int)($values['id'] ?? 0),
                (string)($values['name'] ?? ''),
                $values['status'] ?? 0
            )) {
                $response = ['status' => 'ok', 'msg' => 'Menu zostalo zapisane.'];
            }

            echo json_encode($response);
            exit;
        }

        $menuId = (int)\Shared\Helpers\Helpers::get('id');
        $name = trim((string)\Shared\Helpers\Helpers::get('name'));
        $status = \Shared\Helpers\Helpers::get('status');

        if ($name === '') {
            echo json_encode([
                'success' => false,
                'errors' => ['name' => 'Pole "Nazwa" jest wymagane.'],
            ]);
            exit;
        }

        if ($this->repository->menuSave($menuId, $name, $status)) {
            echo json_encode([
                'success' => true,
                'message' => 'Menu zostalo zapisane.',
            ]);
            exit;
        }

        echo json_encode([
            'success' => false,
            'errors' => ['general' => 'Podczas zapisywania menu wystapil blad. Prosze sprobowac ponownie.'],
        ]);
        exit;
    }

    /**
     * @param array<string, mixed> $menu
     */
    private function buildMenuFormViewModel(array $menu): FormEditViewModel
    {
        $menuId = (int)($menu['id'] ?? 0);
        $actionUrl = '/admin/pages/menuSave/' . ($menuId > 0 ? ('id=' . $menuId) : '');

        $fields = [
            FormField::hidden('id', $menuId),
            FormField::text('name', [
                'label' => 'Nazwa',
                'required' => true,
                'attributes' => ['class' => 'require'],
                'value' => (string)($menu['name'] ?? ''),
            ]),
            FormField::switch('status', [
                'label' => 'Aktywne',
                'value' => (int)($menu['status'] ?? 0) === 1,
            ]),
        ];

        $actions = [
            FormAction::save($actionUrl, '/admin/pages/list/'),
            FormAction::cancel('/admin/pages/list/'),
        ];

        return new FormEditViewModel(
            'pages-menu-edit',
            'Zapisz menu',
            $menu,
            $fields,
            [],
            $actions,
            'POST',
            $actionUrl,
            '/admin/pages/list/',
            true,
            ['id' => $menuId]
        );
    }

    public function menuDelete(): void
    {
        if ($this->repository->menuDelete((int)\Shared\Helpers\Helpers::get('id'))) {
            \Shared\Helpers\Helpers::set_message('Menu zostało usunięte.');
        } else {
            \Shared\Helpers\Helpers::alert('Podczas usuwania menu wystąpił błąd. Aby usunąć menu, nie może ono posiadać przypiętych stron.');
        }

        header('Location: /admin/pages/list/');
        exit;
    }

    public function edit(): string
    {
        $page = $this->repository->pageDetails((int)\Shared\Helpers\Helpers::get('id')) ?: [];
        $parentId = (int)\Shared\Helpers\Helpers::get('pid');
        $menuId = (int)\Shared\Helpers\Helpers::get('menu_id');
        $menus = $this->repository->menusList();
        $layouts = $this->layoutsRepository->listAll();
        $languages = $this->languagesRepository->languagesList();

        return \Shared\Tpl\Tpl::view('pages/page-edit', [
            'form' => $this->buildPageFormViewModel(
                $page,
                $parentId,
                $menuId,
                $menus,
                $layouts,
                $languages
            ),
        ]);
    }

    public function save(): void
    {
        $legacyValues = \Shared\Helpers\Helpers::get('values');
        if ($legacyValues) {
            $response = ['status' => 'error', 'msg' => 'Podczas zapisywania strony wystapil blad. Prosze sprobowac ponownie.'];
            $values = json_decode((string)$legacyValues, true);

            if (is_array($values)) {
                $id = $this->repository->pageSave($values);
                if (!empty($id)) {
                    $response = [
                        'status' => 'ok',
                        'msg' => 'Strona zostala zapisana.',
                        'id' => (int)$id,
                    ];
                }
            }

            echo json_encode($response);
            exit;
        }

        $data = $_POST;
        if (!isset($data['id']) || $data['id'] === '') {
            $data['id'] = (int)\Shared\Helpers\Helpers::get('id');
        }
        if (!isset($data['parent_id']) || $data['parent_id'] === '') {
            $data['parent_id'] = (int)\Shared\Helpers\Helpers::get('pid');
        }
        if ((!isset($data['menu_id']) || $data['menu_id'] === '') && (int)\Shared\Helpers\Helpers::get('menu_id') > 0) {
            $data['menu_id'] = (int)\Shared\Helpers\Helpers::get('menu_id');
        }

        $savedId = $this->repository->pageSave($data);
        if (!empty($savedId)) {
            echo json_encode([
                'success' => true,
                'message' => 'Strona zostala zapisana.',
                'id' => (int)$savedId,
            ]);
            exit;
        }

        echo json_encode([
            'success' => false,
            'errors' => ['general' => 'Podczas zapisywania strony wystapil blad. Prosze sprobowac ponownie.'],
        ]);
        exit;
    }

    /**
     * @param array<string, mixed> $page
     * @param array<int, array<string, mixed>> $menus
     * @param array<int, array<string, mixed>> $layouts
     * @param array<int, array<string, mixed>> $languages
     */
    private function buildPageFormViewModel(
        array $page,
        int $parentId,
        int $menuId,
        array $menus,
        array $layouts,
        array $languages
    ): FormEditViewModel {
        $pageId = (int)($page['id'] ?? 0);
        $isNew = $pageId <= 0;

        $resolvedParentId = $pageId > 0 ? (int)($page['parent_id'] ?? 0) : $parentId;
        $resolvedMenuId = $pageId > 0 ? (int)($page['menu_id'] ?? 0) : $menuId;

        $menuOptions = [];
        foreach ($menus as $menu) {
            $id = (int)($menu['id'] ?? 0);
            if ($id <= 0) {
                continue;
            }
            $menuOptions[$id] = (string)($menu['name'] ?? '');
        }

        $layoutOptions = ['' => '---- szablon ----'];
        foreach ($layouts as $layout) {
            $id = (int)($layout['id'] ?? 0);
            if ($id <= 0) {
                continue;
            }
            $layoutOptions[$id] = (string)($layout['name'] ?? '');
        }

        $data = [
            'id' => $pageId,
            'parent_id' => $resolvedParentId > 0 ? $resolvedParentId : '',
            'menu_id' => $resolvedMenuId > 0 ? $resolvedMenuId : '',
            'page_type' => (int)($page['page_type'] ?? 0),
            'sort_type' => (int)($page['sort_type'] ?? 0),
            'layout_id' => (int)($page['layout_id'] ?? 0),
            'articles_limit' => (int)($page['articles_limit'] ?? 2),
            'show_title' => (int)($page['show_title'] ?? 1),
            'status' => (int)($page['status'] ?? 1),
            'start' => (int)($page['start'] ?? 0),
            'category_id' => (int)($page['category_id'] ?? 0),
            'languages' => [],
        ];

        foreach ($languages as $language) {
            $langId = (string)($language['id'] ?? '');
            if ($langId === '') {
                continue;
            }

            $translation = is_array($page['languages'][$langId] ?? null) ? $page['languages'][$langId] : [];
            $data['languages'][$langId] = [
                'title' => (string)($translation['title'] ?? ''),
                'link' => (string)($translation['link'] ?? ''),
                'seo_link' => (string)($translation['seo_link'] ?? ''),
                'page_title' => (string)($translation['page_title'] ?? ''),
                'meta_title' => (string)($translation['meta_title'] ?? ''),
                'meta_description' => (string)($translation['meta_description'] ?? ''),
                'meta_keywords' => (string)($translation['meta_keywords'] ?? ''),
                'noindex' => (int)($translation['noindex'] ?? 0),
                'canonical' => (string)($translation['canonical'] ?? ''),
            ];
        }

        $tabs = [
            new FormTab('content', 'Tresc', 'fa-file'),
            new FormTab('settings', 'Ustawienia', 'fa-wrench'),
            new FormTab('seo', 'SEO', 'fa-globe'),
        ];

        $fields = [
            FormField::hidden('id', $pageId),
            FormField::hidden('parent_id', $resolvedParentId > 0 ? $resolvedParentId : ''),
            FormField::langSection('page_content', 'content', [
                FormField::text('title', [
                    'label' => 'Nazwa strony',
                    'required' => true,
                ]),
            ]),
            FormField::select('menu_id', [
                'label' => 'Menu',
                'tab' => 'settings',
                'options' => $menuOptions,
                'value' => $resolvedMenuId > 0 ? $resolvedMenuId : '',
            ]),
            FormField::select('page_type', [
                'label' => 'Typ strony',
                'tab' => 'settings',
                'options' => $this->repository->pageTypes(),
                'attributes' => ['id' => 'page_type'],
                'value' => (int)($page['page_type'] ?? 0),
            ]),
            FormField::langSection('page_links', 'settings', [
                FormField::text('link', [
                    'label' => 'Link',
                ]),
            ]),
            FormField::text('category_id', [
                'label' => 'ID kategorii',
                'tab' => 'settings',
                'attributes' => ['id' => 'category_id'],
                'value' => (int)($page['category_id'] ?? 0),
            ]),
            FormField::select('sort_type', [
                'label' => 'Sortowanie artykulow',
                'tab' => 'settings',
                'attributes' => ['id' => 'sort_type'],
                'options' => $this->repository->sortTypes(),
                'value' => (int)($page['sort_type'] ?? 0),
            ]),
            FormField::select('layout_id', [
                'label' => 'Szablon',
                'tab' => 'settings',
                'attributes' => ['id' => 'layout_id'],
                'options' => $layoutOptions,
                'value' => (int)($page['layout_id'] ?? 0),
            ]),
            FormField::text('articles_limit', [
                'label' => 'Liczba artykulow na stronie',
                'tab' => 'settings',
                'attributes' => ['id' => 'articles_limit'],
                'value' => (int)($page['articles_limit'] ?? 2),
            ]),
            FormField::switch('show_title', [
                'label' => 'Pokaz tytul',
                'tab' => 'settings',
                'value' => (int)($page['show_title'] ?? 0) === 1 || $isNew,
            ]),
            FormField::switch('status', [
                'label' => 'Aktywna',
                'tab' => 'settings',
                'value' => (int)($page['status'] ?? 0) === 1 || $isNew,
            ]),
            FormField::switch('start', [
                'label' => 'Strona startowa',
                'tab' => 'settings',
                'value' => (int)($page['start'] ?? 0) === 1,
            ]),
            FormField::langSection('page_seo', 'seo', [
                FormField::text('seo_link', [
                    'label' => 'Link SEO',
                    'attributes' => [
                        'icon_content' => 'generuj',
                        'icon_js' => 'generateSeoLinkForButton(\'{lang}\')',
                    ],
                ]),
                FormField::text('page_title', [
                    'label' => 'Tytul strony (h1)',
                ]),
                FormField::text('meta_title', [
                    'label' => 'Meta title',
                ]),
                FormField::textarea('meta_description', [
                    'label' => 'Meta description',
                ]),
                FormField::textarea('meta_keywords', [
                    'label' => 'Meta keywords',
                ]),
                FormField::select('noindex', [
                    'label' => 'Blokuj indeksacje',
                    'options' => [0 => 'nie', 1 => 'tak'],
                ]),
                FormField::text('canonical', [
                    'label' => 'Rel canonical',
                ]),
            ]),
            FormField::custom('page_edit_script', '
<script type="text/javascript">
  (function () {
    function toggleByType() {
      var pageType = String($(\'#page_type\').val() || \'\');
      var $links = $(\'#languages-page_links\');
      var $category = $(\'#category_id\').closest(\'.form-group\');
      var $articlesLimit = $(\'#articles_limit\').closest(\'.form-group\');
      var $sortType = $(\'#sort_type\').closest(\'.form-group\');

      if (pageType === \'0\' || pageType === \'1\' || pageType === \'2\') {
        $articlesLimit.show();
        $sortType.show();
        $links.addClass(\'hide\');
        $category.hide();
      } else if (pageType === \'3\') {
        $links.removeClass(\'hide\');
        $articlesLimit.hide();
        $sortType.hide();
        $category.hide();
      } else if (pageType === \'5\') {
        $category.show();
        $links.addClass(\'hide\');
        $articlesLimit.hide();
        $sortType.hide();
      } else {
        $links.addClass(\'hide\');
        $category.hide();
        $articlesLimit.hide();
        $sortType.hide();
      }
    }

    function generateSeoLink(langId, title) {
      if (!title) {
        return;
      }

      $.ajax({
        type: \'POST\',
        cache: false,
        url: \'/admin/pages/generateSeoLink/\',
        data: {
          title: title,
          page_id: ' . $pageId . '
        },
        success: function (data) {
          var response = data;
          if (typeof data === \'string\') {
            try { response = JSON.parse(data); } catch (e) { response = null; }
          }
          if (response && response.status === \'ok\') {
            $(\'#seo_link_\' + langId).val(response.seo_link || \'\');
          }
        }
      });
    }

    window.generateSeoLinkForButton = function (langId) {
      var title = $(\'#title_\' + langId).val() || \'\';
      generateSeoLink(langId, title);
    };

    $(function () {
      $(\'#page_type\').on(\'change\', toggleByType);
      toggleByType();

      $(\'[id^=title_]\').on(\'blur\', function () {
        var fieldId = $(this).attr(\'id\') || \'\';
        var langId = fieldId.replace(/^title_/, \'\');
        if (!langId) {
          return;
        }

        var $seo = $(\'#seo_link_\' + langId);
        if ($seo.length && !$seo.val()) {
          generateSeoLink(langId, $(this).val());
        }
      });
    });
  })();
</script>', [
                'tab' => 'settings',
            ]),
        ];

        $actionUrl = '/admin/pages/save/' . ($pageId > 0 ? ('id=' . $pageId) : '');
        $actions = [
            FormAction::save($actionUrl, '/admin/pages/list/'),
            FormAction::cancel('/admin/pages/list/'),
        ];

        return new FormEditViewModel(
            'pages-page-edit',
            'Edycja strony',
            $data,
            $fields,
            $tabs,
            $actions,
            'POST',
            $actionUrl,
            '/admin/pages/list/',
            true,
            [
                'id' => $pageId,
                'parent_id' => $resolvedParentId > 0 ? $resolvedParentId : '',
            ],
            $languages
        );
    }

    public function delete(): void
    {
        if ($this->repository->pageDelete((int)\Shared\Helpers\Helpers::get('id'))) {
            \Shared\Helpers\Helpers::set_message('Strona zostala usunieta.');
        } else {
            \Shared\Helpers\Helpers::alert('Podczas usuwania strony wystapil blad. Aby usunac strone nie moze ona posiadac przypietych podstron.');
        }

        header('Location: /admin/pages/list/');
        exit;
    }

    public function pageArticles(): string
    {
        $pageId = (int)\Shared\Helpers\Helpers::get('id');
        return \Shared\Tpl\Tpl::view('pages/page-articles', [
            'page_id' => $pageId,
            'articles' => $this->repository->pageArticles($pageId),
        ]);
    }

    public function savePagesOrder(): void
    {
        $response = ['status' => 'error', 'msg' => 'Podczas zapisywania kolejnosci stron wystapil blad. Prosze sprobowac ponownie.'];

        if ($this->repository->savePagesOrder((int)\Shared\Helpers\Helpers::get('menu_id'), \Shared\Helpers\Helpers::get('pages'))) {
            $response = ['status' => 'ok'];
        }

        echo json_encode($response);
        exit;
    }

    public function saveArticlesOrder(): void
    {
        $response = ['status' => 'error', 'msg' => 'Podczas zapisywania kolejnosci wyswietlania artykulow wystapil blad. Prosze sprobowac ponownie.'];

        if ($this->repository->saveArticlesOrder((int)\Shared\Helpers\Helpers::get('page_id'), \Shared\Helpers\Helpers::get('articles'))) {
            $response = ['status' => 'ok'];
        }

        echo json_encode($response);
        exit;
    }

    public function generateSeoLink(): void
    {
        $response = ['status' => 'error', 'msg' => 'Podczas generowania pola "seo link" wystapil blad. Prosze sprobowac ponownie.'];

        $seoLink = $this->repository->generateSeoLink(
            (string)\Shared\Helpers\Helpers::get('title'),
            (int)\Shared\Helpers\Helpers::get('page_id'),
            (int)\Shared\Helpers\Helpers::get('article_id'),
            (int)\Shared\Helpers\Helpers::get('category_id')
        );

        if ($seoLink !== '') {
            $response = [
                'status' => 'ok',
                'seo_link' => $seoLink,
            ];
        }

        echo json_encode($response);
        exit;
    }

    public function cookieMenus(): void
    {
        $this->repository->toggleCookieValue('cookie_menus', (int)\Shared\Helpers\Helpers::get('menu_id'));
        exit;
    }

    public function cookiePages(): void
    {
        $this->repository->toggleCookieValue('cookie_pages', (int)\Shared\Helpers\Helpers::get('page_id'));
        exit;
    }

    /**
     * @param array<int, array<string, mixed>> $pages
     * @return array<int, array<string, mixed>>
     */
    private function withPreviewUrls(array $pages, string $defaultLanguage): array
    {
        foreach ($pages as $index => $page) {
            $pageId = (int)($page['id'] ?? 0);
            $languages = is_array($page['languages'] ?? null) ? $page['languages'] : [];

            $previewUrls = [];
            foreach ($languages as $languageRow) {
                $langId = (string)($languageRow['lang_id'] ?? '');
                if ($langId === '') {
                    continue;
                }

                $previewUrls[$langId] = $this->repository->pageUrlPreview(
                    $pageId,
                    $langId,
                    (string)($languageRow['title'] ?? ''),
                    (string)($languageRow['seo_link'] ?? ''),
                    $defaultLanguage
                );
            }

            $page['preview_urls'] = $previewUrls;
            $page['subpages'] = $this->withPreviewUrls($page['subpages'] ?? [], $defaultLanguage);
            $pages[$index] = $page;
        }

        return $pages;
    }

    /**
     * @return array<int, int>
     */
    private function cookieState(string $cookieName): array
    {
        if (empty($_COOKIE[$cookieName])) {
            return [];
        }

        $decoded = @unserialize((string)$_COOKIE[$cookieName], ['allowed_classes' => false]);
        if (!is_array($decoded)) {
            return [];
        }

        $state = [];
        foreach ($decoded as $key => $value) {
            $state[(int)$key] = (int)$value;
        }

        return $state;
    }
}

