<?php

namespace CleantalkSP\SpbctWP;

use CleantalkSP\Common\EarlyTranslation;
use CleantalkSP\SpbctWP\Helpers\Arr;
use CleantalkSP\Variables\Server;

/**
 * Class SpbcEarlyTranslation
 *
 * Security Plugin by CleanTalk specific implementation of CleanTalkL10n.
 * Handles translation tracking and error logging with WordPress options storage.
 *
 * == HOW TO ADD NEW TRANSLATION STRINGS IN CHILD CLASS
 *
 *    1. Add the raw constant to the list:
 *       const __KEY_VALIDATION__FAILED_COMMON = 'Access Key validation failed:';
 *
 *   2. Add the translation call to getWPTranslatePairs():
 *      return [
 *       self::__KEY_VALIDATION__FAILED_COMMON => __('Access Key validation failed:', 'security-malware-firewall'),
 *      ];
 *
 *   3. Add the string to the registry - getRawStringRegistryKeys:
 *       return [
 *           self::__KEY_VALIDATION__FAILED_COMMON,
 *       ];
 *
 *   4. Use in code:
 *      echo __spbc(EarlyTranslation::__KEY_VALIDATION__FAILED_COMMON);
 *
 *   The checkWPTranslationReady() method will validate consistency on the 'init' hook.
 *
 * == HOW TO DEBUG
 *
 *   1. Set the error tracking level to 2 (2 = errors and untranslated strings), then check the error_log.
 *   2. Also, saving the untranslated strings has to be implemented via the abstract method 'saveErrors'\
 *   3. The 'getStats' method can be used to check the current tracking level and errors.
 *
 * @package CleantalkSP\SpbctWP
 */
class SpbcEarlyTranslation extends EarlyTranslation
{
    public $text_domain = 'security-malware-firewall';
    /**
     * Maximum number of untranslated strings to keep in storage
     *
     * @var int
     */
    const UNTRANSLATED_SAVE_LIMIT = 10;

    /**
     * Maximum number of translation errors to keep in storage
     *
     * @var int
     */
    const TRANSLATION_ERROR_SAVE_LIMIT = 2;

    /**
     * WordPress option name for storing translation errors
     *
     * @var string
     */
    const OPTION_NAME = 'spbc_translation_errors';


    /**
     * Expected translation keys for translation registry, these phrases are RAW text, not translated.
     */

    const __KEY_VALIDATION__FAILED_COMMON = 'Access Key validation failed:';
    const __KEY_VALIDATION__KEY_FORMAT_IS_INVALID = 'Access Key format is invalid';
    const __KEY_VALIDATION__API_RESPONSE__ERROR_OCCURRED = 'API error occurred';
    const __KEY_VALIDATION__API_RESPONSE__KEY_IS_INVALID = 'API response - the Access Key is not valid.';
    const __KEY_VALIDATION__API_RESPONSE__LICENSE_INACTIVE = 'API response - the license is inactive';

    /**
     * @inheritDoc
     */
    public function getWPTranslatePairs(): array
    {
        return [ //be sure that values to translate via __() are the same as in the translation RAW constants
            self::__KEY_VALIDATION__FAILED_COMMON => __('Access Key validation failed:', 'security-malware-firewall'),
            self::__KEY_VALIDATION__KEY_FORMAT_IS_INVALID => __('Access Key format is invalid', 'security-malware-firewall'),
            self::__KEY_VALIDATION__API_RESPONSE__ERROR_OCCURRED  => __('API error occurred', 'security-malware-firewall'),
            self::__KEY_VALIDATION__API_RESPONSE__KEY_IS_INVALID  => __('API response - the Access Key is not valid.', 'security-malware-firewall'),
            self::__KEY_VALIDATION__API_RESPONSE__LICENSE_INACTIVE  => __('API response - the license is inactive', 'security-malware-firewall'),
        ];
        //todo Make sure that these phrases are appeared in the wptranslate API after next release.
    }

    /**
     * @inheritDoc
     */
    public function getRawStringRegistryKeys(): array
    {
        return [
            self::__KEY_VALIDATION__FAILED_COMMON,
            self::__KEY_VALIDATION__KEY_FORMAT_IS_INVALID,
            self::__KEY_VALIDATION__API_RESPONSE__ERROR_OCCURRED,
            self::__KEY_VALIDATION__API_RESPONSE__KEY_IS_INVALID,
            self::__KEY_VALIDATION__API_RESPONSE__LICENSE_INACTIVE
        ];
    }

    /**
     * Save translation errors to WordPress options
     *
     * Merges with existing errors and applies storage limits.
     *
     * @param array $errors Errors data to save
     *
     * @return void
     */
    public function saveErrors($errors): void
    {
        $errors_old = $this->getErrors();

        // Merge with existing errors preserving numeric keys
        $errors = Arr::mergeWithSavingNumericKeysRecursive($errors_old, $errors);

        // Apply storage limits
        $errors['untranslated'] = $this->clearOld($errors['untranslated'], self::UNTRANSLATED_SAVE_LIMIT);
        $errors['errors'] = $this->clearOld($errors['errors'], self::TRANSLATION_ERROR_SAVE_LIMIT);

        update_option(self::OPTION_NAME, $errors);
    }

    /**
     * Trim array to a specified limit keeping most recent entries
     *
     * @param array $type_array Array to trim
     * @param int   $limit      Maximum number of elements to keep
     *
     * @return array Trimmed array
     */
    private function clearOld($type_array, $limit): array
    {
        if (!is_array($type_array)) {
            $type_array = [];
        }

        if (count($type_array) > $limit) {
            $type_array = array_slice(
                $type_array,
                count($type_array) - $limit,
                $limit
            );
        }

        return $type_array;
    }

    /**
     * Retrieve stored translation errors from WordPress options
     *
     * @return array Errors data or empty array if none exists
     */
    public function getErrors(): array
    {
        $errors = get_option(self::OPTION_NAME);
        return is_array($errors) ? $errors : array();
    }

    /**
     * Determine tracking level based on current domain
     *
     * Returns:
     * - 2 for local/development domains (full tracking)
     * - 0 for production domains (tracking disabled)
     *
     * @return int Tracking level (0 or 2)
     */
    public function setErrorTrackingLevel(): int
    {
        $domain = Server::getDomain();

        if (!is_string($domain)) {
            return 0;
        }

        // Enable full tracking only on local/development domains
        return in_array($domain, ['lc', 'loc', 'local', 'lh', 'wordpress'], true) ? 2 : 0;
    }

    /**
     * Get statistics about translation errors and tracking status
     *
     * @return string JSON encoded statistics
     */
    public function getStats(): string
    {
        $out = [
            'errors' => $this->getErrors(),
            'tracking_level' => $this->error_tracking_level
        ];

        return $this->prepareJson($out);
    }
}
