<?php
namespace Booktics\Assets;

if ( ! defined( 'ABSPATH' ) ) exit;

use Booktics\Contracts\Hookable_Service_Contract;

/**
 * Main assets management class
 */
abstract class Base_Assets implements Hookable_Service_Contract {
    /**
     * Get all scripts
     *
     * @return  array list of script to register
     */
    abstract public function get_scripts(): array;

    /**
     * Get all styles
     *
     * @return  array   list of styles to regiser
     */
    abstract public function get_styles(): array;

    /**
     * Register scripts and styles
     *
     * @return  void
     */
    public function register_styles_scripts() {
        // Register i18n loader early so other scripts can depend on it.
        $this->register_global_scripts();
        $this->register_scripts();
        $this->register_styles();
    }

    /**
     * Register scripts
     *
     * @param  array $scripts
     *
     * @return void
     */
    public function register_scripts() {
        $scripts = $this->get_scripts();

        foreach ( $scripts as $handle => $script ) {
            $deps      = isset( $script['deps'] ) ? $script['deps'] : [];
            $in_footer = isset( $script['in_footer'] ) ? $script['in_footer'] : true;
            $version   = isset( $script['version'] ) ? $script['version'] : $this->get_version( $script['src'] );

            $deps = $this->get_dependencies( $script['src'], $deps );

            // Mirror wp-cafe: if script uses wp-i18n, ensure our i18n loader runs first.
            if ( in_array( 'wp-i18n', $deps, true ) ) {
                $deps[] = 'booktics-i18n-loader';
            }

            wp_register_script( $handle, $script['src'], $deps, $version, $in_footer );

            // Enable JS translations for bundles that use wp.i18n.
            if ( function_exists( 'wp_set_script_translations' ) ) {
                // Don't force a path: translations are commonly in WP_LANG_DIR/plugins.
                wp_set_script_translations( $handle, 'booktics' );
            }

            // Ensure preloaded locale data is actually registered in wp.i18n for
            // pages that never trigger per-chunk JSON downloads.
            if ( 'booktics-packages' === $handle ) {
                wp_add_inline_script(
                    'booktics-packages',
                    '(function(){try{if(window.bookticsPreloadedLocaleData && window.wp && window.wp.i18n && window.wp.i18n.setLocaleData){window.wp.i18n.setLocaleData(window.bookticsPreloadedLocaleData,"booktics");}}catch(e){}})();',
                    'before'
                );
            }
        }
    }

    /**
     * Register global scripts.
     *
     * @return void
     */
    private function register_global_scripts() {
        $scripts = [
            'booktics-i18n-loader' => [
                'src'       => booktics()->assets_url . '/build/js/i18n-loader.js',
                'deps'      => [],
                'in_footer' => true,
            ],
        ];

        foreach ( $scripts as $handle => $script ) {
            $deps      = isset( $script['deps'] ) ? $script['deps'] : [];
            $in_footer = isset( $script['in_footer'] ) ? $script['in_footer'] : true;
            $version   = isset( $script['version'] ) ? $script['version'] : $this->get_version( $script['src'] );

            $deps = $this->get_dependencies( $script['src'], $deps );

            wp_register_script( $handle, $script['src'], $deps, $version, $in_footer );
        }
    }

    /**
     * Enqueue i18n loader and set its state.
     *
     * @return void
     */
    protected function enqueue_i18n_loader() {
        $data = [
            'baseUrl'        => false,
            'locale'         => determine_locale(),
            'domainMap'      => [],
            'domainPaths'    => [],
            'translationMap' => (object) [],
        ];

        $lang_dir    = WP_LANG_DIR;
        $content_dir = WP_CONTENT_DIR;
        $abspath     = ABSPATH;

        if ( strpos( $lang_dir, $content_dir ) === 0 ) {
            $data['baseUrl'] = content_url(
                substr( trailingslashit( $lang_dir ), strlen( trailingslashit( $content_dir ) ) )
            );
        } elseif ( strpos( $lang_dir, $abspath ) === 0 ) {
            $data['baseUrl'] = site_url(
                substr( trailingslashit( $lang_dir ), strlen( untrailingslashit( $abspath ) ) )
            );
        }

        $data['translationMap'] = (object) $this->get_translation_map();
        $data['domainPaths']    = (object) $this->get_translation_directories();

        wp_enqueue_script( 'booktics-i18n-loader' );

        $data['domainMap']   = (object) $data['domainMap'];
        $data['domainPaths'] = (object) $data['domainPaths'];

        // If a consolidated .l10n.php file exists, preload all messages to avoid
        // relying on per-chunk JSON requests (which may be missing).
        $preload = null;
        $l10n_file = trailingslashit( WP_LANG_DIR ) . 'plugins/booktics-' . $data['locale'] . '.l10n.php';
        $l10n_file_alt = trailingslashit( WP_LANG_DIR ) . 'plugins/booktics-' . str_replace( '-', '_', $data['locale'] ) . '.l10n.php';
        $l10n_file_legacy = trailingslashit( WP_LANG_DIR ) . 'plugins/booktics-' . str_replace( '_', '-', $data['locale'] ) . '.l10n.php';
        $l10n_candidates = array_unique( array_filter( [ $l10n_file, $l10n_file_alt, $l10n_file_legacy ] ) );

        foreach ( $l10n_candidates as $candidate ) {
            if ( file_exists( $candidate ) ) {
                $preload = include $candidate;
                break;
            }
        }

        $inline = '(function(){var k="bookticsI18nLoader"; if (typeof window[k] === "undefined") { window[k] = {}; } window[k].state = ' . wp_json_encode( $data, JSON_UNESCAPED_SLASHES ) . ';';

        if ( is_array( $preload ) && ! empty( $preload['messages'] ) && is_array( $preload['messages'] ) ) {
            $messages = [];
            foreach ( $preload['messages'] as $msgid => $msgstr ) {
                if ( is_string( $msgid ) && is_string( $msgstr ) ) {
                    $messages[ $msgid ] = [ $msgstr ];
                }
            }

            $locale_data = [
                '' => [
                    'domain' => 'booktics',
                    'lang'   => $data['locale'],
                    'plural-forms' => isset( $preload['plural-forms'] ) ? $preload['plural-forms'] : 'nplurals=2; plural=n != 1;',
                ],
            ] + $messages;

            $encoded_locale_data = wp_json_encode( $locale_data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE );
            $inline .= ' window[k].preloadedLocaleData = ' . $encoded_locale_data . '; window.bookticsPreloadedLocaleData = ' . $encoded_locale_data . ';';
        }

        $inline .= '})();';

        wp_add_inline_script(
            'booktics-i18n-loader',
            $inline,
            'before'
        );
    }

