<?php

class Vite {
    protected $base_url = '';
    protected $base_path = '';

    protected $is_running = false;

    protected $entryPoints = [];
    protected $hotFile;
    protected $buildDirectory = 'dist';

    protected static $manifests = [];


    public function __construct() {
        $this->base_url = get_template_directory_uri();
        $this->base_path = get_template_directory();
    }

    public function isRunning() {
        return is_file($this->hotFile());
    }

    public function withEntrypoints($entrypoints) {
        $this->entryPoints = $entrypoints;

        return $this;
    }

    public function hotFile() {
        return $this->hotFile ?? $this->base_path.'/hot';
    }

    public function useHotFile($path) {
        $this->hotFile = $path;

        return $this;
    }

    public function useBuildDirectory($path) {
        $this->buildDirectory = $path;

        return $this;
    }

    public function __invoke($entrypoints, $buildDirectory = null) {
        $buildDirectory ??= $this->buildDirectory;

        if($this->isRunning()) {
            $entrypoints[] = '@vite/client';
            $out = '';

            foreach($entrypoints as $entry) {
                $out .= $this->makeTagForChunk($entrypoints, $this->hotAsset($entry), null, null)."\r\n";
            }

            return $out;
        }

        $manifest = $this->manifest($buildDirectory);
        $tags = [];

        foreach($entrypoints as $entrypoint) {
            $chunk = $this->chunk($manifest, $entrypoint);

            foreach($chunk['imports'] ?? [] as $import) {
                foreach($manifest[$import]['css'] ?? [] as $css) {
                    $partialManifest = $this->array_where($manifest, 'file', $css);

                    $tags[] = $this->makeTagForChunk(array_key_first($partialManifest), $this->assetPath("{$buildDirectory}/{$css}"), $partialManifest[array_key_first($partialManifest)], $manifest);
                }
            }

            $tags[] = $this->makeTagForChunk('', $this->assetPath("{$buildDirectory}/{$chunk['file']}"), '', $manifest);

            foreach($chunk['css'] ?? [] as $css) {
                $partialManifest = $this->array_where($manifest, 'file', $css);

                $tags[] = $this->makeTagForChunk(array_key_first($partialManifest), $this->assetPath("{$buildDirectory}/{$css}"), $partialManifest[array_key_first($partialManifest)], $manifest);
            }
        }

        return implode("\r\n", $tags);
    }

    protected function makeTagForChunk($src, $url, $chunk, $manifest) {
        return $this->makeTag($url);
    }

    protected function makeTag($url) {
        if($this->isCssPath($url)) {
            return $this->makeStylesheetTag($url);
        }

        return $this->makeScriptTag($url);
    }

    protected function makeScriptTag($url) {
        return $this->makeScriptTagWithAttributes($url, []);
    }

    protected function makeStylesheetTag($url) {
        return $this->makeStylesheetTagWithAttributes($url, []);
    }

    protected function makeScriptTagWithAttributes($url, $attributes) {
        $attributes = $this->parseAttributes(array_merge([
            'type' => 'module',
            'src' => $url
        ], $attributes));

        return '<script '.implode(' ', $attributes).'></script>';
    }

    protected function makeStylesheetTagWithAttributes($url, $attributes) {
        $attributes = $this->parseAttributes(array_merge([
            'rel' => 'stylesheet',
            'href' => $url
        ]));

        return '<link '.implode(' ', $attributes).' />';
    }

    protected function parseAttributes($attributes) {
        $out = [];

        foreach($attributes as $key => $value) {
            $out[] = $key.'="'.$value.'"';
        }

        return $out;
    }

    protected function isCssPath($path) {
        return preg_match('/\.(css|less|sass|scss|styl|stylus|pcss|postcss)$/', $path) === 1;
    }

    protected function hotAsset($asset) {
        return rtrim(file_get_contents($this->hotFile())).'/'.$asset;
    }

    public function asset($asset, $buildDirectory = null) {
        $buildDirectory ??= $this->buildDirectory;

        if($this->isRunning()) {
            return $this->hotAsset($asset);
        }

        $chunk = $this->chunk($this->manifest($buildDirectory), $asset);

        return $this->assetPath($buildDirectory.'/'.$chunk['file']);
    }

    protected function assetPath($path) {
        return asset($path);
    }

    protected function manifest($buildDirectory) {
        $path = $this->manifestPath($buildDirectory);

        if(!isset(static::$manifests[$path])) {
            if (!is_file($path)) {
                throw new Exception("Vite manifest not found at: {$path}");
            }

            static::$manifests[$path] = json_decode(file_get_contents($path), true);
        }

        return static::$manifests[$path];
    }

    protected function manifestPath($buildDirectory) {
        return $this->base_path.'/'.$buildDirectory.'/manifest.json';
    }

    protected function chunk($manifest, $file) {
        if(!isset($manifest[$file])) {
            throw new Exception("Unable to locate file in Vite manifest: {$file}");
        }

        return $manifest[$file];
    }


    private function array_where($arr, $key, $value) {
        return array_filter($arr, function($ar) use($key, $value) {
            return ($ar[$key] == $value);
        });
    }

    public function baseUrl($url) {
        $this->base_url = $url;

        return $this;
    }

    public function basePath($path) {
        $this->base_path = $path;

        return $this;
    }
}

function vite($entrypoints, $buildDirectory = null) {
    $vite = new Vite();
    return $vite($entrypoints, $buildDirectory);
}

function asset($path) {
    return get_template_directory_uri().'/'.$path;
}


/**
 *
 * Remove emoji scripts
 *
 */
function wv_disable_emojis() {
	remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
	remove_action( 'admin_print_scripts', 'print_emoji_detection_script' );
	remove_action( 'wp_print_styles', 'print_emoji_styles' );
	remove_action( 'admin_print_styles', 'print_emoji_styles' );
	remove_filter( 'the_content_feed', 'wp_staticize_emoji' );
	remove_filter( 'comment_text_rss', 'wp_staticize_emoji' );
	remove_filter( 'wp_mail', 'wp_staticize_emoji_for_email' );
}
add_action( 'init', 'wv_disable_emojis' );

/**
 *
 * Remove wp-embed script
 *
 */
function wv_disable_embed_js(){
  wp_deregister_script( 'wp-embed' );
}
add_action( 'wp_footer', 'wv_disable_embed_js' );

/**
 *
 * Get optimized image and webp version
 *
 */
function wv_img($name, $alt){
  $file_path = get_template_directory() . '/assets/img/' . $name;
  $file_type = mime_content_type($file_path);
  $file_name = pathinfo($name, PATHINFO_FILENAME);;
  $file_path_webp = get_template_directory() . '/assets/img/' . $file_name . '.webp';
  $file_size = getimagesize($file_path);

  if(file_exists($file_path)){
    $original_url = get_template_directory_uri() . '/assets/img/' . $name;
  }
  if(file_exists($file_path_webp)){
    $webp_url = get_template_directory_uri() . '/assets/img/' . $file_name . '.webp';
  }

  return '<picture>
  '.($webp_url ? '<source srcset="'.$webp_url.'" type="image/webp">' : '').'
  '.($original_url ? '<source srcset="'.$original_url.'" type="'.$file_type.'"> ' : '').'
  '.($original_url ? '<img resources="'.$original_url.'" '.$file_size[3].'>' : '').'
  </picture>';
}