<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Jobs\ProvisionMonnifyReservedAccountJob;
use App\Models\User;
use App\Providers\RouteServiceProvider;
use App\Services\ApiCredentialService;
use App\Services\LegalService;
use App\Services\ReferralService;
use Illuminate\Auth\Events\Registered;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\Rules;
use Illuminate\Validation\ValidationException;
use Inertia\Inertia;
use Inertia\Response;

class RegisteredUserController extends Controller
{
    /**
     * Display the registration view.
     */
    public function create(Request $request, ReferralService $referralService, LegalService $legalService): Response
    {
        $settings = $referralService->settings();
        $legal = $legalService->get();

        return Inertia::render('Auth/Register', [
            'referral' => [
                'enabled' => (bool) ($settings['enabled'] ?? false),
                'prefill_code' => $referralService->normalizeCode((string) $request->query('ref', '')),
                'default_reward_amount' => (string) ($settings['default_reward_amount'] ?? '0.00'),
            ],
            'legal' => [
                'terms_title' => $legal['terms_title'] ?? 'Terms and Conditions',
                'terms_content' => $legal['terms_content'] ?? '',
                'terms_version' => (int) ($legal['terms_version'] ?? 1),
            ],
        ]);
    }

    /**
     * Handle an incoming registration request.
     *
     * @throws \Illuminate\Validation\ValidationException
     */
    public function store(
        Request $request,
        ReferralService $referralService,
        ApiCredentialService $apiCredentialService,
        LegalService $legalService
    ): RedirectResponse
    {
        $request->merge([
            'bvn' => $this->normalizedBvn($request->input('bvn')),
            'phone' => $this->normalizedPhone($request->input('phone')),
        ]);

        $data = $request->validate([
            'name' => 'required|string|max:255',
            'email' => 'required|string|lowercase|email|max:255|unique:'.User::class,
            'phone' => 'required|string|digits_between:10,15|unique:'.User::class.',phone',
            'password' => ['required', 'confirmed', Rules\Password::defaults()],
            'transaction_pin' => ['required', 'digits:4', 'confirmed'],
            'bvn' => ['nullable', 'digits:11'],
            'referral_code' => ['nullable', 'string', 'max:32'],
            'terms_accepted' => ['required', 'accepted'],
        ]);

        $legal = $legalService->get();

        $normalizedReferralCode = $referralService->normalizeCode((string) ($data['referral_code'] ?? ''));
        $referralsEnabled = $referralService->isEnabled();

        if ($referralsEnabled && $normalizedReferralCode !== '' && ! $referralService->findReferrerByCode($normalizedReferralCode)) {
            throw ValidationException::withMessages([
                'referral_code' => 'The referral code you entered is invalid.',
            ]);
        }

        /** @var User $user */
        $user = DB::transaction(function () use ($data, $referralService, $referralsEnabled, $normalizedReferralCode, $apiCredentialService, $legal) {
            $user = User::create([
                'name' => $data['name'],
                'email' => $data['email'],
                'phone' => $this->normalizedPhone($data['phone'] ?? null),
                'bvn' => $this->normalizedBvn($data['bvn'] ?? null),
                'last_login_at' => now(),
                'last_activity_at' => now(),
                'password' => Hash::make($data['password']),
                'transaction_pin' => (string) $data['transaction_pin'],
                'transaction_pin_set_at' => now(),
                'terms_accepted_version' => (int) ($legal['terms_version'] ?? 1),
                'terms_accepted_at' => now(),
            ]);

            $referralService->ensureReferralCode($user);

            if ($referralsEnabled && $normalizedReferralCode !== '') {
                $referralService->applyReferralOnRegistration($user, $normalizedReferralCode);
            }

            $user = $user->fresh();
            $apiCredentialService->ensureDefaultClient($user);

            return $user;
        }, 3);

        event(new Registered($user));

        Auth::login($user);

        ProvisionMonnifyReservedAccountJob::dispatchAfterResponse($user->id, 'registration');

        return redirect(RouteServiceProvider::HOME);
    }

    protected function normalizedBvn(mixed $value): ?string
    {
        $digits = preg_replace('/\D+/', '', (string) ($value ?? ''));

        return $digits !== '' ? $digits : null;
    }

    protected function normalizedPhone(mixed $value): ?string
    {
        $digits = preg_replace('/\D+/', '', (string) ($value ?? ''));

        return $digits !== '' ? $digits : null;
    }
}
