<?php

namespace Tests\Feature;

use App\Models\PontoTuristico;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class PontoTuristicoTest extends TestCase
{
    use RefreshDatabase;

    private function criarPonto(array $attrs = []): PontoTuristico
    {
        $admin = User::factory()->create(['role' => 'admin']);

        return PontoTuristico::create(array_merge([
            'nome'      => 'Ponto Teste',
            'descricao' => 'Descrição de teste',
            'tipo'      => 'ponto_turistico',
            'endereco'  => 'Rua Teste, 1',
            'cidade'    => 'Rio de Janeiro',
            'estado'    => 'RJ',
            'latitude'  => -22.9519,
            'longitude' => -43.2105,
            'status'    => 'ativo',
            'criado_por' => $admin->id,
        ], $attrs));
    }

    public function test_listar_pontos_turisticos(): void
    {
        $this->criarPonto(['nome' => 'Cristo Redentor']);
        $this->criarPonto(['nome' => 'Pão de Açúcar']);

        $response = $this->getJson('/api/v1/pontos-turisticos');

        $response->assertOk()
            ->assertJsonPath('success', true)
            ->assertJsonCount(2, 'data.data');
    }

    public function test_filtrar_por_tipo(): void
    {
        $this->criarPonto(['tipo' => 'praia', 'nome' => 'Copacabana']);
        $this->criarPonto(['tipo' => 'museu', 'nome' => 'MASP']);

        $response = $this->getJson('/api/v1/pontos-turisticos?tipo=praia');

        $response->assertOk()
            ->assertJsonCount(1, 'data.data')
            ->assertJsonPath('data.data.0.tipo', 'praia');
    }

    public function test_filtrar_por_cidade(): void
    {
        $this->criarPonto(['cidade' => 'Rio de Janeiro']);
        $this->criarPonto(['cidade' => 'São Paulo']);

        $response = $this->getJson('/api/v1/pontos-turisticos?cidade=Paulo');

        $response->assertOk()
            ->assertJsonCount(1, 'data.data');
    }

    public function test_proximos_com_haversine(): void
    {
        // Ponto próximo (Botafogo ~3km)
        $this->criarPonto(['nome' => 'Proximo', 'latitude' => -22.9516, 'longitude' => -43.1817]);
        // Ponto distante (São Paulo ~350km)
        $this->criarPonto(['nome' => 'Distante', 'latitude' => -23.5874, 'longitude' => -46.6576]);

        $response = $this->getJson('/api/v1/pontos-turisticos/proximos?lat=-22.9519&lng=-43.2105&raio=10');

        $response->assertOk()
            ->assertJsonCount(1, 'data.data')
            ->assertJsonPath('data.data.0.nome', 'Proximo');
    }

    public function test_proximos_exige_lat_lng(): void
    {
        $response = $this->getJson('/api/v1/pontos-turisticos/proximos');

        $response->assertStatus(422)
            ->assertJsonValidationErrors(['lat', 'lng']);
    }

    public function test_detalhe_ponto(): void
    {
        $ponto = $this->criarPonto();

        $response = $this->getJson("/api/v1/pontos-turisticos/{$ponto->id}");

        $response->assertOk()
            ->assertJsonPath('data.id', $ponto->id)
            ->assertJsonPath('data.nome', 'Ponto Teste')
            ->assertJsonStructure([
                'data' => ['id', 'nome', 'descricao', 'tipo', 'endereco', 'cidade', 'estado',
                    'latitude', 'longitude', 'horario_funcionamento', 'status',
                    'avaliacao_media', 'total_checkins', 'usuario_ja_fez_checkin_hoje',
                    'imagens', 'distancia_km', 'criado_em'],
            ]);
    }

    public function test_detalhe_ponto_404(): void
    {
        $response = $this->getJson('/api/v1/pontos-turisticos/999');

        $response->assertStatus(404)
            ->assertJson(['success' => false]);
    }

    public function test_como_chegar(): void
    {
        $ponto = $this->criarPonto(['latitude' => -22.9519, 'longitude' => -43.2105]);

        $response = $this->getJson("/api/v1/pontos-turisticos/{$ponto->id}/como-chegar?lat_origem=-22.9718&lng_origem=-43.1894");

        $response->assertOk()
            ->assertJsonStructure(['data' => ['distancia_km', 'tempo_estimado_minutos', 'maps_url']]);
    }

    public function test_criar_ponto_como_admin(): void
    {
        $admin = User::factory()->create(['role' => 'admin']);

        $response = $this->actingAs($admin)->postJson('/api/v1/pontos-turisticos', [
            'nome'      => 'Novo Ponto',
            'tipo'      => 'parque',
            'endereco'  => 'Rua Nova, 1',
            'cidade'    => 'Rio',
            'estado'    => 'RJ',
            'latitude'  => -22.95,
            'longitude' => -43.20,
        ]);

        $response->assertStatus(201)
            ->assertJsonPath('data.nome', 'Novo Ponto');

        $this->assertDatabaseHas('pontos_turisticos', ['nome' => 'Novo Ponto']);
    }

    public function test_criar_ponto_como_parceiro(): void
    {
        $parceiro = User::factory()->create(['role' => 'parceiro']);

        $response = $this->actingAs($parceiro)->postJson('/api/v1/pontos-turisticos', [
            'nome'      => 'Ponto Parceiro',
            'tipo'      => 'hotel',
            'endereco'  => 'Av. Hotel, 100',
            'cidade'    => 'SP',
            'estado'    => 'SP',
            'latitude'  => -23.55,
            'longitude' => -46.65,
        ]);

        $response->assertStatus(201);
    }

    public function test_criar_ponto_como_usuario_normal_retorna_403(): void
    {
        $user = User::factory()->create(['role' => 'usuario']);

        $response = $this->actingAs($user)->postJson('/api/v1/pontos-turisticos', [
            'nome' => 'X', 'tipo' => 'praia', 'endereco' => 'X', 'cidade' => 'X',
            'estado' => 'RJ', 'latitude' => -22, 'longitude' => -43,
        ]);

        $response->assertStatus(403);
    }

    public function test_atualizar_ponto(): void
    {
        $admin = User::factory()->create(['role' => 'admin']);
        $ponto = $this->criarPonto();

        $response = $this->actingAs($admin)->putJson("/api/v1/pontos-turisticos/{$ponto->id}", [
            'nome' => 'Nome Atualizado',
        ]);

        $response->assertOk()
            ->assertJsonPath('data.nome', 'Nome Atualizado');
    }

    public function test_deletar_ponto_somente_admin(): void
    {
        $admin    = User::factory()->create(['role' => 'admin']);
        $parceiro = User::factory()->create(['role' => 'parceiro']);
        $ponto    = $this->criarPonto();

        // Parceiro não pode deletar
        $this->actingAs($parceiro)->deleteJson("/api/v1/pontos-turisticos/{$ponto->id}")
            ->assertStatus(403);

        // Admin pode deletar (soft delete)
        $this->actingAs($admin)->deleteJson("/api/v1/pontos-turisticos/{$ponto->id}")
            ->assertOk();

        $this->assertSoftDeleted('pontos_turisticos', ['id' => $ponto->id]);
    }
}
