<?php

namespace App\Http\Controllers\Web;

use App\Http\Controllers\Controller;
use App\Jobs\ProcessLeadCapturedJob;
use App\Models\Lead;
use App\Models\LeadOtpVerification;
use App\Services\LeadActivityService;
use App\Services\Messaging\Fast2SmsService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Validation\ValidationException;

class RegisterLeadController extends Controller
{
    public function show()
    {
        return view('auth.register');
    }

    public function sendOtp(Request $request, Fast2SmsService $smsService): JsonResponse
    {
        $data = $request->validate([
            'mobile' => ['required', 'regex:/^[6-9][0-9]{9}$/'],
        ]);

        $mobile = $this->normalizeMobile($data['mobile']);
        $key = 'lead-otp-send:' . $mobile . ':' . $request->ip();
        Log::info('Lead OTP send requested.', [
            'mobile' => $this->maskMobile($mobile),
            'ip' => $request->ip(),
        ]);
        if (RateLimiter::tooManyAttempts($key, (int) config('lead.otp.resend_limit', 5))) {
            Log::warning('Lead OTP send rate limited.', [
                'mobile' => $this->maskMobile($mobile),
                'ip' => $request->ip(),
            ]);
            return response()->json(['message' => 'Too many OTP requests. Please try again later.'], 429);
        }

        $otp = (string) random_int(100000, 999999);
        $ttl = (int) config('lead.otp.ttl_minutes', 10);

        $verification = LeadOtpVerification::firstOrNew(['mobile' => $mobile]);
        $verification->fill([
            'otp_hash' => Hash::make($otp),
            'expires_at' => now()->addMinutes($ttl),
            'verified_at' => null,
            'verify_attempts' => 0,
            'resend_count' => ((int) $verification->resend_count) + 1,
            'last_sent_at' => now(),
            'ip_address' => $request->ip(),
        ]);
        $verification->save();

        $sent = $smsService->sendOtp($mobile, $otp);
        Log::info('Lead OTP send response.', [
            'mobile' => $this->maskMobile($mobile),
            'sent' => $sent,
            'expires_at' => $verification->expires_at?->toDateTimeString(),
        ]);
        RateLimiter::hit($key, 60);

        if (! $sent) {
            return response()->json([
                'message' => 'OTP request failed. Please check SMS settings and try again.',
            ], 422);
        }

        return response()->json(['message' => 'OTP sent successfully.']);
    }

    public function verifyOtp(Request $request): JsonResponse
    {
        $data = $request->validate([
            'mobile' => ['required', 'regex:/^[6-9][0-9]{9}$/'],
            'otp' => ['required', 'digits:6'],
        ]);

        $mobile = $this->normalizeMobile($data['mobile']);
        Log::info('Lead OTP verify requested.', [
            'mobile' => $this->maskMobile($mobile),
            'ip' => $request->ip(),
        ]);
        $verification = LeadOtpVerification::where('mobile', $mobile)->first();

        if (! $verification || now()->greaterThan($verification->expires_at)) {
            Log::warning('Lead OTP verify failed: expired or missing.', [
                'mobile' => $this->maskMobile($mobile),
            ]);
            return response()->json(['message' => 'OTP expired. Please request a new OTP.'], 422);
        }

        $attemptLimit = (int) config('lead.otp.verify_attempt_limit', 5);
        if ($verification->verify_attempts >= $attemptLimit) {
            Log::warning('Lead OTP verify blocked: max attempts reached.', [
                'mobile' => $this->maskMobile($mobile),
                'attempts' => $verification->verify_attempts,
            ]);
            return response()->json(['message' => 'Maximum OTP attempts reached. Request a new OTP.'], 429);
        }

        if (! Hash::check($data['otp'], $verification->otp_hash)) {
            $verification->increment('verify_attempts');
            Log::warning('Lead OTP verify failed: invalid otp.', [
                'mobile' => $this->maskMobile($mobile),
                'attempts' => $verification->verify_attempts,
            ]);
            return response()->json(['message' => 'Invalid OTP.'], 422);
        }

        $verification->update([
            'verified_at' => now(),
            'verify_attempts' => 0,
        ]);
        Log::info('Lead OTP verify success.', [
            'mobile' => $this->maskMobile($mobile),
            'verified_at' => $verification->verified_at?->toDateTimeString(),
        ]);

        return response()->json(['message' => 'Mobile number verified.']);
    }

    public function store(Request $request, LeadActivityService $activityService)
    {
        $data = $request->validate([
            'company_name' => ['required', 'string', 'max:150'],
            'contact_person_name' => ['required', 'string', 'max:100'],
            'mobile' => ['required', 'regex:/^[6-9][0-9]{9}$/'],
            'email' => ['nullable', 'email', 'max:150'],
            'employee_count' => ['required', 'integer', 'min:1', 'max:100000'],
            'notes' => ['nullable', 'string', 'max:1000'],
        ]);

        $mobile = $this->normalizeMobile($data['mobile']);
        $verification = LeadOtpVerification::where('mobile', $mobile)->first();
        if (! $verification || ! $verification->isVerified()) {
            throw ValidationException::withMessages([
                'mobile' => 'Please verify your mobile number with OTP.',
            ]);
        }

        if (Lead::where('mobile', $mobile)->whereIn('status', ['new', 'contacted', 'qualified', 'meeting_scheduled'])->exists()) {
            throw ValidationException::withMessages([
                'mobile' => 'A lead with this mobile number already exists and is being followed up.',
            ]);
        }

        $lead = Lead::create([
            'company_name' => $data['company_name'],
            'contact_person_name' => $data['contact_person_name'],
            'mobile' => $mobile,
            'email' => $data['email'] ?? null,
            'employee_count' => (int) $data['employee_count'],
            'source' => 'register_free_trial',
            'status' => 'new',
            'otp_verified_at' => $verification->verified_at,
            'notes' => $data['notes'] ?? null,
        ]);

        $activityService->log($lead, 'captured', 'Lead captured from register page', [
            'source' => 'register',
        ]);
        $activityService->log($lead, 'otp_verified', 'Mobile verified via OTP');

        ProcessLeadCapturedJob::dispatch($lead->id);

        return redirect()->route('register')->with('success', 'Thanks! Your free trial request is submitted. Our team will contact you shortly.');
    }

    private function normalizeMobile(string $mobile): string
    {
        return preg_replace('/\D+/', '', $mobile) ?? $mobile;
    }

    private function maskMobile(string $mobile): string
    {
        if (strlen($mobile) <= 4) {
            return str_repeat('*', strlen($mobile));
        }
        return str_repeat('*', max(strlen($mobile) - 4, 0)) . substr($mobile, -4);
    }
}
