<?php
declare(strict_types=1);

namespace PpPhp\Core\Assets;

use PpPhp\Core\Resources\ResourceRegistry;

final class AssetRuntime
{
    public function resources(): array
    {
        ResourceRegistry::reset();

        $resources = [];
        foreach (ResourceRegistry::all() as $type => $packs) {
            foreach ($packs as $id => $pack) {
                $resources[$type][$id] = AssetResourcePackage::fromResource($pack);
            }
        }

        return $resources;
    }

    public function packages(?string $type = null): array
    {
        $rows = [];
        foreach ($this->resources() as $resourceType => $packs) {
            if ($type !== null && $resourceType !== strtolower($type)) {
                continue;
            }
            foreach ($packs as $pack) {
                $rows[] = $pack;
            }
        }

        return $rows;
    }

    public function registerAllIntoAssetRegistry(): int
    {
        $count = 0;
        foreach ($this->packages() as $package) {
            AssetRegistry::register($package->toAssetPackage());
            $count++;
        }

        return $count;
    }

    public function enable(string $packageId): bool
    {
        $this->registerAllIntoAssetRegistry();

        if (!AssetRegistry::has($packageId)) {
            return false;
        }

        AssetRegistry::enable($packageId);
        return true;
    }

    public function manifest(array $packageIds = [], string $manifestId = 'designer_assets'): array
    {
        $this->registerAllIntoAssetRegistry();

        if ($packageIds === []) {
            $packageIds = array_keys(AssetRegistry::packages());
        }

        $assets = [];
        $packages = [];

        foreach ($packageIds as $packageId) {
            $package = AssetRegistry::get($packageId);
            if (!$package) {
                continue;
            }

            $packages[] = [
                'id' => $package->id,
                'label' => $package->label,
                'version' => $package->version,
                'dependencies' => $package->dependencies,
            ];

            foreach ($package->assets->all() as $asset) {
                $assets[$asset->key()] = $asset->toArray();
            }
        }

        return AssetManifest::create($manifestId, $packages, array_values($assets), [
            'generatedAt' => date('c'),
            'packageIds' => $packageIds,
        ])->toArray();
    }

    public function renderPackageHead(array $packageIds, string $baseUrl = ''): string
    {
        $html = [];
        foreach ($this->manifest($packageIds)['assets'] as $asset) {
            if (($asset['location'] ?? '') !== 'head') {
                continue;
            }
            if (($asset['type'] ?? '') === 'css') {
                $html[] = '<link rel="stylesheet" href="' . htmlspecialchars($this->assetUrl($baseUrl, (string) $asset['path']), ENT_QUOTES, 'UTF-8') . '">';
            }
        }

        return implode(PHP_EOL, array_values(array_unique($html)));
    }

    public function renderPackageFooter(array $packageIds, string $baseUrl = ''): string
    {
        $html = [];
        foreach ($this->manifest($packageIds)['assets'] as $asset) {
            if (($asset['location'] ?? '') !== 'footer') {
                continue;
            }
            if (in_array(($asset['type'] ?? ''), ['js', 'vendor'], true)) {
                $html[] = '<script src="' . htmlspecialchars($this->assetUrl($baseUrl, (string) $asset['path']), ENT_QUOTES, 'UTF-8') . '"></script>';
            }
        }

        return implode(PHP_EOL, array_values(array_unique($html)));
    }

    public function packageForGeneratedApp(array $packageIds, string $appId = 'generated_app'): array
    {
        $manifest = $this->manifest($packageIds, $appId . '_assets');

        return [
            'appId' => $appId,
            'manifest' => $manifest,
            'head' => $this->renderPackageHead($packageIds),
            'footer' => $this->renderPackageFooter($packageIds),
            'copyPlan' => array_map(static fn (array $asset): array => [
                'source' => $asset['path'],
                'target' => 'public/assets/' . ltrim((string) $asset['path'], '/'),
                'type' => $asset['type'],
            ], $manifest['assets']),
        ];
    }

    public function stats(): array
    {
        $packages = $this->packages();
        $manifest = $this->manifest();

        $byType = [];
        foreach ($packages as $package) {
            $byType[$package->type()] = ($byType[$package->type()] ?? 0) + 1;
        }

        return [
            'packages' => count($packages),
            'resourceTypes' => count($byType),
            'byType' => $byType,
            'assets' => $manifest['summary']['assets'] ?? 0,
            'css' => $manifest['summary']['css'] ?? 0,
            'js' => $manifest['summary']['js'] ?? 0,
            'fonts' => $manifest['summary']['fonts'] ?? 0,
            'images' => $manifest['summary']['images'] ?? 0,
        ];
    }

    private function assetUrl(string $baseUrl, string $path): string
    {
        if (preg_match('/^https?:\/\//i', $path)) {
            return $path;
        }

        return rtrim($baseUrl, '/') . '/' . ltrim($path, '/');
    }
}
