<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Http\Helpers\ApiResponse;
use App\Models\Transaction;
use App\Models\User;
use App\Services\Auth\PasswordPolicyService;
use App\Services\MobileConfig\MobileConfigService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Password;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Validation\ValidationException;
use OpenApi\Attributes as OA;
use Spatie\Permission\Models\Role;

class AuthController extends Controller
{
    public function __construct(
        protected MobileConfigService $mobileConfig
    ) {}

    #[OA\Post(
        path: '/v1/login',
        operationId: 'login',
        tags: ['Auth'],
        summary: 'Authenticate a user',
        requestBody: new OA\RequestBody(
            required: true,
            content: new OA\JsonContent(
                required: ['email', 'password'],
                properties: [
                    new OA\Property(property: 'email', type: 'string', format: 'email', example: 'user@example.com'),
                    new OA\Property(property: 'password', type: 'string', format: 'password', example: 'secret'),
                ]
            )
        ),
        responses: [
            new OA\Response(response: 200, description: 'Login successful',
                content: new OA\JsonContent(properties: [
                    new OA\Property(property: 'status', type: 'string', example: 'success'),
                    new OA\Property(property: 'data', type: 'object', properties: [
                        new OA\Property(property: 'user', ref: '#/components/schemas/User'),
                        new OA\Property(property: 'token', type: 'string'),
                    ]),
                ])
            ),
            new OA\Response(response: 401, description: 'Invalid credentials'),
            new OA\Response(response: 403, description: 'Account inactive or role not permitted'),
        ]
    )]
    public function login(Request $request)
    {
        $request->validate([
            'email' => 'required|email',
            'password' => 'required',
        ]);

        $config = $this->mobileConfig->all();
        $maxAttempts = $config['security_auth']['login_max_attempts'] ?? 5;
        $throttleKey = 'login_attempt_'.$request->ip().'_'.$request->email;

        if (RateLimiter::tooManyAttempts($throttleKey, $maxAttempts)) {
            $seconds = RateLimiter::availableIn($throttleKey);

            return ApiResponse::error("Too many login attempts. Please try again in {$seconds} seconds.", 429);
        }

        $user = User::where('email', $request->email)->first();

        if (! $user || ! Hash::check($request->password, $user->password)) {
            RateLimiter::hit($throttleKey, 60); // Lock for 60 seconds if limit reached

            return ApiResponse::unauthorized('The provided credentials are incorrect.');
        }

        RateLimiter::clear($throttleKey);

        if (isset($user->is_active) && ! $user->is_active) {
            return ApiResponse::forbidden('Your account is currently inactive. Please contact support.');
        }

        if (class_exists(Role::class)) {
            $allowedRoles = ['User', 'Administrator', 'Developer'];
            if (! $user->hasAnyRole($allowedRoles)) {
                return ApiResponse::forbidden('Access denied. Your role does not have permission to access the mobile application.');
            }
        }

        $token = $user->createToken('mobile-app')->plainTextToken;

        return ApiResponse::success(['user' => $user, 'token' => $token], 'Login successful');
    }

    #[OA\Post(
        path: '/v1/register',
        operationId: 'register',
        tags: ['Auth'],
        summary: 'Register a new user',
        requestBody: new OA\RequestBody(
            required: true,
            content: new OA\JsonContent(
                required: ['name', 'email', 'password'],
                properties: [
                    new OA\Property(property: 'name', type: 'string', example: 'John Doe'),
                    new OA\Property(property: 'email', type: 'string', format: 'email'),
                    new OA\Property(property: 'password', type: 'string', minLength: 8),
                ]
            )
        ),
        responses: [
            new OA\Response(response: 201, description: 'Registration successful'),
            new OA\Response(response: 422, description: 'Validation error'),
        ]
    )]
    public function register(Request $request)
    {
        $config = $this->mobileConfig->all();

        // 1. Check if registration is enabled in Global Mobile Settings
        if (! ($config['features']['enable_registration'] ?? true)) {
            return ApiResponse::error('Registration is currently disabled by administrator.', 403);
        }

        // 2. Check if OTP is required
        if (($config['features']['require_otp_registration'] ?? false) && ! $request->has('otp_token')) {
            return ApiResponse::error('OTP verification is required for registration.', 403);
        }

        $request->validate([
            'name' => 'required|string|max:255',
            'email' => 'required|string|email|max:255|unique:users',
            'password' => ['required', 'string', PasswordPolicyService::getRules()],
        ]);

        $user = User::create([
            'name' => $request->name,
            'email' => $request->email,
            'password' => Hash::make($request->password),
            'is_active' => true,
        ]);

        if (class_exists(Role::class)) {
            $user->assignRole('User');
        }

        $token = $user->createToken('mobile-app')->plainTextToken;

        return ApiResponse::created(['user' => $user, 'token' => $token], 'Registration successful');
    }

    #[OA\Post(
        path: '/v1/logout',
        operationId: 'logout',
        tags: ['Auth'],
        summary: 'Revoke current access token',
        security: [['sanctum' => []]],
        responses: [
            new OA\Response(response: 200, description: 'Logged out successfully'),
            new OA\Response(response: 401, description: 'Unauthenticated'),
        ]
    )]
    public function logout(Request $request)
    {
        $request->user()->currentAccessToken()->delete();

        return ApiResponse::success(null, 'Logged out successfully');
    }

    #[OA\Post(
        path: '/v1/forgot-password',
        operationId: 'forgotPassword',
        tags: ['Auth'],
        summary: 'Send password reset link',
        requestBody: new OA\RequestBody(
            required: true,
            content: new OA\JsonContent(
                required: ['email'],
                properties: [new OA\Property(property: 'email', type: 'string', format: 'email')]
            )
        ),
        responses: [
            new OA\Response(response: 200, description: 'Reset link sent'),
            new OA\Response(response: 422, description: 'Email not found or throttled'),
        ]
    )]
    public function forgotPassword(Request $request)
    {
        $request->validate([
            'email' => 'required|email',
        ]);

        $status = Password::sendResetLink($request->only('email'));

        if ($status === Password::RESET_LINK_SENT) {
            return ApiResponse::success(null, __($status));
        }

        return ApiResponse::error(__($status), 422);
    }

    #[OA\Post(
        path: '/v1/profile/update',
        operationId: 'updateProfile',
        tags: ['Profile'],
        summary: 'Update authenticated user profile',
        security: [['sanctum' => []]],
        requestBody: new OA\RequestBody(
            required: true,
            content: new OA\JsonContent(
                required: ['name', 'email'],
                properties: [
                    new OA\Property(property: 'name', type: 'string'),
                    new OA\Property(property: 'email', type: 'string', format: 'email'),
                ]
            )
        ),
        responses: [
            new OA\Response(response: 200, description: 'Profile updated'),
            new OA\Response(response: 422, description: 'Validation error'),
        ]
    )]
    public function updateProfile(Request $request)
    {
        $request->validate([
            'name' => 'required|string|max:255',
            'email' => 'required|string|email|max:255|unique:users,email,'.Auth::id(),
        ]);

        $user = Auth::user();
        $user->update([
            'name' => $request->name,
            'email' => $request->email,
        ]);

        return ApiResponse::success(['user' => $user->fresh()], 'Profile updated successfully');
    }

    #[OA\Post(
        path: '/v1/profile/avatar',
        operationId: 'updateAvatar',
        tags: ['Profile'],
        summary: 'Upload user avatar',
        security: [['sanctum' => []]],
        requestBody: new OA\RequestBody(
            required: true,
            content: new OA\MediaType(
                mediaType: 'multipart/form-data',
                schema: new OA\Schema(properties: [
                    new OA\Property(property: 'avatar', type: 'string', format: 'binary'),
                ])
            )
        ),
        responses: [
            new OA\Response(response: 200, description: 'Avatar updated'),
            new OA\Response(response: 422, description: 'Validation error'),
        ]
    )]
    public function updateAvatar(Request $request)
    {
        $request->validate([
            'avatar' => 'required|image|mimes:jpeg,png,jpg,gif|max:10240',
        ]);

        $user = Auth::user();

        if ($request->hasFile('avatar')) {
            $user->clearMediaCollection('avatar');
            $media = $user->addMediaFromRequest('avatar')->toMediaCollection('avatar');

            return ApiResponse::success([
                'avatar_url' => $media->getFullUrl(),
                'user' => $user->fresh(),
            ], 'Avatar updated successfully');
        }

        return ApiResponse::error('No file uploaded', 400);
    }

    #[OA\Get(
        path: '/v1/dashboard',
        operationId: 'getDashboard',
        tags: ['Dashboard'],
        summary: 'Get dashboard summary data',
        security: [['sanctum' => []]],
        responses: [
            new OA\Response(response: 200, description: 'Dashboard data'),
            new OA\Response(response: 401, description: 'Unauthenticated'),
        ]
    )]
    public function getDashboardData(Request $request)
    {
        $user = Auth::user();
        $cacheKey = "user_dashboard_v2_{$user->id}";

        $data = Cache::remember($cacheKey, now()->addMinutes(5), function () use ($user) {
            $transactions = Transaction::where('user_id', $user->id)->latest()->take(10)->get();

            $totalBalance = Transaction::where('user_id', $user->id)
                ->selectRaw("SUM(CASE WHEN type = 'income' THEN amount ELSE -amount END) as balance")
                ->value('balance') ?? 0;

            return [
                'balance' => number_format($totalBalance, 2),
                'transactions' => $transactions,
                'stats' => [
                    'income' => Transaction::where('user_id', $user->id)->where('type', 'income')->sum('amount'),
                    'expense' => Transaction::where('user_id', $user->id)->where('type', 'expense')->sum('amount'),
                ],
            ];
        });

        return ApiResponse::success($data);
    }

    #[OA\Post(
        path: '/v1/profile/password',
        operationId: 'updatePassword',
        tags: ['Profile'],
        summary: 'Change authenticated user password',
        security: [['sanctum' => []]],
        requestBody: new OA\RequestBody(
            required: true,
            content: new OA\JsonContent(
                required: ['current_password', 'password', 'password_confirmation'],
                properties: [
                    new OA\Property(property: 'current_password', type: 'string'),
                    new OA\Property(property: 'password', type: 'string', minLength: 8),
                    new OA\Property(property: 'password_confirmation', type: 'string'),
                ]
            )
        ),
        responses: [
            new OA\Response(response: 200, description: 'Password updated'),
            new OA\Response(response: 422, description: 'Current password incorrect'),
        ]
    )]
    public function updatePassword(Request $request)
    {
        $request->validate([
            'current_password' => 'required',
            'password' => 'required|string|min:8|confirmed',
        ]);

        $user = Auth::user();

        if (! Hash::check($request->current_password, $user->password)) {
            return ApiResponse::error('The current password you entered is incorrect.', 422);
        }

        try {
            PasswordPolicyService::checkHistory($user, $request->password);
        } catch (ValidationException $e) {
            return ApiResponse::error($e->errors()['password'][0] ?? 'Password does not meet policy requirements.', 422);
        }

        $passwordHash = Hash::make($request->password);
        $user->update(['password' => $passwordHash]);
        PasswordPolicyService::recordPasswordChange($user, $passwordHash);

        return ApiResponse::success(null, 'Password updated successfully.');
    }

    #[OA\Delete(
        path: '/v1/profile/delete',
        operationId: 'deleteAccount',
        tags: ['Profile'],
        summary: 'Permanently delete authenticated user account',
        security: [['sanctum' => []]],
        requestBody: new OA\RequestBody(
            required: true,
            content: new OA\JsonContent(
                required: ['password'],
                properties: [
                    new OA\Property(property: 'password', type: 'string', description: 'Current password to confirm deletion'),
                ]
            )
        ),
        responses: [
            new OA\Response(response: 200, description: 'Account deleted'),
            new OA\Response(response: 422, description: 'Password incorrect or missing'),
        ]
    )]
    public function deleteAccount(Request $request)
    {
        $request->validate([
            'password' => 'required|string',
        ]);

        $user = Auth::user();

        if (! Hash::check($request->password, $user->password)) {
            return ApiResponse::error('The password you entered is incorrect.', 422);
        }

        $user->tokens()->delete();
        $user->delete();

        return ApiResponse::success(null, 'Your account has been deleted permanently.');
    }

    #[OA\Get(
        path: '/v1/user',
        operationId: 'getUser',
        tags: ['Auth'],
        summary: 'Get authenticated user',
        security: [['sanctum' => []]],
        responses: [
            new OA\Response(response: 200, description: 'User object'),
            new OA\Response(response: 401, description: 'Unauthenticated'),
        ]
    )]
    public function user(Request $request)
    {
        return ApiResponse::success(['user' => $request->user()]);
    }

    #[OA\Get(
        path: '/v1/app-config',
        operationId: 'getAppConfig',
        tags: ['Config'],
        summary: 'Get public app configuration (branding, taglines)',
        responses: [
            new OA\Response(response: 200, description: 'App config'),
        ]
    )]
    public function getAppConfig()
    {
        return ApiResponse::success([
            'logo' => asset(get_setting('app_logo', 'assets/img/logo.png')),
            'tagline1' => get_setting('app_tagline1', 'Welcome'),
            'tagline2' => strip_tags(get_setting('app_tagline2', 'Manage your assets efficiently')),
            'footer' => get_setting('footer_text', '© 2026 Your App'),
        ]);
    }
}
