<?php

namespace App\Http\Controllers\Api\V1;

use App\Http\Controllers\Controller;
use App\Http\Resources\Ambiental\EcopontoResource;
use App\Models\Ecoponto;
use App\Services\EcopontoService;
use App\Traits\ApiResponse;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use OpenApi\Attributes as OA;

class EcopontoController extends Controller
{
    use ApiResponse;

    public function __construct(private readonly EcopontoService $service) {}

    #[OA\Get(
        path: '/api/v1/ecopontos',
        summary: 'Listar ecopontos com filtros',
        tags: ['Ecopontos'],
        parameters: [
            new OA\Parameter(name: 'status', in: 'query', required: false, schema: new OA\Schema(type: 'string', enum: ['ativo', 'inativo', 'temporariamente_fechado'])),
            new OA\Parameter(name: 'tipo_residuo', in: 'query', required: false, description: 'Filtrar por tipo de resíduo aceito', schema: new OA\Schema(type: 'string')),
            new OA\Parameter(name: 'cidade', in: 'query', required: false, schema: new OA\Schema(type: 'string')),
        ],
        responses: [new OA\Response(response: 200, description: 'Lista paginada de ecopontos')]
    )]
    public function index(Request $request): JsonResponse
    {
        $ecopontos = $this->service->listar($request->only(['status', 'tipo_residuo', 'cidade']));

        return $this->success(EcopontoResource::collection($ecopontos)->response()->getData(true));
    }

    #[OA\Get(
        path: '/api/v1/ecopontos/proximos',
        summary: 'Ecopontos próximos por raio (Haversine)',
        tags: ['Ecopontos'],
        parameters: [
            new OA\Parameter(name: 'lat', in: 'query', required: true, schema: new OA\Schema(type: 'number', format: 'float')),
            new OA\Parameter(name: 'lng', in: 'query', required: true, schema: new OA\Schema(type: 'number', format: 'float')),
            new OA\Parameter(name: 'raio', in: 'query', required: false, description: 'Raio em KM (padrão 10, máx 50)', schema: new OA\Schema(type: 'number')),
            new OA\Parameter(name: 'tipo_residuo', in: 'query', required: false, schema: new OA\Schema(type: 'string')),
        ],
        responses: [
            new OA\Response(response: 200, description: 'Lista paginada com distancia_km calculada'),
            new OA\Response(response: 422, description: 'Parâmetros inválidos'),
        ]
    )]
    public function proximos(Request $request): JsonResponse
    {
        $request->validate([
            'lat'  => 'required|numeric|between:-90,90',
            'lng'  => 'required|numeric|between:-180,180',
            'raio' => 'sometimes|numeric|min:1|max:50',
        ]);

        $ecopontos = $this->service->proximos(
            (float) $request->lat,
            (float) $request->lng,
            (float) ($request->raio ?? 10),
            $request->only(['tipo_residuo'])
        );

        return $this->success(EcopontoResource::collection($ecopontos)->response()->getData(true));
    }

    #[OA\Get(
        path: '/api/v1/ecopontos/{id}',
        summary: 'Detalhe do ecoponto',
        tags: ['Ecopontos'],
        parameters: [new OA\Parameter(name: 'id', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
        responses: [
            new OA\Response(response: 200, description: 'Detalhe do ecoponto com total de doações'),
            new OA\Response(response: 404, description: 'Não encontrado'),
        ]
    )]
    public function show(int $id): JsonResponse
    {
        return $this->success(new EcopontoResource($this->service->buscarPorId($id)));
    }

    #[OA\Post(
        path: '/api/v1/ecopontos',
        summary: 'Criar ecoponto (admin/parceiro)',
        security: [['bearerAuth' => []]],
        tags: ['Ecopontos'],
        requestBody: new OA\RequestBody(
            required: true,
            content: new OA\JsonContent(
                required: ['nome', 'endereco', 'latitude', 'longitude'],
                properties: [
                    new OA\Property(property: 'nome', type: 'string', example: 'Ecoponto Centro'),
                    new OA\Property(property: 'descricao', type: 'string'),
                    new OA\Property(property: 'endereco', type: 'string'),
                    new OA\Property(property: 'latitude', type: 'number', format: 'float'),
                    new OA\Property(property: 'longitude', type: 'number', format: 'float'),
                    new OA\Property(property: 'tipos_residuo', type: 'array', items: new OA\Items(type: 'string'), example: ['plastico', 'vidro', 'metal']),
                    new OA\Property(property: 'horario_funcionamento', type: 'object'),
                    new OA\Property(property: 'status', type: 'string', enum: ['ativo', 'inativo', 'temporariamente_fechado']),
                ]
            )
        ),
        responses: [
            new OA\Response(response: 201, description: 'Ecoponto criado'),
            new OA\Response(response: 403, description: 'Sem permissão'),
            new OA\Response(response: 422, description: 'Dados inválidos'),
        ]
    )]
    public function store(Request $request): JsonResponse
    {
        $dados = $request->validate([
            'nome'                  => 'required|string|max:255',
            'descricao'             => 'nullable|string',
            'endereco'              => 'required|string|max:500',
            'latitude'              => 'required|numeric|between:-90,90',
            'longitude'             => 'required|numeric|between:-180,180',
            'tipos_residuo'         => 'nullable|array',
            'tipos_residuo.*'       => 'string',
            'horario_funcionamento' => 'nullable|array',
            'status'                => 'sometimes|in:ativo,inativo,temporariamente_fechado',
        ]);

        $ecoponto = $this->service->criar($dados);

        return $this->created(new EcopontoResource($ecoponto), 'Ecoponto criado com sucesso.');
    }

    #[OA\Put(
        path: '/api/v1/ecopontos/{id}',
        summary: 'Atualizar ecoponto (admin/parceiro)',
        security: [['bearerAuth' => []]],
        tags: ['Ecopontos'],
        parameters: [new OA\Parameter(name: 'id', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
        requestBody: new OA\RequestBody(required: true, content: new OA\JsonContent(properties: [new OA\Property(property: 'nome', type: 'string')])),
        responses: [
            new OA\Response(response: 200, description: 'Ecoponto atualizado'),
            new OA\Response(response: 404, description: 'Não encontrado'),
        ]
    )]
    public function update(Request $request, int $id): JsonResponse
    {
        $ecoponto = Ecoponto::findOrFail($id);

        $dados = $request->validate([
            'nome'                  => 'sometimes|string|max:255',
            'descricao'             => 'nullable|string',
            'endereco'              => 'sometimes|string|max:500',
            'latitude'              => 'sometimes|numeric|between:-90,90',
            'longitude'             => 'sometimes|numeric|between:-180,180',
            'tipos_residuo'         => 'nullable|array',
            'tipos_residuo.*'       => 'string',
            'horario_funcionamento' => 'nullable|array',
            'status'                => 'sometimes|in:ativo,inativo,temporariamente_fechado',
        ]);

        $ecoponto = $this->service->atualizar($ecoponto, $dados);

        return $this->success(new EcopontoResource($ecoponto), 'Ecoponto atualizado.');
    }

    #[OA\Delete(
        path: '/api/v1/ecopontos/{id}',
        summary: 'Remover ecoponto — soft delete (admin)',
        security: [['bearerAuth' => []]],
        tags: ['Ecopontos'],
        parameters: [new OA\Parameter(name: 'id', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))],
        responses: [
            new OA\Response(response: 200, description: 'Removido'),
            new OA\Response(response: 404, description: 'Não encontrado'),
        ]
    )]
    public function destroy(int $id): JsonResponse
    {
        $ecoponto = Ecoponto::findOrFail($id);
        $this->service->deletar($ecoponto);

        return $this->noContent('Ecoponto removido.');
    }
}