    /**
     * Register styles
     *
     * @param  array $styles
     *
     * @return void
     */
    public function register_styles() {
        $styles = $this->get_styles();

        foreach ( $styles as $handle => $style ) {
            $deps    = isset( $style['deps'] ) ? $style['deps'] : false;
            $version = booktics()->version;

            wp_register_style( $handle, $style['src'], $deps, $version );
        }
    }

    /**
     * Get script and style file dependencies
     *
     * @param   string  $file_name
     * @param   array  $deps
     *
     * @return  array
     */
    private function get_dependencies( $file_name, $deps = [] ) {
        $assets = $this->get_file_assets( $file_name );

        $assets_deps = ! empty( $assets['dependencies'] ) ? $assets['dependencies'] : [];

        $merged_deps = array_merge( $assets_deps, $deps );

        return $merged_deps;
    }

    /**
     * Get file assets
     *
     * @param   string  $file_name
     *
     * @return  array
     */
    private function get_file_assets( $file_url ) {
        $file   = $this->get_file_path( $file_url );
        $assets = [];

        if ( file_exists( $file ) ) {
            $assets = include $file;
        }

        return $assets;
    }

    /**
     * Get script file version
     *
     * @param   string  $file_name
     *
     * @return  string
     */
    private function get_version( $file_name ) {
        $assets      = $this->get_file_assets( $file_name );
        $assets_vers = ! empty( $assets['version'] ) ? $assets['version'] : booktics()->version;
        return $assets_vers;
    }

    /**
     * Get file path from url
     *
     * @param   string  $url
     *
     * @return string
     */
    private function get_file_path( $url ) {
        // Check if the URL is valid
        if ( ! filter_var( $url, FILTER_VALIDATE_URL ) ) {
            return false;
        }

        // Parse the URL
        $url_parts = wp_parse_url( $url );

        // Check if the URL has a path component
        if ( ! isset( $url_parts['path'] ) ) {
            return false; // URL does not contain a path
        }

        $clean_path = str_replace( '.js', '.asset.php', $url_parts['path'] );

        // Get the file path from the URL path.
        if ( isset( $_SERVER['DOCUMENT_ROOT'] ) ) {
            $file_path = sanitize_text_field( wp_unslash( $_SERVER['DOCUMENT_ROOT'] ) ) . $clean_path;
        } else {
            $file_path = ''; // Or another appropriate fallback.
        }

        // Check if the file exists
        if ( ! file_exists( $file_path ) ) {
            return false; // File does not exist.
        }

        return $file_path;
    }

    /**
     * Get map of translation file hashes to their URLs.
     *
     * Scans all translation directories for JSON files matching
     * the current locale and domain, building a hash => URL map.
     *
     * @return array Hash => URL map.
     */
    private function get_translation_map() {
        $map    = [];
        $locale = determine_locale();
        $domain = 'booktics';

        $locale_variants = array_unique( array_filter( [
            $locale,
            str_replace( '-', '_', $locale ),
            str_replace( '_', '-', $locale ),
        ] ) );

        foreach ( $this->get_translation_directories() as $dir ) {
            if ( ! is_dir( $dir['path'] ) || ! is_readable( $dir['path'] ) ) {
                continue;
            }

            foreach ( $locale_variants as $variant ) {
                $files = glob( $dir['path'] . $domain . '-' . $variant . '-*.json' );
                if ( ! $files ) {
                    continue;
                }

                foreach ( $files as $file ) {
                    $filename = basename( $file );
                    // Extract hash: everything after "{domain}-{locale}-".
                    $variant_prefix = $domain . '-' . $variant . '-';
                    if ( strpos( $filename, $variant_prefix ) === 0 ) {
                        $hash = substr( $filename, strlen( $variant_prefix ), -5 ); // strip .json
                        if ( $hash ) {
                            $map[ $hash ] = trailingslashit( $dir['url'] ) . $filename;
                        }
                    }
                }
            }
        }

        return $map;
    }

    /**
     * Return translation directory paths and their corresponding URLs.
     *
     * Covers the standard WP languages/plugins/ directory, Loco Translate's
     * directory, and the plugin's own bundled languages/ folder.
     *
     * @return array<int, array{path: string, url: string}>
     */
    private function get_translation_directories() {
        return [
            [
                'path' => WP_CONTENT_DIR . '/languages/plugins/',
                'url'  => content_url( 'languages/plugins/' ),
            ],
            [
                'path' => WP_CONTENT_DIR . '/languages/loco/plugins/',
                'url'  => content_url( 'languages/loco/plugins/' ),
            ],
            [
                'path' => booktics()->plugin_directory . '/languages/',
                'url'  => booktics()->plugin_url . '/languages/',
            ],
        ];
    }
}
