<?php

declare(strict_types=1);

namespace ReallySimplePlugins\RSS\Core\Features\Vulnerability\Services\Strategies;

use ReallySimplePlugins\RSS\Core\Features\Vulnerability\Dtos\ComponentVulnerabilitiesDto;
use ReallySimplePlugins\RSS\Core\Features\Vulnerability\Dtos\InstalledComponentDto;
use ReallySimplePlugins\RSS\Core\Features\Vulnerability\Interfaces\ComponentSyncStrategyInterface;

/**
 * Abstract base for component sync *Strategies*.
 *
 * This class provides shared mechanics for concrete sync strategies (plugin, theme, core),
 * such as validation, API delegation, and DTO mapping.
 *
 * Strategy context:
 * - Defines *how* vulnerability data is synchronized for a component type.
 * - Concrete subclasses are interchangeable and selected by an orchestrator.
 *
 * Not a Policy:
 * - This class does not decide *whether* or *when* a sync should run.
 * - It does not apply severity thresholds or notification rules.
 * - Those concerns belong to policies and higher-level scheduling/orchestration.
 *
 * Responsibilities:
 * - Validate installed component identifiers
 * - Delegate component-specific API fetching
 * - Map API payloads into ComponentVulnerabilitiesDto
 */
abstract class AbstractComponentSyncStrategy implements ComponentSyncStrategyInterface
{
    /**
     * {@inheritDoc}
     */
    public function fetchComponent(InstalledComponentDto $installedComponentDto): array
    {
        $slug = $installedComponentDto->getSlug();
        $name = $installedComponentDto->getName();
        $version = $installedComponentDto->getInstalledVersion();

        if ($slug === '') {
            return [
                'success' => false,
                'message' => sprintf('Missing %s slug for installed component.', $this->getType()),
            ];
        }

        return $this->fetchFromApi($slug, $name, $version);
    }

    /**
     * {@inheritDoc}
     */
    public function toComponentDto(array $apiPayload, InstalledComponentDto $installedComponentDto): ComponentVulnerabilitiesDto
    {
        $installedSlug = $installedComponentDto->getSlug();
        $installedName = $installedComponentDto->getName();
        $installedVersion = $installedComponentDto->getInstalledVersion();

        $dto = ComponentVulnerabilitiesDto::FromApiComponentArray($apiPayload);

        $dto->setType($this->getType());
        $dto->setSlug($installedSlug);
        $dto->setName($installedName);
        $dto->setInstalledVersion($installedVersion);

        $latestRaw = $apiPayload['latestVersion'] ?? $apiPayload['latest_version'] ?? null;
        $latestVersion = is_string($latestRaw) ? $latestRaw : '';

        $dto->setLatestVersion($latestVersion !== '' ? $latestVersion : null);
        $dto->setUpdateAvailable(
            $latestVersion !== '' && $installedVersion !== '' && version_compare($installedVersion, $latestVersion, '<')
        );

        return $dto;
    }

    /**
     * Perform the component-specific API fetch.
     *
     * Implementations must return the standardized client response shape.
     *
     * @param string $slug The name of the component slug.
     * @param string $name The name of the component.
     * @param string $version The installed version of the component. Only used by core.
     *
     * @return array{success: bool, data?: array<string, mixed>, message?: string}
     */
    abstract protected function fetchFromApi(string $slug, string $name, string $version = ''): array;
}
