<?php

namespace App\Http\Controllers\Api\Auth;

use App\Http\Controllers\Api\Core\BaseApiController;
use App\Http\Requests\Security\IpBanIndexRequest;
use App\Http\Requests\Security\IpBanRequest;
use App\Http\Requests\Security\IpUnbanRequest;
use App\Http\Resources\Security\IpBanCollection;
use App\Http\Resources\Security\IpBanResource;
use App\Models\IpAttempt;
use App\Services\Security\IpBanCommandService;
use App\Services\Security\IpBanQueryService;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
use Symfony\Component\HttpFoundation\Response;

class IpBanController extends BaseApiController
{
    public function __construct(
        private IpBanQueryService $queryService,
        private IpBanCommandService $commandService
    ) {
        parent::__construct();
    }

    public function index(IpBanIndexRequest $request): JsonResponse
    {
        $this->authorize('viewAny', IpAttempt::class);

        $filters = $request->validated();
        $page = (int) ($filters['page'] ?? 1);
        $perPage = (int) ($filters['per_page'] ?? 20);

        $bans = $this->queryService->paginate($filters, $page, $perPage);
        $collection = new IpBanCollection($bans);

        return $this->success([
            'bans' => $collection->toArray($request),
            'meta' => $collection->with($request)['meta'],
        ]);
    }

    public function show(int $id): JsonResponse
    {
        $ban = $this->queryService->find($id);
        if (!$ban) {
            return $this->error('IP record not found.', Response::HTTP_NOT_FOUND);
        }

        $this->authorize('view', $ban);

        return $this->success([
            'ban' => new IpBanResource($ban),
        ]);
    }

    public function ban(IpBanRequest $request): JsonResponse
    {
        $this->authorize('create', IpAttempt::class);

        $validated = $request->validated();
        $id = $validated['id'] ?? null;
        $ip = $validated['ip'] ?? null;
        $hours = (int) ($validated['hours'] ?? 24);

        try {
            $ban = $this->commandService->banNow($id ? (int) $id : null, $ip ? (string) $ip : null, $hours);
        } catch (\Throwable $e) {
            Log::error('IP ban failed: ' . $e->getMessage());
            return $this->error('Unable to ban IP.', Response::HTTP_INTERNAL_SERVER_ERROR);
        }

        if (!$ban) {
            return $this->error('IP record not found.', Response::HTTP_NOT_FOUND);
        }

        return $this->success([
            'ban' => new IpBanResource($ban),
        ], 'IP banned.');
    }

    public function unban(IpUnbanRequest $request): JsonResponse
    {
        $this->authorize('update', IpAttempt::class);

        $validated = $request->validated();
        $all = filter_var($validated['all'] ?? false, FILTER_VALIDATE_BOOLEAN);

        try {
            if ($all) {
                $count = $this->commandService->unbanAll();
                return $this->success([
                    'count' => $count,
                ], $count . ' IP(s) unbanned.');
            }

            $ban = $this->commandService->unbanOne(
                isset($validated['id']) ? (int) $validated['id'] : null,
                $validated['ip'] ?? null
            );
        } catch (\Throwable $e) {
            Log::error('IP unban failed: ' . $e->getMessage());
            return $this->error('Unable to unban IP.', Response::HTTP_INTERNAL_SERVER_ERROR);
        }

        if (!$ban) {
            return $this->error('IP record not found.', Response::HTTP_NOT_FOUND);
        }

        return $this->success([
            'ban' => new IpBanResource($ban),
        ], 'IP unbanned.');
    }
}
