<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Http\Controllers\CartController;
use App\Http\Controllers\Traits\LimitsOtpRequests;
use App\Models\User;
use App\Models\Otp;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\View\View;

class OtpAuthController extends Controller
{
    use LimitsOtpRequests;
    public function showVerifyForm(Request $request): View
    {
        $phone = $request->get('phone');
        $type = $request->get('type', 'auth_verification');

        return view('auth.verify-otp', compact('phone', 'type'));
    }

    public function showLoginForm(Request $request): View
    {
        if ($request->has('intended')) {
            session(['url.intended' => $request->intended]);
        }

        return view('auth.otp-login');
    }

    public function sendOtp(Request $request): JsonResponse
    {
        $request->validate([
            'name' => 'nullable|string|max:255',
            'phone' => ['required', 'string', 'regex:/^01[3-9][0-9]{8}$/'],
        ]);

        $phone = $request->phone;
        $name = $request->name;
        $ip = $this->resolveClientIp();

        $rateLimited = $this->otpRateLimitExceeded($ip, $phone, 'auth');
        if ($rateLimited) {
            return $rateLimited;
        }

        $this->recordOtpAttempt($ip, $phone);

        $otp = Otp::createForPhone($phone, 'auth_verification', 4, 5);

        $user = User::where('phone', $phone)->first();
        $mode = $user ? 'login' : 'register';

        session(['auth_pending' => [
            'phone' => $phone,
            'name' => $name,
            'mode' => $mode,
        ]]);

        Log::info("Auth OTP for {$phone}: {$otp->otp_code} (mode: {$mode})");

        return response()->json([
            'success' => true,
            'message' => 'Verification code sent to your phone.',
            'mode' => $mode,
        ]);
    }

    public function verifyOtp(Request $request): JsonResponse
    {
        $request->validate([
            'phone' => ['required', 'string'],
            'otp' => ['required', 'string', 'size:4'],
        ]);

        $otp = Otp::where('phone', $request->phone)
            ->where('otp_code', $request->otp)
            ->where('type', 'auth_verification')
            ->where('is_verified', false)
            ->where('expires_at', '>', now())
            ->first();

        if (! $otp) {
            return response()->json([
                'success' => false,
                'message' => 'Invalid or expired verification code.',
            ], 422);
        }

        $pending = session('auth_pending');
        if (! $pending || $pending['phone'] !== $request->phone) {
            return response()->json([
                'success' => false,
                'message' => 'Session expired. Please request a new code.',
            ], 422);
        }

        $otp->update(['is_verified' => true]);

        $this->resetOtpRateLimits($this->resolveClientIp(), $request->phone);

        DB::beginTransaction();

        try {
            $user = User::where('phone', $request->phone)->first();

            if (! $user) {
                $user = User::create([
                    'name' => $pending['name'] ?: $request->phone,
                    'phone' => $request->phone,
                    'phone_verified_at' => now(),
                    'password' => bcrypt($request->otp),
                ]);
            } else {
                $user->update([
                    'phone_verified_at' => now(),
                    'password' => bcrypt($request->otp),
                ]);
            }

            Auth::login($user);
            $request->session()->regenerate();
            session()->forget('auth_pending');

            $cartController = new CartController();
            $cartController->transferSessionCartToDatabase($user->id, $request->input('source') === 'checkout');

            $redirect = session('url.intended') ?: route('dashboard');
            session()->forget('url.intended');

            DB::commit();

            return response()->json([
                'success' => true,
                'message' => 'Logged in successfully!',
                'redirect' => $redirect,
            ]);
        } catch (\Exception $e) {
            DB::rollBack();
            Log::error('OTP auth verify error:', ['error' => $e->getMessage()]);

            return response()->json([
                'success' => false,
                'message' => 'Something went wrong. Please try again.',
            ], 500);
        }
    }

    public function resendOtp(Request $request): JsonResponse
    {
        $request->validate([
            'phone' => ['required', 'string', 'regex:/^01[3-9][0-9]{8}$/'],
            'name' => 'nullable|string|max:255',
        ]);

        $phone = $request->phone;
        $name = $request->name;
        $ip = $this->resolveClientIp();

        $rateLimited = $this->otpRateLimitExceeded($ip, $phone, 'auth_resend');
        if ($rateLimited) {
            return $rateLimited;
        }

        $this->recordOtpAttempt($ip, $phone);

        $otp = Otp::createForPhone($phone, 'auth_verification', 4, 5);

        $user = User::where('phone', $phone)->first();
        session(['auth_pending' => [
            'phone' => $phone,
            'name' => $name,
            'mode' => $user ? 'login' : 'register',
        ]]);

        Log::info("Auth OTP (resend) for {$phone}: {$otp->otp_code}");

        return response()->json([
            'success' => true,
            'message' => 'Verification code resent.',
        ]);
    }

    public function destroy(Request $request)
    {
        Auth::guard('web')->logout();

        $request->session()->invalidate();
        $request->session()->regenerateToken();

        return redirect('/');
    }
}
