<?php

namespace MetForm_Pro\Base;
use MetForm_Pro\Traits\Singleton;


defined( 'ABSPATH' ) || exit;

/**
 * Assets_Base
 *
 * Shared foundation for Assets_Register and Assets_Enqueue.
 * Holds all asset definitions, the manifest loader, and URL resolvers.
 * Neither registers nor enqueues anything.
 *
 * @package ElementsKit_Lite\Config
 * @since   3.9.6
 */
abstract class Assets_Base {

    use Singleton;
    /**
     * Asset type constants.
     */
    const SCRIPT = 'script';
    const STYLE  = 'style';

    /**
     * Cache for loaded asset manifests to avoid duplicate file reads.
     *
     * @var array<string, array>
     */
    private array $manifest_cache = [];

    /**
     * Cache for merged asset definitions to avoid repeated array construction.
     *
     * @var array<int, array>|null
     */
    private ?array $definitions_cache = null;

    /**
     * Returns admin-only asset definitions (build/admin/).
     *
     * @since 3.9.6
     *
     * @return array<int, array>
     */
    private function get_admin_asset_definitions(): array {
        return [
            [
                'type'     => self::SCRIPT,
                'handle'   => 'metform-pro-admin-js',
                'source'   => 'build',
                'src'      => 'admin/admin-shell/index.js',
                'manifest' => 'admin/admin-shell/index.asset.php',
                'extra_dependencies' => [ 'jquery' ],
            ],
            [
                'type'     => self::SCRIPT,
                'handle'   => 'metform-author-search',
                'source'   => 'build',
                'src'      => 'admin/author-search/index.js',
                'manifest' => 'admin/author-search/index.asset.php',
                'extra_dependencies' => [ 'jquery' ],
            ],
            [
                'type'     => self::SCRIPT,
                'handle'   => 'metform-pdf-export',
                'source'   => 'build',
                'src'      => 'admin/pdf-export/index.js',
                'manifest' => 'admin/pdf-export/index.asset.php',
                'extra_dependencies' => [],
            ],
            [
                'type'     => self::SCRIPT,
                'handle'   => 'metform-pro-integration-js',
                'source'   => 'build',
                'src'      => 'admin/integrations/index.js',
                'manifest' => 'admin/integrations/index.asset.php',
                'extra_dependencies' => [ 'jquery' ],
            ],
            [
                'type'     => self::STYLE,
                'handle'   => 'metform-pro-integration-style',
                'source'   => 'build',
                'src'      => 'admin/integrations/index.css',
                'manifest' => 'admin/integrations/index.asset.php',
                'extra_dependencies' => [],
            ],
        ];
    }

    /**
     * Returns frontend asset definitions (build/frontend/).
     *
     * @since 3.9.6
     *
     * @return array<int, array>
     */
    private function get_frontend_asset_definitions(): array {
        return [
            [
                'type'     => self::SCRIPT,
                'handle'   => 'metform-pro-repeater',
                'source'   => 'build',
                'src'      => 'frontend/repeater/index.js',
                'manifest' => 'frontend/repeater/index.asset.php',
                'extra_dependencies' => ['elementor-frontend'],
            ],
            [
                'type'     => self::STYLE,
                // New handle: simple-repeater styles used to ship inside the
                // global metform-pro-style bundle; now split out with the
                // repeater feature bundle, so they need their own handle.
                'handle'   => 'metform-pro-repeater-style',
                'source'   => 'build',
                'src'      => 'frontend/repeater/index.css',
                'manifest' => 'frontend/repeater/index.asset.php',
                'extra_dependencies' => [],
            ],
        ];
    }

    /**
     * Returns shared/global asset definitions (build/styles/).
     *
     * @since 3.9.6
     *
     * @return array<int, array>
     */
    private function get_shared_asset_definitions(): array {
        return [
            [
                'type'     => self::STYLE,
                'handle'   => 'metform-pro-category-top',
                'source'   => 'build',
                'src'      => 'styles/category-top.css',
                'manifest' => 'styles/category-top.asset.php',
                'extra_dependencies' => [],
            ],
            [
                'type'     => self::STYLE,
                'handle'   => 'metform-pro-style',
                'source'   => 'build',
                'src'      => 'styles/metform-pro.css',
                'manifest' => 'styles/metform-pro.asset.php',
                'extra_dependencies' => [],
            ],
        ];
    }


