<?php

namespace Tests\Feature;

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

class AuthTest extends TestCase
{
    use RefreshDatabase;

    // ── Request OTP ──────────────────────────────────────────────────────────

    public function test_request_otp_creates_code_and_returns_phone(): void
    {
        $res = $this->postJson('/api/auth/request-otp', ['phone' => '0712345678']);

        $res->assertOk()
            ->assertJsonStructure(['message', 'phone']);

        $this->assertDatabaseHas('otp_codes', ['phone' => '+255712345678', 'is_used' => false]);
    }

    public function test_request_otp_normalises_tanzanian_number(): void
    {
        $this->postJson('/api/auth/request-otp', ['phone' => '0755000001'])
            ->assertOk()
            ->assertJsonPath('phone', '+255755000001');
    }

    public function test_request_otp_invalidates_previous_codes(): void
    {
        OtpCode::factory()->create(['phone' => '+255712345678', 'is_used' => false]);

        $this->postJson('/api/auth/request-otp', ['phone' => '+255712345678']);

        $this->assertDatabaseCount('otp_codes', 1); // old deleted, new created
    }

    public function test_request_otp_rejects_short_phone(): void
    {
        $this->postJson('/api/auth/request-otp', ['phone' => '123'])
            ->assertUnprocessable();
    }

    // ── Demo phone ───────────────────────────────────────────────────────────

    public function test_demo_phone_skips_sms_and_returns_demo_flag(): void
    {
        $phone = config('app.demo_phone', env('DEMO_PHONE', '+25578312752'));

        $this->postJson('/api/auth/request-otp', ['phone' => $phone])
            ->assertOk()
            ->assertJsonPath('demo', true);

        // No OTP stored for demo phone
        $this->assertDatabaseCount('otp_codes', 0);
    }

    public function test_demo_phone_verifies_with_any_code(): void
    {
        $phone = config('app.demo_phone', env('DEMO_PHONE', '+25578312752'));

        $this->postJson('/api/auth/verify-otp', ['phone' => $phone, 'code' => '999999'])
            ->assertOk()
            ->assertJsonStructure(['token', 'user']);
    }

    public function test_demo_user_created_with_correct_defaults(): void
    {
        $phone = config('app.demo_phone', env('DEMO_PHONE', '+25578312752'));

        $this->postJson('/api/auth/verify-otp', ['phone' => $phone, 'code' => '000000']);

        $this->assertDatabaseHas('users', [
            'phone'       => $phone,
            'role'        => 'both',
            'is_verified' => true,
            'trip_credits' => 10,
        ]);
    }

    // ── Verify OTP ───────────────────────────────────────────────────────────

    public function test_verify_otp_returns_token_and_user(): void
    {
        $otp = OtpCode::factory()->create([
            'phone'      => '+255712345678',
            'code'       => '123456',
            'expires_at' => now()->addMinutes(5),
        ]);

        $res = $this->postJson('/api/auth/verify-otp', [
            'phone' => '+255712345678',
            'code'  => '123456',
        ]);

        $res->assertOk()
            ->assertJsonStructure(['token', 'user' => ['id', 'phone', 'role', 'trip_credits']]);

        $this->assertTrue($otp->fresh()->is_used);
    }

    public function test_verify_otp_creates_new_user_on_first_login(): void
    {
        OtpCode::factory()->create([
            'phone' => '+255700000001', 'code' => '111111',
            'expires_at' => now()->addMinutes(5),
        ]);

        $this->postJson('/api/auth/verify-otp', ['phone' => '+255700000001', 'code' => '111111']);

        $this->assertDatabaseHas('users', ['phone' => '+255700000001']);
    }

    public function test_verify_otp_rejects_wrong_code(): void
    {
        OtpCode::factory()->create([
            'phone' => '+255712345678', 'code' => '123456',
            'expires_at' => now()->addMinutes(5),
        ]);

        $this->postJson('/api/auth/verify-otp', ['phone' => '+255712345678', 'code' => '000000'])
            ->assertUnprocessable();
    }

    public function test_verify_otp_rejects_expired_code(): void
    {
        OtpCode::factory()->create([
            'phone' => '+255712345678', 'code' => '123456',
            'expires_at' => now()->subMinute(),
        ]);

        $this->postJson('/api/auth/verify-otp', ['phone' => '+255712345678', 'code' => '123456'])
            ->assertUnprocessable();
    }

    public function test_verify_otp_rejects_used_code(): void
    {
        OtpCode::factory()->create([
            'phone' => '+255712345678', 'code' => '123456',
            'expires_at' => now()->addMinutes(5), 'is_used' => true,
        ]);

        $this->postJson('/api/auth/verify-otp', ['phone' => '+255712345678', 'code' => '123456'])
            ->assertUnprocessable();
    }

    // ── Me / Logout ───────────────────────────────────────────────────────────

    public function test_me_returns_authenticated_user(): void
    {
        $user = User::factory()->create();

        $this->actingAs($user)->getJson('/api/auth/me')
            ->assertOk()
            ->assertJsonPath('user.id', $user->id);
    }

    public function test_me_requires_authentication(): void
    {
        $this->getJson('/api/auth/me')->assertUnauthorized();
    }

    public function test_logout_deletes_token(): void
    {
        $user  = User::factory()->create();
        $token = $user->createToken('mobile')->plainTextToken;

        $this->withToken($token)->postJson('/api/auth/logout')
            ->assertOk();

        // Token is removed from DB
        $this->assertDatabaseCount('personal_access_tokens', 0);

        // Token can no longer access protected routes (reset guard cache first)
        app('auth')->forgetGuards();
        $this->withToken($token)->getJson('/api/auth/me')
            ->assertUnauthorized();
    }
}
