<?php

use App\Enums\WorkoutSource;
use App\Models\User;
use App\Models\WorkoutSessions;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Laravel\Sanctum\Sanctum;

uses(RefreshDatabase::class);

it('creates a workout for the authenticated user', function () {
    $user = User::factory()->create();

    Sanctum::actingAs($user);

    $response = $this->postJson('/api/workouts', [
        'external_id' => 'apple-workout-1',
        'source' => WorkoutSource::APPLE_HEALTH->value,
        'type' => 'running',
        'title' => 'Morning run',
        'duration_seconds' => 1800,
        'calories_burned' => 450,
        'distance_meters' => 5200,
        'started_at' => '2026-05-19T07:30:00.000Z',
    ]);

    $response
        ->assertCreated()
        ->assertJsonPath('data.externalId', 'apple-workout-1')
        ->assertJsonPath('data.source', WorkoutSource::APPLE_HEALTH->value)
        ->assertJsonPath('data.type', 'running')
        ->assertJsonPath('data.title', 'Morning run')
        ->assertJsonPath('data.durationSeconds', 1800)
        ->assertJsonPath('data.caloriesBurned', 450)
        ->assertJsonPath('data.distanceMeters', 5200);

    $this->assertDatabaseHas('workout_sessions', [
        'id' => $response->json('data.id'),
        'user_id' => $user->id,
        'external_id' => 'apple-workout-1',
        'source' => WorkoutSource::APPLE_HEALTH->value,
        'type' => 'running',
        'title' => 'Morning run',
        'duration_seconds' => 1800,
        'calories_burned' => 450,
        'distance_meters' => 5200,
    ]);
});

it('returns workouts for the authenticated user', function () {
    $user = User::factory()->create();
    $otherUser = User::factory()->create();

    $oldWorkoutSession = WorkoutSessions::factory()->for($user, 'user')->create([
        'external_id' => 'manual-1',
        'source' => WorkoutSource::MANUAL,
        'type' => 'strength',
        'title' => 'Upper body',
        'duration_seconds' => 2400,
        'calories_burned' => 320,
        'distance_meters' => 0,
        'started_at' => '2026-05-18 10:00:00',
    ]);
    $latestWorkoutSession = WorkoutSessions::factory()->for($user, 'user')->create([
        'external_id' => 'apple-1',
        'source' => WorkoutSource::APPLE_HEALTH,
        'type' => 'running',
        'title' => 'Morning run',
        'duration_seconds' => 1800,
        'calories_burned' => 450,
        'distance_meters' => 5200,
        'started_at' => '2026-05-19 07:30:00',
    ]);
    $otherWorkoutSession = WorkoutSessions::factory()->for($otherUser, 'user')->create([
        'title' => 'Hidden workout',
        'started_at' => '2026-05-20 07:30:00',
    ]);

    Sanctum::actingAs($user);

    $response = $this->getJson('/api/workouts');

    $response
        ->assertOk()
        ->assertJsonCount(2, 'data')
        ->assertJsonPath('data.0.id', $latestWorkoutSession->id)
        ->assertJsonPath('data.0.externalId', 'apple-1')
        ->assertJsonPath('data.0.source', WorkoutSource::APPLE_HEALTH->value)
        ->assertJsonPath('data.0.type', 'running')
        ->assertJsonPath('data.0.title', 'Morning run')
        ->assertJsonPath('data.0.durationSeconds', 1800)
        ->assertJsonPath('data.0.caloriesBurned', 450)
        ->assertJsonPath('data.0.distanceMeters', 5200)
        ->assertJsonPath('data.1.id', $oldWorkoutSession->id)
        ->assertJsonMissing([
            'id' => $otherWorkoutSession->id,
        ]);
});

it('filters workouts by date', function () {
    $user = User::factory()->create();

    $todayWorkoutSession = WorkoutSessions::factory()->for($user, 'user')->create([
        'calories_burned' => 450,
        'started_at' => '2026-05-19 07:30:00',
    ]);
    $eveningWorkoutSession = WorkoutSessions::factory()->for($user, 'user')->create([
        'calories_burned' => 120,
        'started_at' => '2026-05-19 19:30:00',
    ]);
    $yesterdayWorkoutSession = WorkoutSessions::factory()->for($user, 'user')->create([
        'calories_burned' => 320,
        'started_at' => '2026-05-18 10:00:00',
    ]);

    Sanctum::actingAs($user);

    $response = $this->getJson('/api/workouts?date=2026-05-19');

    $response
        ->assertOk()
        ->assertJsonCount(2, 'data')
        ->assertJsonPath('data.0.id', $eveningWorkoutSession->id)
        ->assertJsonPath('data.1.id', $todayWorkoutSession->id)
        ->assertJsonMissing([
            'id' => $yesterdayWorkoutSession->id,
        ]);
});

it('validates the workouts pagination size', function () {
    Sanctum::actingAs(User::factory()->create());

    $this
        ->getJson('/api/workouts?per_page=101')
        ->assertUnprocessable()
        ->assertJsonValidationErrors(['per_page']);
});

it('validates the workouts date filter', function () {
    Sanctum::actingAs(User::factory()->create());

    $this
        ->getJson('/api/workouts?date=2026-13-01')
        ->assertUnprocessable()
        ->assertJsonValidationErrors(['date']);
});

it('validates workout creation data', function () {
    Sanctum::actingAs(User::factory()->create());

    $this
        ->postJson('/api/workouts', [
            'source' => 'invalid',
            'type' => '',
            'title' => '',
            'duration_seconds' => 0,
            'calories_burned' => -1,
            'distance_meters' => -1,
            'started_at' => 'not-a-date',
        ])
        ->assertUnprocessable()
        ->assertJsonValidationErrors([
            'source',
            'type',
            'title',
            'duration_seconds',
            'calories_burned',
            'distance_meters',
            'started_at',
        ]);
});

it('validates workout external ids per source', function () {
    $user = User::factory()->create();

    WorkoutSessions::factory()->create([
        'external_id' => 'manual-1',
        'source' => WorkoutSource::MANUAL,
    ]);

    Sanctum::actingAs($user);

    $this
        ->postJson('/api/workouts', [
            'external_id' => 'manual-1',
            'source' => WorkoutSource::MANUAL->value,
            'type' => 'running',
            'title' => 'Morning run',
            'duration_seconds' => 1800,
            'calories_burned' => 450,
            'distance_meters' => 5200,
        ])
        ->assertUnprocessable()
        ->assertJsonValidationErrors(['external_id']);
});
