<?php

declare(strict_types=1);

namespace PpPhp\Core;

/**
 * Tracks who installed each plugin, so developers can manage their own plugins
 * without being able to touch anyone else's.
 *
 * Plugins themselves are plain folders under `plugins/{Category}/{Name}`, so
 * ownership is recorded alongside them in a small central registry rather than
 * inside the plugin folder — that keeps plugin directories clean and portable
 * (re-zipping a plugin never carries ownership with it).
 *
 * Rules:
 *   • superadmin — may manage every plugin.
 *   • developer  — may install, and manage only the plugins they installed.
 *   • anyone else — no access.
 *
 * Plugins that pre-date this registry have no recorded owner and are therefore
 * superadmin-only, which is the safe default.
 */
class PluginOwnership
{
    private static function file(): string
    {
        return constant('BASE_PATH') . '/storage/plugins/owners.json';
    }

    private static function key(string $category, string $name): string
    {
        return $category . '/' . $name;
    }

    /** @return array<string,array{owner:int,username:string,at:int}> */
    public static function all(): array
    {
        $file = self::file();
        if (!is_file($file)) {
            return [];
        }
        $data = json_decode((string) file_get_contents($file), true);
        return is_array($data) ? $data : [];
    }

    private static function save(array $map): void
    {
        $file = self::file();
        $dir  = dirname($file);
        if (!is_dir($dir)) {
            mkdir($dir, 0755, true);
        }
        file_put_contents($file, json_encode($map, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
    }

    /** Record the installer of a plugin. */
    public static function claim(string $category, string $name, int $userId, string $username): void
    {
        $map = self::all();
        $map[self::key($category, $name)] = ['owner' => $userId, 'username' => $username, 'at' => time()];
        self::save($map);
    }

    /** Forget a plugin (called after it is deleted). */
    public static function release(string $category, string $name): void
    {
        $map = self::all();
        unset($map[self::key($category, $name)]);
        self::save($map);
    }

    /** @return array{owner:int,username:string,at:int}|null */
    public static function ownerOf(string $category, string $name): ?array
    {
        return self::all()[self::key($category, $name)] ?? null;
    }

    /** Central store of owner core/custom overrides — kept OUTSIDE plugin folders so it survives updates/re-zips (like ownership). */
    private static function coreFlagsFile(): string
    {
        return constant('BASE_PATH') . '/storage/plugins/core-flags.json';
    }

    /** @return array<string,string> key => 'core'|'custom' */
    private static function coreFlags(): array
    {
        $file = self::coreFlagsFile();
        if (!is_file($file)) {
            return [];
        }
        $data = json_decode((string) file_get_contents($file), true);
        return is_array($data) ? $data : [];
    }

    /**
     * A "core" plugin is the platform owner's exclusive domain. Resolution:
     *   1. the owner's explicit core/custom override (central core-flags.json),
     *   2. a legacy `.core` marker file,
     *   3. default: a built-in/system plugin (no recorded installer) is core.
     */
    public static function isCore(string $category, string $name): bool
    {
        $flags = self::coreFlags();
        $key = self::key($category, $name);
        if (isset($flags[$key])) {
            return $flags[$key] === 'core';
        }
        if (is_file(constant('BASE_PATH') . '/plugins/' . $category . '/' . $name . '/.core')) {
            return true;
        }
        return self::ownerOf($category, $name) === null;
    }

    /** Owner-only: explicitly mark a plugin core (true) or custom (false). */
    public static function setCore(string $category, string $name, bool $core): bool
    {
        if (!Security::IsOwner()) {
            return false;
        }
        $flags = self::coreFlags();
        $flags[self::key($category, $name)] = $core ? 'core' : 'custom';
        $file = self::coreFlagsFile();
        $dir = dirname($file);
        if (!is_dir($dir)) {
            mkdir($dir, 0755, true);
        }
        file_put_contents($file, json_encode($flags, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
        return true;
    }

    /** True when the current user may delete/enable/disable/update this plugin. */
    public static function canManage(string $category, string $name): bool
    {
        // Core/system plugins → owner only (superadmins cannot touch them).
        if (self::isCore($category, $name)) {
            return Security::IsOwner();
        }
        if (Security::IsAdmin()) {
            return true;
        }
        if (Security::CurrentUserGroup() !== 'developer') {
            return false;
        }
        $owner = self::ownerOf($category, $name);
        $me    = (int) (Security::CurrentUserData()['id'] ?? 0);
        return $owner !== null && $me > 0 && (int) $owner['owner'] === $me;
    }

    /** A short label for the UI: who installed this plugin. */
    public static function ownerLabel(string $category, string $name): string
    {
        $owner = self::ownerOf($category, $name);
        if ($owner === null) {
            return 'System';
        }
        return (string) ($owner['username'] ?? 'Unknown');
    }
}
