<?php

namespace Tests\Feature;

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

class DoacaoTest extends TestCase
{
    use RefreshDatabase;

    private User $cidadao;
    private Ecoponto $ecoponto;

    protected function setUp(): void
    {
        parent::setUp();

        $this->cidadao = User::factory()->create(['user_type' => 'cidadao']);
        $this->ecoponto = Ecoponto::create([
            'nome' => 'Eco Teste', 'endereco' => 'R. X', 'latitude' => -22.95,
            'longitude' => -43.18, 'tipos_residuo' => ['plastico'], 'status' => 'ativo',
        ]);
    }

    public function test_registrar_doacao(): void
    {
        $response = $this->actingAs($this->cidadao)->postJson('/api/v1/doacoes', [
            'eco_ponto_id'  => $this->ecoponto->id,
            'tipo_material' => 'plastico',
            'quantidade_kg' => 3.5,
        ]);

        $response->assertStatus(201)
            ->assertJsonPath('success', true)
            ->assertJsonPath('data.tipo_material', 'plastico')
            ->assertJsonPath('data.quantidade_kg', 3.5)
            ->assertJsonPath('data.status', 'pendente');

        $this->assertDatabaseHas('doacoes', [
            'user_id'       => $this->cidadao->id,
            'tipo_material' => 'plastico',
            'status'        => 'pendente',
        ]);
    }

    public function test_registrar_doacao_sem_ecoponto(): void
    {
        $response = $this->actingAs($this->cidadao)->postJson('/api/v1/doacoes', [
            'tipo_material' => 'metal',
            'quantidade_kg' => 1.0,
        ]);

        $response->assertStatus(201)
            ->assertJsonPath('data.ecoponto', null);
    }

    public function test_registrar_doacao_ecoponto_inativo(): void
    {
        $inativo = Ecoponto::create([
            'nome' => 'Eco Inativo', 'endereco' => 'R. X', 'latitude' => -22.95,
            'longitude' => -43.18, 'tipos_residuo' => ['plastico'], 'status' => 'inativo',
        ]);

        $response = $this->actingAs($this->cidadao)->postJson('/api/v1/doacoes', [
            'eco_ponto_id'  => $inativo->id,
            'tipo_material' => 'plastico',
            'quantidade_kg' => 1.0,
        ]);

        $response->assertStatus(422)
            ->assertJsonValidationErrors(['eco_ponto_id']);
    }

    public function test_listar_minhas_doacoes(): void
    {
        Doacao::create([
            'user_id' => $this->cidadao->id, 'eco_ponto_id' => $this->ecoponto->id,
            'tipo_material' => 'plastico', 'quantidade_kg' => 2, 'status' => 'pendente',
        ]);
        Doacao::create([
            'user_id' => $this->cidadao->id, 'eco_ponto_id' => null,
            'tipo_material' => 'vidro', 'quantidade_kg' => 1, 'status' => 'confirmada',
        ]);

        $response = $this->actingAs($this->cidadao)->getJson('/api/v1/doacoes/minhas');

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

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

        Doacao::create(['user_id' => $this->cidadao->id, 'tipo_material' => 'plastico', 'quantidade_kg' => 1, 'status' => 'pendente']);
        Doacao::create(['user_id' => $outro->id, 'tipo_material' => 'vidro', 'quantidade_kg' => 2, 'status' => 'confirmada']);

        $response = $this->actingAs($admin)->getJson('/api/v1/doacoes');

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

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

        Doacao::create(['user_id' => $this->cidadao->id, 'tipo_material' => 'plastico', 'quantidade_kg' => 1, 'status' => 'pendente']);
        Doacao::create(['user_id' => $this->cidadao->id, 'tipo_material' => 'vidro', 'quantidade_kg' => 2, 'status' => 'confirmada']);

        $response = $this->actingAs($admin)->getJson('/api/v1/doacoes?status=pendente');

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

    public function test_confirmar_doacao(): void
    {
        $admin  = User::factory()->create(['role' => 'admin']);
        $doacao = Doacao::create([
            'user_id' => $this->cidadao->id, 'tipo_material' => 'plastico',
            'quantidade_kg' => 1, 'status' => 'pendente',
        ]);

        $response = $this->actingAs($admin)->patchJson("/api/v1/doacoes/{$doacao->id}/confirmar");

        $response->assertOk()
            ->assertJsonPath('data.status', 'confirmada');

        $this->assertDatabaseHas('doacoes', ['id' => $doacao->id, 'status' => 'confirmada']);
    }

    public function test_confirmar_doacao_ja_confirmada_falha(): void
    {
        $admin  = User::factory()->create(['role' => 'admin']);
        $doacao = Doacao::create([
            'user_id' => $this->cidadao->id, 'tipo_material' => 'plastico',
            'quantidade_kg' => 1, 'status' => 'confirmada',
        ]);

        $response = $this->actingAs($admin)->patchJson("/api/v1/doacoes/{$doacao->id}/confirmar");

        $response->assertStatus(422)
            ->assertJsonValidationErrors(['status']);
    }

    public function test_cancelar_doacao(): void
    {
        $admin  = User::factory()->create(['role' => 'admin']);
        $doacao = Doacao::create([
            'user_id' => $this->cidadao->id, 'tipo_material' => 'plastico',
            'quantidade_kg' => 1, 'status' => 'pendente',
        ]);

        $response = $this->actingAs($admin)->patchJson("/api/v1/doacoes/{$doacao->id}/cancelar");

        $response->assertOk()
            ->assertJsonPath('data.status', 'cancelada');
    }

    public function test_cancelar_doacao_ja_cancelada_falha(): void
    {
        $admin  = User::factory()->create(['role' => 'admin']);
        $doacao = Doacao::create([
            'user_id' => $this->cidadao->id, 'tipo_material' => 'plastico',
            'quantidade_kg' => 1, 'status' => 'cancelada',
        ]);

        $response = $this->actingAs($admin)->patchJson("/api/v1/doacoes/{$doacao->id}/cancelar");

        $response->assertStatus(422)
            ->assertJsonValidationErrors(['status']);
    }

    public function test_usuario_comum_nao_pode_listar_todas(): void
    {
        $this->actingAs($this->cidadao)->getJson('/api/v1/doacoes')
            ->assertStatus(403);
    }

    public function test_usuario_comum_nao_pode_confirmar(): void
    {
        $doacao = Doacao::create([
            'user_id' => $this->cidadao->id, 'tipo_material' => 'plastico',
            'quantidade_kg' => 1, 'status' => 'pendente',
        ]);

        $this->actingAs($this->cidadao)->patchJson("/api/v1/doacoes/{$doacao->id}/confirmar")
            ->assertStatus(403);
    }

    public function test_doacao_nao_autenticado(): void
    {
        $this->postJson('/api/v1/doacoes', [
            'tipo_material' => 'plastico', 'quantidade_kg' => 1,
        ])->assertStatus(401);
    }
}
