<?php

declare(strict_types=1);

namespace PpPhp\Core\Projects;

/** Stores and removes template packages outside editable project directories. */
final class ProjectTemplateService
{
    public function __construct(private ?string $storageRoot = null)
    {
        $this->storageRoot ??= (defined('BASE_PATH') ? constant('BASE_PATH') : getcwd()) . '/storage/project-templates';
    }

    public function save(int $ownerId, array $project, string $projectDir, array $connection, array $input): array
    {
        $slug = ProjectPackageFormat::safeSlug((string)$input['slug']);
        $export = (new ProjectPackageExporter())->export($project, $projectDir, $connection, [
            'include_custom' => $this->toBool($input['include_custom'] ?? true), 'include_sqlite' => false,
        ]);
        $ownerDir = rtrim((string)$this->storageRoot, '/') . '/' . $ownerId;
        if (!is_dir($ownerDir) && !mkdir($ownerDir, 0700, true) && !is_dir($ownerDir)) {
            @unlink($export['path']); throw new \RuntimeException('Could not prepare protected template storage.');
        }
        $destination = $ownerDir . '/' . $slug . '-' . bin2hex(random_bytes(6)) . '.ppphp';
        if (!rename($export['path'], $destination)) {
            @unlink($export['path']); throw new \RuntimeException('Could not move the template package into protected storage.');
        }
        @chmod($destination, 0600);
        return ['path' => $destination, 'manifest' => $export['manifest'], 'size' => $export['size']];
    }

    public function deletePackage(array $template): void
    {
        $path = (string)($template['package_path'] ?? '');
        $root = realpath((string)$this->storageRoot);
        $resolved = $path !== '' ? realpath($path) : false;
        if ($root !== false && $resolved !== false && str_starts_with($resolved, rtrim($root, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR) && is_file($resolved)) {
            if (!unlink($resolved)) throw new \RuntimeException('Could not remove the stored template package.');
        }
    }

    private function toBool(mixed $value): bool
    {
        return is_bool($value) ? $value : in_array(strtolower(trim((string)$value)), ['1', 'true', 'yes', 'on'], true);
    }
}
