<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Models\RefreshToken;
use App\Models\User;
use App\Support\ApiResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;

class AuthController extends Controller
{
    public function register(Request $request)
    {
        $data = $request->validate([
            'fullName' => 'required|string|max:255',
            'email' => 'required|email|unique:users,email',
            'password' => 'required|string|min:8',
            'confirmPassword' => 'required|same:password',
            'redirectURL' => 'nullable|string',
        ]);

        $user = User::create([
            'full_name' => $data['fullName'],
            'email' => $data['email'],
            'password' => $data['password'],
            'role' => 'client',
            'verification_token' => Str::random(64),
            'is_email_verified' => false,
        ]);

        // In production, mail the verification link with $data['redirectURL'] + token.
        return ApiResponse::success('Registered successfully. Please verify your email.', [
            'userId' => $user->id,
            'verifyToken' => $user->verification_token,
        ]);
    }

    public function verify(Request $request, string $token)
    {
        $user = User::where('verification_token', $token)->first();
        if (!$user) {
            return ApiResponse::error('Invalid or expired verification token', null, 422);
        }
        $user->is_email_verified = true;
        $user->email_verified_at = now();
        $user->verification_token = null;
        $user->save();

        return ApiResponse::success('Email verified successfully', ['userId' => $user->id]);
    }

    public function login(Request $request)
    {
        $data = $request->validate([
            'email' => 'required|email',
            'password' => 'required|string',
        ]);

        $user = User::where('email', $data['email'])->first();
        if (!$user || !Hash::check($data['password'], $user->password)) {
            return ApiResponse::error('Invalid email or password', null, 401);
        }
        if (!$user->is_active) {
            return ApiResponse::error('Account is disabled', null, 403);
        }

        $accessTtl = (int) env('SANCTUM_ACCESS_TOKEN_TTL', 10080);
        $refreshTtl = (int) env('SANCTUM_REFRESH_TOKEN_TTL', 43200);

        $accessToken = $user->createToken(
            'access',
            ['*'],
            now()->addMinutes($accessTtl)
        );

        $refresh = RefreshToken::create([
            'user_id' => $user->id,
            'token' => Str::random(80),
            'expires_at' => now()->addMinutes($refreshTtl),
            'revoked' => false,
        ]);

        return ApiResponse::success('Logged in', [
            'user' => self::userPayload($user),
            'access_token' => [
                'token' => $accessToken->plainTextToken,
                'expires' => $accessToken->accessToken->expires_at?->toIso8601String(),
            ],
            'refreshToken' => [
                'token' => $refresh->token,
                'expires' => $refresh->expires_at->toIso8601String(),
            ],
        ]);
    }

    public function refresh(Request $request)
    {
        $token = $request->input('refreshToken') ?? $request->header('refreshToken');
        if (!$token) {
            return ApiResponse::error('Refresh token required', null, 422);
        }

        $rt = RefreshToken::where('token', $token)->first();
        if (!$rt || $rt->revoked || Carbon::parse($rt->expires_at)->isPast()) {
            return ApiResponse::error('Invalid or expired refresh token', null, 401);
        }

        $user = $rt->user;
        $accessTtl = (int) env('SANCTUM_ACCESS_TOKEN_TTL', 10080);
        $refreshTtl = (int) env('SANCTUM_REFRESH_TOKEN_TTL', 43200);

        $accessToken = $user->createToken('access', ['*'], now()->addMinutes($accessTtl));

        $rt->revoked = true;
        $rt->save();
        $newRefresh = RefreshToken::create([
            'user_id' => $user->id,
            'token' => Str::random(80),
            'expires_at' => now()->addMinutes($refreshTtl),
        ]);

        return ApiResponse::success('Token refreshed', [
            'access_token' => [
                'token' => $accessToken->plainTextToken,
                'expires' => $accessToken->accessToken->expires_at?->toIso8601String(),
            ],
            'refreshToken' => [
                'token' => $newRefresh->token,
                'expires' => $newRefresh->expires_at->toIso8601String(),
            ],
        ]);
    }

    public function forgetPassword(Request $request)
    {
        $email = $request->query('email') ?? $request->input('email');
        if (!$email) {
            return ApiResponse::error('Email is required', null, 422);
        }
        $user = User::where('email', $email)->first();
        if (!$user) {
            // Don't leak which emails exist.
            return ApiResponse::success('If the email exists, a reset link has been sent.');
        }
        $token = Str::random(64);
        // Store the token on the user row so we can look it up without the email later.
        $user->verification_token = $token;
        $user->save();
        // In production: send email to $user->email with $request->query('redirectURL').'?token='.$token

        return ApiResponse::success('Password reset link sent', ['resetToken' => $token]);
    }

    public function resetPassword(Request $request)
    {
        $data = $request->validate([
            'email' => 'nullable|email',
            'token' => 'required|string',
            'password' => 'required|string|min:8',
            'confirmPassword' => 'required|same:password',
        ]);

        $user = User::where('verification_token', $data['token'])->first();
        if (!$user) {
            return ApiResponse::error('Invalid or expired token', null, 422);
        }

        $user->password = $data['password'];
        $user->verification_token = null;
        $user->save();

        return ApiResponse::success('Password reset successfully');
    }

    public function changePassword(Request $request)
    {
        $data = $request->validate([
            'currentPassword' => 'required|string',
            'newPassword' => 'required|string|min:8',
            'confirmPassword' => 'required|same:newPassword',
        ]);
        $user = $request->user();
        if (!Hash::check($data['currentPassword'], $user->password)) {
            return ApiResponse::error('Current password is incorrect', null, 422);
        }
        $user->password = $data['newPassword'];
        $user->save();
        return ApiResponse::success('Password changed');
    }

    public function me(Request $request)
    {
        return ApiResponse::success('Current user', self::userPayload($request->user()));
    }

    public function logout(Request $request)
    {
        $request->user()?->currentAccessToken()?->delete();
        return ApiResponse::success('Logged out');
    }

    public static function userPayload(User $user): array
    {
        return [
            'id' => $user->id,
            'email' => $user->email,
            'full_name' => $user->full_name,
            'fullName' => $user->full_name,
            'role' => $user->role,
            'profile_picture' => $user->profile_picture,
            'connected' => $user->connected,
            'is_email_verified' => $user->is_email_verified,
        ];
    }
}
