<?php

declare(strict_types=1);

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

use ReallySimplePlugins\RSS\Core\Features\Vulnerability\Dtos\VulnerabilitySnapshotDto;
use ReallySimplePlugins\RSS\Core\Features\Vulnerability\Repositories\VulnerabilityStorageRepository;
use ReallySimplePlugins\RSS\Core\Support\Helpers\Storages\EnvironmentConfig;
use ReallySimplePlugins\RSS\Core\Support\Helpers\Storages\UriConfig;
use ReallySimplePlugins\RSS\Core\Services\EmailService;

/**
 * Builds and sends vulnerability notification emails using the legacy RSSSL mailer.
 *
 * Responsibilities:
 * - Shapes the email content (subject/title/message + per-severity blocks).
 * - Reads vulnerability aggregates from the storage repository.
 *
 * Delivery is delegated to {@see EmailService} which lazy-loads the legacy mailer
 * and provides common helpers (site URL, admin URLs, recipient handling).
 *
 * This service intentionally does not perform scanning or persistence.
 */
final class VulnerabilityEmailService extends EmailService
{
    private VulnerabilityStorageRepository $vulnerabilityStorageRepository;

    /**
     * Constructs the VulnerabilityEmailService.
     *
     * We extend EmailService to reuse legacy mailer initialization and common helpers.
     * Injected dependencies include environment and URI configs plus the vulnerability storage repository.
     */
    public function __construct(
        EnvironmentConfig $environmentConfig,
        UriConfig $uriConfig,
        VulnerabilityStorageRepository $vulnerabilityStorageRepository
    ) {
        parent::__construct($environmentConfig, $uriConfig);
        $this->vulnerabilityStorageRepository = $vulnerabilityStorageRepository;
    }

    /**
     * Sends the vulnerability summary notification email.
     *
     * This composes an email similar to the legacy `send_vulnerability_mail()` flow:
     * - Uses the provided snapshot for overall counts (e.g. total vulnerable components).
     * - Uses the storage repository for severity breakdown (used to build blocks).
     *
     * The legacy mailer expects specific public properties to be set (subject/title/message,
     * button text, and `warning_blocks`). After composition we call `send_mail()`.
     *
     * @return array{success: bool, title?: string, message?: string}
     */
    public function sendVulnerabilityNotification(
        VulnerabilitySnapshotDto $vulnerabilitySnapshotDto
    ): array {
        $total = $vulnerabilitySnapshotDto->getVulnerableCount();
        $blocks = [];
        $rssslmailer = $this->getMailer();

        $rssslmailer->subject = sprintf(
            /* translators: %s is the site url */
            __('Vulnerability Alert: %s', 'really-simple-ssl'),
            $this->siteUrl()
        );

        $rssslmailer->title = sprintf(
            _n(
                '%s: %s vulnerability found',
                '%s: %s vulnerabilities found',
                $total,
                'really-simple-ssl'
            ),
            $this->date(),
            $total
        );

        $rssslmailer->message = sprintf(
            /* translators: %s is a clickable domain */
            __('This is a vulnerability alert from Really Simple Security for %s.', 'really-simple-ssl'),
            $this->domain()
        );

        $rssslmailer->button_text = __('Learn more', 'really-simple-ssl');

        $vulnerabilityCountBySeverity = $this->vulnerabilityStorageRepository->getComponentCountPerHighestSeverity();
        foreach ($vulnerabilityCountBySeverity as $severity => $count) {
            $blocks[] = $this->createBlock($severity, $count);
        }
        $rssslmailer->warning_blocks = $blocks;

        return $rssslmailer->send_mail();
    }

    /**
     * Creates a "warning block" for a single severity bucket.
     *
     * The legacy mailer renders these blocks in the email body.
     *
     * @return array{title: string, message: string, url: string}
     */
    private function createBlock(string $severity, int $count): array
    {
        $title = $this->getWarningString($severity, $count);

        $riskLabel = strtolower(trim($severity));

        $message = $count === 1
            ? sprintf(
                /* translators: 1: severity label */
                __('A %s vulnerability has been found.', 'really-simple-ssl'),
                $riskLabel
            )
            : sprintf(
                /* translators: 1: severity label */
                __('Multiple %s vulnerabilities have been found.', 'really-simple-ssl'),
                $riskLabel
            );

        $message .= ' ' . __('Based on your settings, Really Simple Security will take appropriate action, or you will need to solve it manually.', 'really-simple-ssl');
        $message .= ' ' . sprintf(
            /* translators: %s is a clickable domain */
            __('Get more information from the Really Simple Security dashboard on %s', 'really-simple-ssl'),
            $this->domain()
        );

        return [
            'title' => $title,
            'message' => $message,
            'url' => $this->getVulnerabilitiesSettingsUrl(),
        ];
    }

    /**
     * Returns a translated, pluralized title line for a severity and count.
     */
    private function getWarningString(string $severity, int $count): string
    {
        switch (strtolower(trim($severity))) {
            case 'critical':
                return sprintf(
                    _n('You have %s critical-risk vulnerability', 'You have %s critical-risk vulnerabilities', $count, 'really-simple-ssl'),
                    $count
                );
            case 'high':
                return sprintf(
                    _n('You have %s high-risk vulnerability', 'You have %s high-risk vulnerabilities', $count, 'really-simple-ssl'),
                    $count
                );
            case 'medium':
                return sprintf(
                    _n('You have %s medium-risk vulnerability', 'You have %s medium-risk vulnerabilities', $count, 'really-simple-ssl'),
                    $count
                );
            case 'low':
            default:
                return sprintf(
                    _n('You have %s low-risk vulnerability', 'You have %s low-risk vulnerabilities', $count, 'really-simple-ssl'),
                    $count
                );
        }
    }

    private function date(): string
    {
        return (string) date_i18n(get_option('date_format'));
    }

    /**
     * Returns an HTML anchor tag with the site URL, used by the legacy mailer.
     */
    private function domain(): string
    {
        $url = $this->siteUrl();

        return '<a href="' . esc_url($url) . '" target="_blank" rel="noopener noreferrer">' . esc_html($url) . '</a>';
    }

    private function siteUrl(): string
    {
        $scheme = (function_exists('is_ssl') && is_ssl()) ? 'https' : 'http';
        return (string) get_site_url(null, '', $scheme);
    }

    /**
     * Returns the admin settings URL (hash route) used in email buttons/blocks.
     */
    public function getVulnerabilitiesSettingsUrl(): string
    {
        if (function_exists('rsssl_admin_url')) {
            return (string) rsssl_admin_url([], '#settings/vulnerabilities');
        }

        return (string) admin_url('admin.php?page=really-simple-security#settings/vulnerabilities');
    }

    /**
     * Sends a generic test email via the legacy mailer.
     *
     * Used for diagnostics, delegates to the legacy mailer's test method.
     */
    public function sendTestEmail(): array
    {
        return $this->getMailer()->send_test_mail();
    }
}
