<?php

namespace RtmMail\Actions\Handlers;

/**
 * Handles the action for looking up DomainKeys Identified Mail (DKIM) records.
 */
class DkimLookupAction extends AbstractActionHandler
{
    /**
     * Initializes the action with specific action types.
     */
    public function __construct()
    {
        parent::__construct('test_dkim_settings', 'rtm_mail_test_dkim');
    }

    /**
     * Handles the DKIM lookup action.
     *
     * @param string $dkimSelector The DKIM selector used for locating the DKIM record.
     *
     * @return array Result of the DKIM record lookup.
     */
    public function handleAction($dkimSelector = ""): array
    {
        // Verify the nonce before proceeding with the action to enhance security.
        if (! $this->verifyNonce()) {
            return [
                'success' => false,
                'message' => __('Invalid nonce!', 'plugin-domain')
            ];
        }

        // Retrieve SMTP settings from the database.
        $settings = get_option('rtm_mail_smtp_settings');
        if (empty($settings) || ! isset($settings['smtp_settings']['other'])) {
            return [ 'success' => false, 'message' => 'SMTP settings are incomplete.' ];
        }

        $smtp = $settings['smtp_settings']['other'];
        if (! isset($smtp['other_smtp_host'])) {
            return [ 'success' => false, 'message' => 'SMTP host is not set.' ];
        }

        // Extract the domain name from the SMTP host for DKIM verification.
        $domain = $this->extractDomainFromHost($smtp['other_smtp_host']);

        // Sanitize and clean the DKIM selector to ensure it is in the correct format.
        $cleanedSelector = $this->cleanSelector($dkimSelector);

        // Perform the DKIM record check using the cleaned selector and extracted domain.
        $dkimCheckResult = $this->checkDkim($domain, $cleanedSelector);

        // Return the result of the DKIM check.
        return $dkimCheckResult;
    }

    /**
     * Cleans the provided DKIM selector to remove unnecessary characters.
     *
     * @param string $selector The original selector.
     *
     * @return string The cleaned selector.
     */
    private function cleanSelector($selector)
    {
        if (preg_match('/\(([^)]+)\)/', $selector, $matches)) {
            return $matches[1];
        }

        return $selector;
    }

    /**
     * Extracts the domain part from the given host address.
     *
     * @param string $host The full host address.
     *
     * @return string The domain part of the host.
     */
    private function extractDomainFromHost($host)
    {
        return join('.', array_slice(explode('.', $host), - 2));
    }

    /**
     * Validates the format of a DKIM record.
     *
     * @param string $record The DKIM record string.
     *
     * @return bool True if the record is valid, false otherwise.
     */
    private function validateDkimRecord($record)
    {
        // Check for the presence of essential DKIM record components.
        if (strpos($record, 'v=DKIM1;') !== false && strpos($record, 'p=') !== false) {
            return true;
        }

        return false;
    }

    /**
     * Performs the DKIM check by querying DNS for TXT records.
     *
     * @param string $domain The domain to check.
     * @param string $selector The DKIM selector.
     *
     * @return array The result of the DKIM check, including success status and message.
     */
    private function checkDkim($domain, $selector)
    {
        // Construct the full selector to query DNS.
        $fullSelector = $selector . '._domainkey.' . $domain;
        $records      = dns_get_record($fullSelector, DNS_TXT);

        // Handle cases where no DNS records are found.
        if (! $records) {
            return [
                'success'    => false,
                'message'    => 'No DKIM record found for the provided selector.',
                'dkimRecord' => null
            ];
        }

        // Validate each DKIM record found in the DNS query.
        $validRecords = [];
        foreach ($records as $record) {
            if (isset($record['txt']) && $this->validateDkimRecord($record['txt'])) {
                $validRecords[] = $record['txt'];  // Collect valid records
            }
        }

        // Return results based on the validation of found records.
        if (! empty($validRecords)) {
            return [
                'success'    => true,
                'message'    => "Valid DKIM record(s) found for selector: '$selector', Domain: '$domain'.",
                'dkimRecord' => $validRecords
            ];
        }

        return [
            'success'    => false,
            'message'    => 'DKIM records found but none are valid.',
            'dkimRecord' => $records[0]['txt']
        ];
    }
}