    private function get_third_party_asset_definitions(): array {
    return [
        [
            'type'     => self::SCRIPT,
            'handle'   => 'metform-html2canvas',
            'source'   => 'assets',
            'src'      => 'libs/html2canvas/html2canvas.js',
            'manifest' => '',
            'extra_dependencies' => [],
        ],
        [
            'type'     => self::SCRIPT,
            'handle'   => 'metform-jspdf',
            'source'   => 'assets',
            'src'      => 'libs/jspdf/jspdf.min.js',
            'manifest' => '',
            'extra_dependencies' => [],
        ],
    ];
}


    /**
     * Merges all asset groups into a single definitions array.
     * Result is cached after the first call.
     *
     * @since 3.9.6
     *
     * @return array<int, array>
     */
    protected function get_all_asset_definitions(): array {
        if ( $this->definitions_cache !== null ) {
            return $this->definitions_cache;
        }

        $this->definitions_cache = array_merge(
            $this->get_admin_asset_definitions(),
            $this->get_frontend_asset_definitions(),
            $this->get_shared_asset_definitions(),
            $this->get_third_party_asset_definitions()
        );

        return $this->definitions_cache;
    }

    /**
     * Loads and caches an asset manifest file.
     * Returns a safe fallback if the file is missing.
     *
     * @since 3.9.6
     *
     * @param string $relative_path Path relative to build/.
     *
     * @return array{ dependencies: string[], version: string }
     */
    protected function load_manifest( string $relative_path ): array {
        if ( $relative_path === '' ) {
            return [ 'dependencies' => [], 'version' => METFORM_PRO_VERSION ];
        }

        if ( isset( $this->manifest_cache[ $relative_path ] ) ) {
            return $this->manifest_cache[ $relative_path ];
        }

        $full_path = METFORM_PRO_PATH . 'build/' . $relative_path;

        $this->manifest_cache[ $relative_path ] = file_exists( $full_path )
            ? (array) include $full_path
            : [ 'dependencies' => [], 'version' => METFORM_PRO_VERSION ];

        return $this->manifest_cache[ $relative_path ];
    }

    /**
     * Returns the full URL for the src of a handle by type.
     *
     * @since 3.9.6
     *
     * @param string $handle The asset handle.
     * @param string $type   Asset type: self::SCRIPT or self::STYLE.
     *
     * @return string Full URL or empty string if not found.
     */
    public static function src( string $handle, string $type = self::STYLE ): string {
        foreach ( static::instance()->get_all_asset_definitions() as $definition ) {
            if ( $definition['handle'] === $handle && $definition['type'] === $type ) {
                return METFORM_PRO_URL . 'build/' . $definition['src'];
            }
        }
        return '';
    }

    /**
     * Returns URLs for json files of a handle.
     *
     * @since 3.9.6
     *
     * @param string $handle The asset handle.
     * @param string $name   Optional specific json key.
     *
     * @return string|array<string, string>
     */
    public static function json( string $handle, string $name = '' ): string|array {
        foreach ( static::instance()->get_all_asset_definitions() as $definition ) {
            if ( $definition['handle'] !== $handle || ! isset( $definition['json'] ) ) {
                continue;
            }
            $urls = array_map(
                fn( $path ) => METFORM_PRO_URL . 'build/' . $path,
                $definition['json']
            );
            return $name !== '' ? ( $urls[ $name ] ?? '' ) : $urls;
        }
        return $name !== '' ? '' : [];
    }

    /**
     * Returns URLs for image files of a handle.
     *
     * @since 3.9.6
     *
     * @param string $handle The asset handle.
     * @param string $name   Optional specific image key.
     *
     * @return string|array<string, string>
     */
    public static function images( string $handle, string $name = '' ): string|array {
        foreach ( static::instance()->get_all_asset_definitions() as $definition ) {
            if ( $definition['handle'] !== $handle || ! isset( $definition['images'] ) ) {
                continue;
            }
            $urls = array_map(
                fn( $path ) => METFORM_PRO_URL . 'build/' . $path,
                $definition['images']
            );
            return $name !== '' ? ( $urls[ $name ] ?? '' ) : $urls;
        }
        return $name !== '' ? '' : [];
    }

    /**
     * Returns URLs for font files of a handle.
     *
     * @since 3.9.6
     *
     * @param string $handle The asset handle.
     * @param string $name   Optional specific font key.
     *
     * @return string|array<string, string>
     */
    public static function font( string $handle, string $name = '' ): string|array {
        foreach ( static::instance()->get_all_asset_definitions() as $definition ) {
            if ( $definition['handle'] !== $handle || ! isset( $definition['font'] ) ) {
                continue;
            }
            $urls = array_map(
                fn( $path ) => METFORM_PRO_URL . 'build/' . $path,
                $definition['font']
            );
            return $name !== '' ? ( $urls[ $name ] ?? '' ) : $urls;
        }
        return $name !== '' ? '' : [];
    }
}
