<?php

namespace Ignite\Core\Http\ViewComposers;

use Ignite\Core\Contracts\Repositories\PageRepository;
use Ignite\Core\Models\Menu\FooterNavigationMenu;
use Ignite\Core\Models\Menu\Item;
use Ignite\Core\Models\Menu\PageItem;
use Illuminate\Support\HtmlString;
use Illuminate\View\View;

class FooterNavigationMenuComposer
{
    /**
     * @var PageRepository
     */
    protected $pageRepository;

    /**
     * @var FooterNavigationMenu
     */
    protected $manager;

    /**
     * @param PageRepository       $pages
     * @param FooterNavigationMenu $manager
     */
    public function __construct(PageRepository $pages, FooterNavigationMenu $manager)
    {
        $this->pageRepository = $pages;
        $this->manager = $manager;
    }

    /**
     * Bind footer navigation data to the view.
     *
     * @param  View $view
     * @return void
     */
    public function compose(View $view)
    {
        $this->ensureFooterGroups();
        $this->addCorePageItems();
        $this->addCoreAccountItems();

        $view->with('footerNavigation', new HtmlString($this->manager->render()));
    }

    /**
     * Add Core page-backed links to their footer groups.
     *
     * @return void
     */
    protected function addCorePageItems(): void
    {
        $this->addPageToFooterGroup('eligibility', FooterNavigationMenu::SUPPORT_MENU_KEY);
        $this->addPageToFooterGroup('faq', FooterNavigationMenu::SUPPORT_MENU_KEY);
        $this->addPageToFooterGroup('contact', FooterNavigationMenu::SUPPORT_MENU_KEY);
        $this->addPageToFooterGroup('terms', FooterNavigationMenu::LEGAL_MENU_KEY);
        $this->addPageToFooterGroup('privacy', FooterNavigationMenu::LEGAL_MENU_KEY);
    }

    /**
     * Add Core-owned account links to the footer account group.
     *
     * @return void
     */
    protected function addCoreAccountItems(): void
    {
        if (! auth()->check()) {
            return;
        }

        $navigation = $this->navigationConfig();

        $items = [
            $this->createFooterItem(
                url('/participant/profile'),
                data_get($navigation, 'profile.label'),
                data_get($navigation, 'profile.footer_position')
            ),
            $this->createFooterItem(
                url('/transactions'),
                data_get($navigation, 'transactions.label'),
                data_get($navigation, 'transactions.footer_position')
            ),
        ];

        foreach ($items as $item) {
            $this->addItemToFooterGroup($item, FooterNavigationMenu::ACCOUNT_MENU_KEY);
        }
    }

    /**
     * Ensure top-level footer group parent items exist before module listeners run.
     *
     * @return void
     */
    protected function ensureFooterGroups(): void
    {
        $navigation = $this->navigationConfig();

        if (! $this->manager->has(FooterNavigationMenu::PROGRAM_MENU_KEY)) {
            $this->manager->add(
                $this->createFooterGroupItem(
                    FooterNavigationMenu::PROGRAM_MENU_KEY,
                    data_get($navigation, 'program.label'),
                    data_get($navigation, 'program.footer_position')
                )
            );
        }

        if (! $this->manager->has(FooterNavigationMenu::ACCOUNT_MENU_KEY)) {
            $this->manager->add(
                $this->createFooterGroupItem(
                    FooterNavigationMenu::ACCOUNT_MENU_KEY,
                    data_get($navigation, 'account.label'),
                    data_get($navigation, 'account.footer_position')
                )
            );
        }

        if (! $this->manager->has(FooterNavigationMenu::SUPPORT_MENU_KEY)) {
            $this->manager->add(
                $this->createFooterGroupItem(
                    FooterNavigationMenu::SUPPORT_MENU_KEY,
                    data_get($navigation, 'support.label'),
                    data_get($navigation, 'support.footer_position')
                )
            );
        }

        if (! $this->manager->has(FooterNavigationMenu::LEGAL_MENU_KEY)) {
            $this->manager->add(
                $this->createFooterGroupItem(
                    FooterNavigationMenu::LEGAL_MENU_KEY,
                    data_get($navigation, 'legal.label'),
                    data_get($navigation, 'legal.footer_position')
                )
            );
        }
    }

    protected function addPageToFooterGroup(string $code, string $parentMenuKey): void
    {
        $navigation = $this->navigationConfig();
        $page = $this->pageRepository->findByCode($code);

        if (! $page) {
            return;
        }

        $item = new PageItem($page);
        $item->setPosition(data_get($navigation, $code . '.footer_position'));
        $label = data_get($navigation, $code . '.label');
        if (!empty($label)) {
            $item->setLabel(data_get($navigation, $code . '.label'));
        } else {
            $item->setLabel($page->getLabel());
        }

        $this->addItemToFooterGroup($item, $parentMenuKey);
    }

    protected function addItemToFooterGroup($item, string $parentMenuKey): void
    {
        $parent = $this->manager->get($parentMenuKey);

        if (! $parent || $parent->hasChild($item->getMenuKey())) {
            return;
        }

        $this->manager->addChildToParentMenu($item, $parentMenuKey);
    }

    /**
     * Create a footer menu item.
     *
     * @param  string $url
     * @param  string $label
     * @param  int $position
     * @param  bool $allow
     * @return Item
     */
    protected function createFooterItem(string $url, string $label, int $position, bool $allow = true): Item
    {
        return new Item($url, $label, $position, $allow);
    }

    /**
     * Create a footer group item.
     *
     * @param  string $url
     * @param  string $label
     * @param  int $position
     * @return Item
     */
    protected function createFooterGroupItem(string $url, string $label, int $position): Item
    {
        return $this->createFooterItem($url, $label, $position, true);
    }

    /**
     * Get the merged navigation configuration.
     *
     * @return array
     */
    protected function navigationConfig(): array
    {
        return config('core.navigation', []);
    }
}
