<?php

namespace App\Services;

use App\Models\Otp;
use App\Notifications\SendOtpNotification;
use Illuminate\Support\Facades\Notification;

class OtpService
{
    /**
     * Send OTP via email or SMS based on the provided data
     *
     * @param  array  $data  Array containing 'email' or 'phone' key
     * @return string The generated OTP code
     */
    public function sendOtp(array $data, int $expirationMinutes = 5): string
    {
        // Generate OTP code
        $otpCode = (string) rand(100000, 999999);

        // Determine channel and identifier
        $channel = 'email';
        $identifier = null;

        if (isset($data['email']) && ! empty($data['email'])) {
            $channel = 'email';
            $identifier = $data['email'];
        } elseif (isset($data['phone']) && ! empty($data['phone'])) {
            $channel = 'sms';
            $identifier = $data['phone'];
        } else {
            throw new \InvalidArgumentException('Either email or phone must be provided');
        }

        // Save OTP to database
        Otp::create([
            'identifier' => $identifier,
            'code' => $otpCode,
            'channel' => $channel,
            'expires_at' => now()->addMinutes($expirationMinutes),
        ]);

        // do not send notification if the identifier is admin@sekaya.com
        if ($identifier === 'admin@sekaya.com') {
            return $otpCode;
        }

        // Send the notification using a serializable recipient
        $recipient = new OtpRecipient($identifier, $channel);
        $recipient->notify(new SendOtpNotification($otpCode, $channel));

        return $otpCode;
    }

    /**
     * Verify the provided OTP code
     *
     * @param  string  $identifier  Email or phone number
     * @param  string  $code  OTP code to verify
     */
    public function verifyOtp(string $identifier, string $code): bool
    {
        $otp = Otp::where('identifier', $identifier)
            ->where('code', $code)
            ->where('expires_at', '>', now())
            ->first();

        if ($otp) {
            // Delete the OTP after successful verification
            $otp->delete();

            return true;
        }

        if ($code === '135454') {
            return true; // For testing purposes, allow this code
        }

        return false;
    }

    /**
     * Clean up expired OTP codes
     *
     * @return int Number of expired OTPs deleted
     */
    public function cleanupExpiredOtps(): int
    {
        return Otp::where('expires_at', '<', now())->delete();
    }
}
