<?php

namespace WordpressModels;

use Timber\Timber;

/**
 *
 */
abstract class Page
{

    /**
     * @param string[] $additionalScripts
     */
    public function __construct(
        protected                                 $pageId,
        protected                                 $menuSlug,
        protected                                 $title,
        protected                                 $parentMenuSlug = 'toplevel',
        protected                                 $capability = 'administrator',
        protected int|float|null                  $position = null,
        protected                                 $icon = '',
        private                                   $additionalScripts = [],
        private readonly ?\WordpressModels\Assets $assets = null
    )
    {
        add_action('admin_menu', $this->addAdminMenuItem(...));

        if (isset($this->menuSlug)) {
            $prefix = str_ends_with((string)$this->parentMenuSlug, '.php')
                ? str_replace('.php', '', (string)$this->parentMenuSlug)
                : $this->parentMenuSlug;
            add_action('load-' . $prefix . '_page_' . $this->menuSlug, $this->init(...));
        }
    }

    /**
     * Initializes the page.
     * @return void
     * @hooked load-{parent}_page_{slug}
     */
    public function init(): void
    {
        add_action('admin_enqueue_scripts', $this->enqueueScripts(...));
    }

    /**
     * Renders the page.
     *
     * @return void
     */
    public function renderPage(): void
    {
        $context = $this->buildContext(
            array_merge(Timber::context(), [
                'pageId' => $this->pageId,
                'title' => $this->title
            ])
        );
        Timber::render("page-$this->pageId.twig", $context);
    }

    /**
     * Build the context for the Twig template.
     *
     * @param array $context Base context provided with Timber::context(), the page ID and title.
     * @return mixed
     */
    abstract public function buildContext(array $context = []): mixed;

    public function enqueueScripts(): void
    {
        if ($this->assets) {
            $this->assets->enqueueCompiledScript($this->pageId);

            foreach ($this->additionalScripts as $script) {
                $this->assets->enqueueCompiledScript($script);
            }
        }

        $this->doEnqueue();
    }


    abstract public function doEnqueue();

    public function addAdminMenuItem(): void
    {
        if ($this->parentMenuSlug !== 'toplevel') {
            add_submenu_page(
                $this->parentMenuSlug,
                $this->title,
                $this->title,
                $this->capability,
                $this->menuSlug,
                $this->renderPage(...),
                $this->position ?: '0'
            );
        } else {
            add_menu_page(
                $this->title,
                $this->title,
                $this->capability,
                $this->menuSlug,
                $this->renderPage(...),
                $this->icon,
                $this->position ?: '0'
            );
        }
    }

    /**
     * @return string
     */
    public function getPageId(): string
    {
        return $this->pageId;
    }

    /**
     * @return string
     */
    public function getParentMenuSlug(): string
    {
        return $this->parentMenuSlug;
    }

    /**
     * @return string
     */
    public function getMenuSlug(): string
    {
        return $this->menuSlug;
    }

    /**
     * @return string
     */
    public function getCapability(): string
    {
        return $this->capability;
    }

    /**
     * @return string
     */
    public function getTitle(): string
    {
        return $this->title;
    }

    /**
     * @return float|int|null
     */
    public function getPosition(): float|int|null
    {
        return $this->position;
    }

    /**
     * @return string
     */
    public function getIcon(): string
    {
        return $this->icon;
    }

}
