<?php

namespace App\Services;

use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Password;
use Illuminate\Validation\ValidationException;

class AuthService
{
    public function __construct(
        private TwoFactorAuthService $twoFactorService
    ) {
    }
    /**
     * Attempt to authenticate a user and return a token or 2FA challenge.
     *
     * @param  string  $email
     * @param  string  $password
     * @return array
     *
     * @throws ValidationException
     */
    public function login(string $email, string $password): array
    {
        $user = User::where('email', $email)->first();

        if (! $user || ! Hash::check($password, $user->password)) {
            throw ValidationException::withMessages([
                'email' => ['The provided credentials are incorrect.'],
            ]);
        }

        // Check if user needs 2FA (admins always do)
        if ($user->needsTwoFactorSetup() || $user->hasTwoFactorEnabled()) {
            // Generate and send 2FA code
            $sessionToken = $this->twoFactorService->generateAndSendCode($user);

            return [
                'requires_2fa' => true,
                'session_token' => $sessionToken,
                'user' => [
                    'id' => $user->id,
                    'email' => $user->email,
                ],
                'message' => 'Verification code sent to your email.',
            ];
        }

        // If 2FA is not enabled (shouldn't happen for admins, but safety check)
        return $this->issueToken($user);
    }

    /**
     * Verify 2FA code and issue token.
     *
     * @param  string  $email
     * @param  string  $code
     * @param  string  $sessionToken
     * @return array
     *
     * @throws ValidationException
     */
    public function verifyTwoFactor(string $email, string $code, string $sessionToken): array
    {
        $user = User::where('email', $email)->first();

        if (! $user) {
            throw ValidationException::withMessages([
                'email' => ['User not found.'],
            ]);
        }

        // Verify the code
        $this->twoFactorService->verifyCode($user, $code, $sessionToken);

        // Issue the authentication token
        return $this->issueToken($user);
    }

    /**
     * Issue an authentication token for the user.
     *
     * @param  User  $user
     * @return array
     */
    protected function issueToken(User $user): array
    {
        // Revoke all existing tokens (optional - for security)
        // $user->tokens()->delete();

        // Create a new token — expires in 8 hours
        $token = $user->createToken('auth-token', ['*'], now()->addHours(8))->plainTextToken;

        return [
            'user' => $user,
            'token' => $token,
        ];
    }

    /**
     * Send a password reset link to the user's email.
     *
     * @param string $email
     * @param string|null $origin The origin header from the request
     * @return string
     * @throws ValidationException
     */
    public function sendPasswordResetLink(string $email, ?string $origin = null): string
    {
        // Set the frontend URL based on the validated origin
        $frontendUrl = $this->getFrontendUrl($origin);
        config(['app.frontend_url' => $frontendUrl]);

        // Always attempt — do not reveal whether the email exists or not
        Password::sendResetLink(['email' => $email]);

        // Return a generic message regardless of outcome (prevents user enumeration)
        return 'If an account with that email address exists, you will receive a password reset link shortly.';
    }

    /**
     * Get the frontend URL from the origin, validating it against allowed origins.
     *
     * @param string|null $origin
     * @return string
     */
    protected function getFrontendUrl(?string $origin): string
    {
        // If no origin provided (e.g., Postman, CLI, server-to-server)
        // Use localhost as a safe placeholder that won't mislead users
        if (! $origin) {
            return 'http://localhost';
        }

        // Validate origin against allowed origins
        $allowedOrigins = config('cors.allowed_origins', []);

        if (in_array($origin, $allowedOrigins)) {
            return $origin;
        }

        // This should never happen because RestrictOrigin middleware blocks unauthorized origins
        // But as a safety measure, use localhost instead of a potentially malicious origin
        return 'http://localhost';
    }

    /**
     * Reset the user's password.
     *
     * @param string $email
     * @param string $password
     * @param string $token
     * @return string
     * @throws ValidationException
     */
    public function resetPassword(string $email, string $password, string $token): string
    {
        $status = Password::reset(
            [
                'email' => $email,
                'password' => $password,
                'password_confirmation' => $password,
                'token' => $token,
            ],
            function (User $user, string $password) {
                $user->forceFill([
                    'password' => Hash::make($password),
                ])->save();

                // Revoke all existing tokens for security
                $user->tokens()->delete();
            }
        );

        if ($status !== Password::PASSWORD_RESET) {
            throw ValidationException::withMessages([
                'email' => [__($status)],
            ]);
        }

        return __($status);
    }
}

