<?php

/**
 * @package Dotclear
 * @subpackage Backend
 *
 * @copyright Olivier Meunier & Association Dotclear
 * @copyright AGPL-3.0
 */
declare(strict_types=1);

namespace Dotclear\Core\Backend;

use ArrayObject;

class Favorite
{
    /**
     * @param string                                    $id                 favorite id
     * @param ?string                                   $title              favorite title (localized)
     * @param ?string                                   $url                favorite URL
     * @param null|string|list{0: string, 1?: string}   $small_icon         favorite small icon(s) (for menu)
     * @param null|string|list{0: string, 1?: string}   $large_icon         favorite large icon(s) (for dashboard)
     * @param string|bool|null                          $permissions        comma-separated list of permissions, if not set : no restriction
     * @param ?callable                                 $dashboard_cb       callback to modify title if dynamic
     * @param ?callable                                 $active_cb          callback to tell whether current page matches favorite or not
     * @param bool                                      $active             is favorite currently active
     * @param ?Icon                                     $menu_icon          favorite menu icon (small icons)
     * @param ?Icon                                     $dashboard_icon     favorite dashboard icon (large icons)
     */
    public function __construct(
        protected readonly string $id,
        protected ?string $title,
        protected readonly ?string $url,
        protected null|string|array $small_icon,
        protected null|string|array $large_icon,
        protected readonly null|string|bool $permissions = null,
        protected readonly mixed $dashboard_cb = null,
        protected readonly mixed $active_cb = null,
        protected bool $active = false,
        protected ?Icon $menu_icon = null,
        protected ?Icon $dashboard_icon = null,
    ) {
    }

    /**
     * Return favorite id
     */
    public function id(): string
    {
        return $this->id;
    }

    /**
     * Return favorite title
     */
    public function title(): ?string
    {
        return $this->title;
    }

    /**
     * Return favorite URL
     */
    public function url(): ?string
    {
        return $this->url;
    }

    /**
     * Return favorite small icon
     *
     * @deprecated since 2.39 use Favorite::menuIcon() instead
     *
     * @return null|string|list{0: string, 1?: string}
     */
    public function smallIcon(): null|string|array
    {
        return $this->menu_icon instanceof Icon ? $this->menu_icon->getIcons() : $this->small_icon;
    }

    /**
     * Return favorite large icon
     *
     * @deprecated since 2.39 use Favorite::dashboardIcon() instead
     *
     * @return null|string|list{0: string, 1?: string}
     */
    public function largeIcon(): null|string|array
    {
        return $this->dashboard_icon instanceof Icon ? $this->dashboard_icon->getIcons() : $this->large_icon;
    }

    /**
     * Return favorite permissions
     */
    public function permissions(): null|string|bool
    {
        return $this->permissions;
    }

    /**
     * Return favorite dashboard callback
     */
    public function dashboardCallback(): ?callable
    {
        return $this->dashboard_cb;
    }

    /**
     * Set dashboard title if possible using defined callback
     */
    public function callDashboardCallback(): void
    {
        if (is_callable($this->dashboard_cb)) {
            // Prepare modifiable favorite properties
            $data = new ArrayObject([
                'title'          => $this->title,
                'small-icon'     => $this->small_icon,
                'large-icon'     => $this->large_icon,
                'menu-icon'      => $this->menu_icon,
                'dashboard-icon' => $this->dashboard_icon,
            ]);

            call_user_func($this->dashboard_cb, $data);

            // Store new values if provided
            if ($data->offsetExists('title') && is_string($data['title'])) {
                $this->title = $data['title'];
            }

            if ($data->offsetExists('small-icon') && (is_array($data['small-icon']) || is_string($data['small-icon']))) {
                $this->small_icon = $data['small-icon'];
            }

            if ($data->offsetExists('large-icon') && (is_array($data['large-icon']) || is_string($data['large-icon']))) {
                $this->large_icon = $data['large-icon'];
            }

            if ($data->offsetExists('menu-icon') && $data['menu-icon'] instanceof Icon) {
                $this->menu_icon = $data['menu-icon'];
            }

            if ($data->offsetExists('dashboard-icon') && $data['dashboard-icon'] instanceof Icon) {
                $this->dashboard_icon = $data['dashboard-icon'];
            }
        }
    }

    /**
     * Return favorite active callback
     */
    public function activeCallback(): ?callable
    {
        return $this->active_cb;
    }

    /**
     * Return favorite active status using defined callback
     *
     * @param   string                  $url        URL part before query string
     * @param   array<array-key, mixed> $request    Usually $_REQUEST array
     */
    public function callActiveCallback(string $url, array $request): bool
    {
        return is_callable($this->active_cb) && (bool) call_user_func($this->active_cb, $url, $request);
    }

    /**
     * Return favorite active status
     */
    public function active(): bool
    {
        return $this->active;
    }

    /**
     * Set favorite active status
     */
    public function setActive(bool $active): void
    {
        $this->active = $active;
    }

    public function menuIcon(): ?Icon
    {
        return $this->menu_icon;
    }

    public function dashboardIcon(): ?Icon
    {
        return $this->dashboard_icon;
    }
}
