<?php

/**
 * Handles an asset.
 *
 * @package northmill-online-shared
 */
declare (strict_types=1);
namespace Northmill_Online_Shared_Checkout\Northmill_Online_Shared\Modules\Assets\Models;

use Closure;
use Northmill_Online_Shared_Checkout\Northmill_Online_Shared\Abstract_Shared_Base;
use Northmill_Online_Shared_Checkout\Northmill_Online_Shared\Modules\Assets\Asset_Location_Enum;
use Northmill_Online_Shared_Checkout\Northmill_Online_Shared\Modules\Loggers\Log_Level_Enum;
defined('ABSPATH') || exit;
/**
 * Class Abstract_Asset_Model
 */
abstract class Abstract_Asset_Model
{
    /**
     * The handle base for the asset.
     *
     * @var string
     */
    protected string $handle_base;
    /**
     * The name of the asset file, excluding the extension (and excluding '.min', if applicable).
     *
     * @var string
     */
    protected string $filename;
    /**
     * The name of the asset file, with dashes instead of slashes (for sub dirs).
     *
     * @var string
     */
    protected string $dashed_filename;
    /**
     * The name of the asset file, with underscores instead of slashes (for sub dirs) and dashes.
     *
     * @var string
     */
    protected string $underscored_filename;
    /**
     * The asset dependencies.
     *
     * @var string[]
     */
    protected array $asset_dependencies;
    /**
     * Where asset should be enqueued.
     *
     * @var Asset_Location_Enum
     */
    protected Asset_Location_Enum $location;
    /**
     * Whether the asset should be enqueued.
     *
     * @var bool|array|Closure
     */
    protected bool|array|Closure $should_enqueue;
    /**
     * Whether the asset is a dependency.
     * A dependency isn't enqueued directly, but is instead enqueued by another asset.
     * Also, the handle is not prefixed with the package name.
     *
     * @var bool
     */
    protected bool $is_dependency;
    /**
     * Constructor.
     *
     * @param string              $filename           The name of the asset file, excluding the extension (and excluding '.min', if applicable).
     * @param Asset_Location_Enum $location           Where asset should be enqueued.
     * @param array               $asset_dependencies The asset dependencies.
     * @param bool|array|Closure  $should_enqueue     Whether the asset should be enqueued. Defaults to true.
     * @param bool                $is_dependency      Whether the asset is a dependency. Defaults to false.
     */
    public function __construct(string $filename, Asset_Location_Enum $location, array $asset_dependencies = array(), bool|array|Closure $should_enqueue = \true, bool $is_dependency = \false)
    {
        $this->filename = $filename;
        $this->dashed_filename = str_replace('/', '-', $filename);
        $this->underscored_filename = str_replace(array('/', '-'), '_', $filename);
        $this->location = $location;
        $this->asset_dependencies = $asset_dependencies;
        $this->should_enqueue = $should_enqueue;
        $this->is_dependency = $is_dependency;
        $this->handle_base = $this->build_handle_base();
        if (Asset_Location_Enum::ADMIN === $this->location) {
            add_action('admin_enqueue_scripts', array($this, 'maybe_enqueue_assets'));
        } elseif (Asset_Location_Enum::FRONTEND === $this->location) {
            add_action('wp_enqueue_scripts', array($this, 'maybe_enqueue_assets'));
        } elseif (Asset_Location_Enum::BOTH === $this->location) {
            add_action('admin_enqueue_scripts', array($this, 'maybe_enqueue_assets'));
            add_action('wp_enqueue_scripts', array($this, 'maybe_enqueue_assets'));
        }
    }
    /**
     * Builds the handle base for the asset.
     *
     * @return string The handle base for the asset.
     */
    private function build_handle_base(): string
    {
        $handle_base_parts = array();
        if (!$this->is_dependency) {
            $handle_base_parts[] = Abstract_Shared_Base::base_instance()->package_info->get_service_name();
        }
        if (Asset_Location_Enum::ADMIN === $this->location) {
            $handle_base_parts[] = 'admin';
        }
        return implode('-', $handle_base_parts);
    }
    /**
     * Builds the handle for the asset.
     *
     * @param string $type      The type of asset ('script' or 'style').
     * @param bool   $is_shared Whether the asset is shared.
     *
     * @return string The handle for the asset.
     */
    protected function build_handle(string $type, bool $is_shared): string
    {
        $handle_parts = array();
        if (!empty($this->handle_base)) {
            $handle_parts[] = $this->handle_base;
        }
        $handle_parts[] = $this->dashed_filename;
        $handle_parts[] = $type;
        $handle_parts[] = $is_shared ? 'shared' : 'package';
        return implode('-', $handle_parts);
    }
    /**
     * Attempts to enqueue the asset files, both from Shared and from the package.
     *
     * @return void
     */
    public function maybe_enqueue_assets(): void
    {
        $assets_module = Abstract_Shared_Base::base_instance()->assets;
        if (is_callable($this->should_enqueue)) {
            $should_enqueue = call_user_func($this->should_enqueue);
        } elseif (is_bool($this->should_enqueue)) {
            $should_enqueue = $this->should_enqueue;
        } else {
            Abstract_Shared_Base::base_instance()->logger->log('assets', 'Invalid should_enqueue value', array('filename' => $this->filename, 'location' => $this->location, 'should_enqueue' => $this->should_enqueue), Log_Level_Enum::ERROR);
            $should_enqueue = \true;
        }
        if (!$should_enqueue) {
            return;
        }
        $this->maybe_enqueue_asset(\true, $assets_module->get_shared_assets_path(), $assets_module->get_shared_assets_url());
        $this->maybe_enqueue_asset(\false, $assets_module->get_package_assets_path(), $assets_module->get_package_assets_url());
    }
    /**
     * Enqueues an asset if it is available.
     *
     * @param bool   $is_shared Whether the asset is shared.
     * @param string $path_base The base path for the asset.
     * @param string $url_base  The base URL for the asset.
     *
     * @return void
     */
    abstract protected function maybe_enqueue_asset(bool $is_shared, string $path_base, string $url_base): void;
    /**
     * Retrieves the asset file paths and URLs for a given type.
     *
     * @param string $path The base path for the asset.
     * @param string $url The base URL for the asset.
     * @param string $type The type of asset ('js' or 'css'). Defaults to 'js'.
     *
     * @return array|false The admin asset file paths and URLs for the given type, or false if the asset file doesn't exist.
     */
    protected function get_asset(string $path, string $url, string $type = 'js'): array|false
    {
        switch ($type) {
            case 'js':
                $long_type = 'script';
                break;
            case 'css':
                $long_type = 'style';
                break;
            default:
                return \false;
        }
        $is_admin = Asset_Location_Enum::ADMIN === $this->location;
        $alternatives = array($type . '/' . ($is_admin ? 'admin/' : '') . $this->filename . '.min.' . $type, $type . '/' . ($is_admin ? 'admin/' : '') . $this->filename . '.' . $type, ($is_admin ? 'admin/' : '') . 'out/' . $this->filename . '-' . $long_type . '.min.' . $type, ($is_admin ? 'admin/' : '') . 'out/' . $this->filename . '-' . $long_type . '.' . $type);
        foreach ($alternatives as $alternative) {
            if (file_exists($path . $alternative)) {
                return array('path' => $path . $alternative, 'url' => $url . $alternative);
            }
        }
        return \false;
    }
}
