<?php

declare(strict_types=1);

/**
 * 本文件属于 DBErp 进销存系统。
 *
 * 版权所有 © 2026 北京珑大钜商科技有限公司。保留所有权利。
 *
 * 未经官方授权，不得删除、篡改或隐藏本文件中的版权声明、产品标识与来源信息。
 * 商业授权、官方更新与技术支持服务，请以珑大官方支持中心记录为准。
 *
 * @link https://support.loongdom.cn
 * @see  https://www.dberp.com.cn
 */

namespace App\Services\Plugin;

use App\Models\CorePlugin;
use DBCore\Plugin\Contracts\PluginRepositoryInterface;
use DBCore\Plugin\Data\PluginState;
use DBCore\Plugin\Enums\PluginStatus;
use Illuminate\Support\Facades\Schema;
use Throwable;

/**
 * 基于 core_plugins 表的插件状态仓储（DBErp 宿主实现）。
 */
final class DberpDatabasePluginRepository implements PluginRepositoryInterface
{
    /**
     * @return array<string, PluginState>
     */
    public function all(): array
    {
        if (! $this->tableReady()) {
            return [];
        }

        $states = [];

        foreach (CorePlugin::query()->orderBy('identifier')->cursor() as $record) {
            $state = $this->recordToState($record);

            if ($state !== null) {
                $states[$state->getName()] = $state;
            }
        }

        return $states;
    }

    public function find(string $plugin): ?PluginState
    {
        if (! $this->tableReady()) {
            return null;
        }

        $record = CorePlugin::query()->where('identifier', $plugin)->first();

        if ($record === null) {
            return null;
        }

        return $this->recordToState($record);
    }

    public function save(PluginState $state): PluginState
    {
        if (! $this->tableReady()) {
            return $state;
        }

        $identifier = trim($state->getName());

        if ($identifier === '') {
            return $state;
        }

        $meta = $this->buildMetaPayload($state);
        $displayName = $this->resolveDisplayName($identifier, $meta);

        CorePlugin::query()->updateOrCreate(
            ['identifier' => $identifier],
            [
                'name' => $displayName,
                'version' => $state->getVersion(),
                'status' => $state->getStatus(),
                'meta' => $meta,
            ],
        );

        return $state;
    }

    public function delete(string $plugin): bool
    {
        if (! $this->tableReady()) {
            return false;
        }

        return CorePlugin::query()->where('identifier', $plugin)->delete() > 0;
    }

    /**
     * @return list<string>
     */
    public function enabledIdentifiers(): array
    {
        if (! $this->tableReady()) {
            return [];
        }

        return CorePlugin::query()
            ->where('status', PluginStatus::Enabled->value)
            ->orderBy('identifier')
            ->pluck('identifier')
            ->map(static fn (mixed $identifier): string => trim((string) $identifier))
            ->filter(static fn (string $identifier): bool => $identifier !== '')
            ->values()
            ->all();
    }

    private function tableReady(): bool
    {
        try {
            return Schema::hasTable('core_plugins');
        } catch (Throwable) {
            return false;
        }
    }

    private function recordToState(CorePlugin $record): ?PluginState
    {
        $identifier = trim((string) $record->identifier);

        if ($identifier === '') {
            return null;
        }

        /** @var array<string, mixed> $meta */
        $meta = is_array($record->meta) ? $record->meta : [];

        /** @var array<string, mixed> $extra */
        $extra = is_array($meta['extra'] ?? null) ? $meta['extra'] : [];

        return new PluginState(
            name: $identifier,
            status: (string) ($record->status ?: PluginStatus::Installed->value),
            version: $record->version !== null ? (string) $record->version : null,
            installedAt: isset($meta['installed_at']) ? (string) $meta['installed_at'] : null,
            enabledAt: isset($meta['enabled_at']) ? (string) $meta['enabled_at'] : null,
            extra: $extra,
        );
    }

    /**
     * @return array<string, mixed>
     */
    private function buildMetaPayload(PluginState $state): array
    {
        return array_filter([
            'display_name' => $state->getExtra()['display_name'] ?? null,
            'installed_at' => $state->getInstalledAt(),
            'enabled_at' => $state->getEnabledAt(),
            'extra' => $state->getExtra() !== [] ? $state->getExtra() : null,
        ], static fn (mixed $value): bool => $value !== null && $value !== []);
    }

    /**
     * @param  array<string, mixed>  $meta
     */
    private function resolveDisplayName(string $identifier, array $meta): string
    {
        $displayName = trim((string) ($meta['display_name'] ?? ''));

        return $displayName !== '' ? $displayName : $identifier;
    }
}
