<?php

namespace App\Http\Controllers;

use App\Http\Requests\AuthRequest;
use App\Http\Requests\RefreshTokenAppRequest;
use App\Http\Requests\RefreshTokenRequest;
use App\Http\Requests\UserAppsRequest;
use App\Http\Requests\UserAppsValidateCodeRequest;
use App\Http\Resources\AuthResource;
use App\Services\AuthService;
use Illuminate\Http\JsonResponse;

class AuthController extends Controller
{
    public function __construct(protected AuthService $authService) {}

    public function login(AuthRequest $request): JsonResponse
    {
        $validated = $request->validated();

        $result = $this->authService->login(
            email:    data_get($validated, 'email'),
            password: data_get($validated, 'password'),
        );

        if (! $result) {
            return $this->errorResponse(message: __('auth.failed'), code: 401);
        }

        return $this->successResponse(
            payload: new AuthResource(data_get($result, 'payload')),
            message: __('auth.logged_in'),
        )->withCookie(
            cookie(
                'refresh_token',
                data_get($result, 'refreshToken'),
                config('sanctum.rt_expiration') * 60,
                '/',
                config('session.domain'),
                config('session.secure'),
                true,
                false,
                'Lax',
            ),
        );
    }

    public function loginApp(AuthRequest $request): JsonResponse
    {
        $validated = $request->validated();

        $result = $this->authService->login(
            email:    data_get($validated, 'email'),
            password: data_get($validated, 'password'),
        );

        if (! $result) {
            return $this->errorResponse(message: __('auth.failed'), code: 401);
        }

        return $this->successResponse(
            payload: new AuthResource([
                ...data_get($result, 'payload'),
                'refresh_token' => data_get($result, 'refreshToken'),
            ]),
            message: __('auth.logged_in'),
        );
    }

    public function logout(): JsonResponse
    {
        $this->authService->logout();

        return $this->successResponse(
            message: __('auth.logout'),
        )->withoutCookie('refresh_token');
    }

    public function refresh(RefreshTokenRequest $request): JsonResponse
    {
        $refresh_token = $request->cookie('refresh_token');

        if (is_null($refresh_token)) {
            return $this->errorResponse(
                code: 403,
            )->withoutCookie('refresh_token');
        }

        $result = $this->authService->refresh(
            $refresh_token
        );

        if (is_null($result)) {
            return $this->errorResponse(
                message: __('auth.unauthorized'), code: 403,
            )->withoutCookie('refresh_token');
        }

        return $this->successResponse(
            payload: new AuthResource(data_get($result, 'payload')),
        )->withCookie(
            cookie(
                'refresh_token',
                data_get($result, 'refreshToken'),
                config('sanctum.rt_expiration') * 60,
                '/',
                config('session.domain'),
                config('session.secure'),
                true,
                true,
                'Lax',
            ),
        );
    }

    public function refreshApp(RefreshTokenAppRequest $request): JsonResponse
    {
        $refresh_token = $request->validated('refresh_token');

        if (is_null($refresh_token)) {
            return $this->errorResponse(code: 403);
        }

        $result = $this->authService->refresh(
            $refresh_token, isApp: true,
        );

        if (is_null($result)) {
            return $this->errorResponse(
                message: __('auth.unauthorized'), code: 403,
            );
        }

        return $this->successResponse(
            payload: new AuthResource([
                ...data_get($result, 'payload'),
                'refresh_token' => data_get($result, 'refreshToken'),
            ]),
        );
    }

    public function clientSendCode(UserAppsRequest $request): JsonResponse
    {
        $result = $this->authService->clientSendCode($request->validated());

        if (is_array($result) && data_get($result, 'error') !== null) {
            return $this->errorResponse(message: __('auth.'.data_get($result, 'error')), code: 403);
        }

        return $this->successResponse(
            message: __('messages.code_sent'),
            code:    201,
            payload: ['isLogin' => $result],
        );
    }

    public function providerSendCode(UserAppsRequest $request): JsonResponse
    {
        $result = $this->authService->providerSendCode($request->validated());

        if (is_array($result) && data_get($result, 'error') !== null) {
            return $this->errorResponse(message: __('auth.'.data_get($result, 'error')), code: 403);
        }

        return $this->successResponse(
            message: __('messages.code_sent'),
            code:    201,
            payload: ['isLogin' => $result],
        );
    }

    public function validateCodeClient(UserAppsValidateCodeRequest $request): JsonResponse
    {
        $email   = $request->input('email');
        $phone   = $request->input('phone');
        $code    = $request->input('code');
        $isLogin = (bool) $request->input('isLogin', false);

        $result = $this->authService->validateCodeClient($request->validated(), $isLogin);

        if ($result === false) {
            return $this->errorResponse(message: __('auth.invalid_code'), code: 400);
        }

        if (is_array($result) && data_get($result, 'error') !== null) {
            return $this->errorResponse(message: __('auth.'.data_get($result, 'error')), code: 403);
        }

        if ($isLogin) {
            return $this->successResponse(
                payload: new AuthResource([...data_get($result, 'payload'), 'refresh_token' => data_get($result, 'refreshToken')]),
                message: __('auth.logged_in'),
            );
        }

        return $this->successResponse(
            payload: ['email' => $email, 'phone' => $phone, 'code' => $code],
            // message: __('auth.valid_code'),
        );
    }

    public function validateCodeProvider(UserAppsValidateCodeRequest $request): JsonResponse
    {
        $email   = $request->input('email');
        $phone   = $request->input('phone');
        $code    = $request->input('code');
        $isLogin = (bool) $request->input('isLogin', false);

        $result = $this->authService->validateCodeProvider($request->validated(), $isLogin);

        if ($result === false) {
            return $this->errorResponse(message: __('auth.invalid_code'), code: 400);
        }

        if (is_array($result) && data_get($result, 'error') !== null) {
            return $this->errorResponse(message: __('auth.'.data_get($result, 'error')), code: 403);
        }

        if ($isLogin) {
            return $this->successResponse(
                payload: new AuthResource([...data_get($result, 'payload'), 'refresh_token' => data_get($result, 'refreshToken')]),
                message: __('auth.logged_in'),
            );
        }

        return $this->successResponse(
            payload: ['email' => $email, 'phone' => $phone, 'code' => $code],
            message: __('auth.valid_code'),
        );
    }

    public function validateCode(UserAppsValidateCodeRequest $request): JsonResponse
    {
        try {
            $email   = $request->input('email');
            $phone   = $request->input('phone');
            $code    = $request->input('code');
            $isLogin = $request->input('isLogin');

            $result = $this->authService->validateCode($request->validated(), $isLogin);

            if (! $result) {
                return $this->errorResponse(
                    message: __('auth.invalid_code'), code: 400,
                );
            }

            if ($isLogin) {
                return $this->successResponse(
                    payload: new AuthResource([
                        ...data_get($result, 'payload'),
                        'refresh_token' => data_get($result, 'refreshToken'),
                    ]),
                    message: __('auth.logged_in'),
                );
            } else {
                return $this->successResponse(
                    payload: ['email' => $email, 'phone' => $phone, 'code' => $code],
                    message: __('auth.valid_code'),
                    code:    200,
                );
            }

        } catch (\Exception $e) {
            return $this->errorResponse(
                message: __('auth.validation_error'), code: 500, exception: $e,
            );
        }
    }
}
