<?php

namespace App\Http\Controllers\Api;

use App\Enums\AccountStatus;
use App\Http\Controllers\Controller;
use App\Mail\EmailVerificationOtp;
use App\Services\OtpService;
use App\Services\SmsService;
use Illuminate\Auth\Events\Verified;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Mail;

class VerificationController extends Controller
{
    public function __construct(
        private readonly OtpService $otp,
        private readonly SmsService $sms,
    ) {
    }

    public function sendEmailOtp(Request $request): JsonResponse
    {
        $user = $request->user();

        if ($user->email_verified_at) {
            return response()->json(['message' => 'Email already verified.'], 400);
        }

        $code = $this->otp->generate("email:{$user->id}");

        Mail::to($user->email)->send(new EmailVerificationOtp($code));

        return response()->json(['message' => 'Verification code sent to email.']);
    }

    public function verifyEmailOtp(Request $request): JsonResponse
    {
        $request->validate(['code' => ['required', 'string']]);

        $user = $request->user();

        if (! $this->otp->verify("email:{$user->id}", $request->code)) {
            return response()->json(['message' => 'Invalid or expired code.'], 422);
        }

        $user->email_verified_at = now();
        $user->save();

        event(new Verified($user));

        return response()->json(['message' => 'Email verified.', 'user' => $user->fresh()]);
    }

    public function sendPhoneOtp(Request $request): JsonResponse
    {
        $user = $request->user();

        if (! $user->phone_number) {
            return response()->json(['message' => 'No phone number on file.'], 400);
        }

        if ($user->phone_number_verified_at) {
            return response()->json(['message' => 'Phone number already verified.'], 400);
        }

        $code = $this->otp->generate("phone:{$user->id}");

        $this->sms->send($user->phone_number, "Your Payth verification code is {$code}. It expires in 10 minutes.");

        return response()->json(['message' => 'Verification code sent to phone.']);
    }

    public function verifyPhoneOtp(Request $request): JsonResponse
    {
        $request->validate(['code' => ['required', 'string']]);

        $user = $request->user();

        if (! $this->otp->verify("phone:{$user->id}", $request->code)) {
            return response()->json(['message' => 'Invalid or expired code.'], 422);
        }

        $user->phone_number_verified_at = now();
        $user->save();

        $this->maybeActivate($user);

        return response()->json(['message' => 'Phone number verified.', 'user' => $user->fresh()]);
    }

    private function maybeActivate($user): void
    {
        if (
            $user->status === AccountStatus::Pending
            && $user->email_verified_at
            && $user->phone_number_verified_at
        ) {
            $user->status = AccountStatus::Activated;
            $user->save();
        }
    }
}