<?php

namespace App\Http\Requests\Site;

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Http;
use Illuminate\Validation\Validator;

class ContactSubmissionRequest extends FormRequest
{
    public function authorize(): bool
    {
        return true;
    }

    public function rules(): array
    {
        $turnstileEnabled = (bool) config('hillcrest.turnstile.enabled')
            && filled(config('hillcrest.turnstile.site_key'))
            && filled(config('hillcrest.turnstile.secret_key'));

        return [
            'name' => ['required', 'string', 'max:255'],
            'email' => ['required', 'email:rfc,dns', 'max:255'],
            'phone' => ['nullable', 'string', 'max:50'],
            'subject' => ['required', 'string', 'max:255'],
            'enquiry_type' => ['required', 'string', 'in:general,services,referral,partnership,careers,other'],
            'preferred_contact' => ['nullable', 'string', 'in:email,phone,either'],
            'message' => ['required', 'string', 'min:20', 'max:3000'],
            'cf-turnstile-response' => $turnstileEnabled ? ['required', 'string'] : ['nullable', 'string'],
        ];
    }

    protected function prepareForValidation(): void
    {
        $clean = static function (?string $value, bool $preserveNewlines = false): ?string {
            if ($value === null) {
                return null;
            }

            $value = strip_tags($value);
            $value = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/u', '', $value ?? '');
            $value = $preserveNewlines
                ? preg_replace('/[ \t]+/u', ' ', $value ?? '')
                : preg_replace('/\s+/u', ' ', $value ?? '');

            return trim((string) $value);
        };

        $this->merge([
            'name' => $clean($this->input('name')),
            'email' => strtolower((string) $clean($this->input('email'))),
            'phone' => $clean($this->input('phone')),
            'subject' => $clean($this->input('subject')),
            'enquiry_type' => $clean($this->input('enquiry_type')),
            'preferred_contact' => $clean($this->input('preferred_contact')),
            'message' => $clean($this->input('message'), preserveNewlines: true),
        ]);
    }

    public function withValidator(Validator $validator): void
    {
        $validator->after(function (Validator $validator): void {
            $message = strtolower((string) $this->input('message', ''));
            $subject = (string) $this->input('subject', '');
            $name = (string) $this->input('name', '');
            $email = strtolower((string) $this->input('email', ''));
            $combinedText = strtolower(trim($subject.' '.$message));

            preg_match_all('/https?:\/\/|www\./i', $message, $matches);
            $urlMentions = count($matches[0] ?? []);

            if ($urlMentions > 1) {
                $validator->errors()->add('message', 'Please remove excessive links from your message.');
            }

            if (preg_match('/(.)\\1{6,}/', $message)) {
                $validator->errors()->add('message', 'Please enter a valid enquiry message.');
            }

            // Basic header/script injection guards.
            if (preg_match('/(?:\r|\n|%0a|%0d|bcc:|cc:|content-type:)/i', $subject.' '.$name)) {
                $validator->errors()->add('subject', 'Your input contains invalid characters.');
            }

            if (preg_match('/<\s*script|javascript:|onerror\s*=|onload\s*=/i', $message)) {
                $validator->errors()->add('message', 'Your message contains unsafe content.');
            }

            $this->applyBlocklistChecks($validator, $email, $combinedText);
            $this->applySuspiciousScoring($validator, $combinedText, $urlMentions);
            $this->validateTurnstile($validator);
        });
    }

    private function applyBlocklistChecks(Validator $validator, string $email, string $combinedText): void
    {
        $blockedKeywords = array_map('strtolower', (array) config('hillcrest.contact_spam.blocked_keywords', []));

        foreach ($blockedKeywords as $blockedKeyword) {
            if ($blockedKeyword !== '' && str_contains($combinedText, $blockedKeyword)) {
                $validator->errors()->add('message', 'Your message has been blocked by our spam filter.');
                break;
            }
        }

        $blockedDomains = array_map('strtolower', (array) config('hillcrest.contact_spam.blocked_email_domains', []));
        if ($email !== '' && str_contains($email, '@')) {
            $domain = substr($email, (int) strrpos($email, '@') + 1);
            if (in_array($domain, $blockedDomains, true)) {
                $validator->errors()->add('email', 'Please use a valid business or personal email address.');
            }
        }
    }

    private function applySuspiciousScoring(Validator $validator, string $combinedText, int $urlMentions): void
    {
        $score = 0;
        $weightedKeywords = (array) config('hillcrest.contact_spam.weighted_keywords', []);

        foreach ($weightedKeywords as $keyword => $weight) {
            if (is_string($keyword) && $keyword !== '' && str_contains($combinedText, strtolower($keyword))) {
                $score += max(0, (int) $weight);
            }
        }

        if ($urlMentions > 0) {
            $score += min(3, $urlMentions);
        }

        $threshold = (int) config('hillcrest.contact_spam.score_threshold', 4);
        if ($score >= $threshold) {
            $validator->errors()->add('message', 'Your submission looks suspicious. Please revise the message and try again.');
        }
    }

    private function validateTurnstile(Validator $validator): void
    {
        $enabled = (bool) config('hillcrest.turnstile.enabled');
        $siteKey = (string) config('hillcrest.turnstile.site_key');
        $secretKey = (string) config('hillcrest.turnstile.secret_key');

        if (! $enabled || $siteKey === '' || $secretKey === '') {
            return;
        }

        $token = (string) $this->input('cf-turnstile-response', '');
        if ($token === '') {
            $validator->errors()->add('cf-turnstile-response', 'Please complete the verification check.');
            return;
        }

        $endpoint = (string) config('hillcrest.turnstile.verify_endpoint', 'https://challenges.cloudflare.com/turnstile/v0/siteverify');
        $timeoutSeconds = (int) config('hillcrest.turnstile.timeout_seconds', 4);
        $failOpen = (bool) config('hillcrest.turnstile.fail_open', true);

        try {
            $response = Http::asForm()
                ->timeout(max(2, $timeoutSeconds))
                ->post($endpoint, [
                    'secret' => $secretKey,
                    'response' => $token,
                    'remoteip' => (string) $this->ip(),
                ]);

            $ok = (bool) data_get($response->json(), 'success', false);
            if (! $ok) {
                $validator->errors()->add('cf-turnstile-response', 'Verification failed. Please try again.');
            }
        } catch (\Throwable $exception) {
            if (! $failOpen) {
                $validator->errors()->add('cf-turnstile-response', 'Verification service is unavailable. Please try again shortly.');
            }
        }
    }
}
