<?php

namespace Tests\Feature\V2\Dashboard\RoadItemsProject;

use App\Models\City;
use App\Models\EdarateOstani;
use App\Models\EdarateShahri;
use App\Models\InfoItem;
use App\Models\LogList;
use App\Models\ObservedItem;
use App\Models\Permission;
use App\Models\Province;
use App\Models\User;
use App\Models\UserActivityLog;
use App\Services\NominatimService;
use Illuminate\Foundation\Testing\RefreshDataBase;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Illuminate\Validation\ValidationException;
use Mockery\MockInterface;
use Tests\TestCase;

class StoreTest extends TestCase
{
    use RefreshDataBase;
    /**
     * A basic feature test example.
     */
    public function test_user_should_have_create_road_item_permission(): void
    {
        $user = User::factory()->create();

        $response = $this->actingAs($user)->postJson('/v2/road_items/operator/store');

        $response->assertForbidden();
    }

    public function test_user_should_not_have_city_id(): void
    {
        $edarateOstani = EdarateOstani::factory()->create();

        $user = User::factory()
            ->has(Permission::factory([
                'name' => 'create-road-item'
            ]))
            ->create([
                'edarate_ostani_id' => $edarateOstani->id
            ]);

        $response = $this->actingAs($user)->postJson('/v2/road_items/operator/store');

        $response->assertStatus(400)
            ->assertExactJson([
                'message' => 'امکان ثبت فعالیت برای ادارات استانی و ستادی وجود ندارد!'
            ]);
    }

    public function test_user_should_not_have_edarate_shahri_id(): void
    {
        $city = City::factory()->create();

        $user = User::factory()
            ->has(Permission::factory([
                'name' => 'create-road-item'
            ]))
            ->create([
                'city_id' => $city->id
            ]);

        $response = $this->actingAs($user)->postJson('/v2/road_items/operator/store');

        $response->assertStatus(400)
            ->assertExactJson([
                'message' => 'اداره شهری برای شما در سامانه ثبت نشده است!'
            ]);
    }

    public function test_start_point_is_required(): void
    {
        $city = City::factory()->create();
        $edarateShari = EdarateShahri::factory()->create();

        $user = User::factory()
            ->has(Permission::factory([
                'name' => 'create-road-item'
            ]))
            ->create([
                'city_id' => $city->id,
                'edarate_shahri_id' => $edarateShari->id
            ]);

        $response = $this->actingAs($user)->postJson('/v2/road_items/operator/store');

        $response->assertUnprocessable()
            ->assertInvalid([
                'start_point' => __('validation.required', ['attribute' => 'start point'])
            ]);
    }

    public function test_item_id_is_required(): void
    {
        $city = City::factory()->create();
        $edarateShari = EdarateShahri::factory()->create();

        $user = User::factory()
            ->has(Permission::factory([
                'name' => 'create-road-item'
            ]))
            ->create([
                'city_id' => $city->id,
                'edarate_shahri_id' => $edarateShari->id
            ]);

        $response = $this->actingAs($user)->postJson('/v2/road_items/operator/store');

        $response->assertUnprocessable()
            ->assertInvalid([
                'item_id' => __('validation.required', ['attribute' => 'item id'])
            ]);
    }

    public function test_item_id_should_be_integer(): void
    {
        $city = City::factory()->create();
        $edarateShari = EdarateShahri::factory()->create();

        $user = User::factory()
            ->has(Permission::factory([
                'name' => 'create-road-item'
            ]))
            ->create([
                'city_id' => $city->id,
                'edarate_shahri_id' => $edarateShari->id
            ]);

        $response = $this->actingAs($user)->postJson('/v2/road_items/operator/store', [
            'item_id' => $this->faker->name
        ]);

        $response->assertUnprocessable()
            ->assertInvalid([
                'item_id' => __('validation.integer', ['attribute' => 'item id'])
            ]);
    }

    public function test_sub_item_id_is_required(): void
    {
        $city = City::factory()->create();
        $edarateShari = EdarateShahri::factory()->create();

        $user = User::factory()
            ->has(Permission::factory([
                'name' => 'create-road-item'
            ]))
            ->create([
                'city_id' => $city->id,
                'edarate_shahri_id' => $edarateShari->id
            ]);

        $response = $this->actingAs($user)->postJson('/v2/road_items/operator/store');

        $response->assertUnprocessable()
            ->assertInvalid([
                'sub_item_id' => __('validation.required', ['attribute' => 'sub item id'])
            ]);
    }

    public function test_sub_item_id_should_be_integer(): void
    {
        $city = City::factory()->create();
        $edarateShari = EdarateShahri::factory()->create();

        $user = User::factory()
            ->has(Permission::factory([
                'name' => 'create-road-item'
            ]))
            ->create([
                'city_id' => $city->id,
                'edarate_shahri_id' => $edarateShari->id
            ]);

        $response = $this->actingAs($user)->postJson('/v2/road_items/operator/store', [
            'sub_item_id' => $this->faker->name
        ]);

        $response->assertUnprocessable()
            ->assertInvalid([
                'sub_item_id' => __('validation.integer', ['attribute' => 'sub item id'])
            ]);
    }

    public function test_amount_is_required(): void
    {
        $city = City::factory()->create();
        $edarateShari = EdarateShahri::factory()->create();

        $user = User::factory()
            ->has(Permission::factory([
                'name' => 'create-road-item'
            ]))
            ->create([
                'city_id' => $city->id,
                'edarate_shahri_id' => $edarateShari->id
            ]);

        $response = $this->actingAs($user)->postJson('/v2/road_items/operator/store');

        $response->assertUnprocessable()
            ->assertInvalid([
                'amount' => __('validation.required', ['attribute' => 'amount'])
            ]);
    }

    public function test_amount_should_be_numeric(): void
    {
        $city = City::factory()->create();
        $edarateShari = EdarateShahri::factory()->create();

        $user = User::factory()
            ->has(Permission::factory([
                'name' => 'create-road-item'
            ]))
            ->create([
                'city_id' => $city->id,
                'edarate_shahri_id' => $edarateShari->id
            ]);

        $response = $this->actingAs($user)->postJson('/v2/road_items/operator/store', [
            'amount' => $this->faker->name
        ]);

        $response->assertUnprocessable()
            ->assertInvalid([
                'amount' => __('validation.numeric', ['attribute' => 'amount'])
            ]);
    }

    public function test_before_image_should_be_image(): void
    {
        $city = City::factory()->create();
        $edarateShari = EdarateShahri::factory()->create();

        $user = User::factory()
            ->has(Permission::factory([
                'name' => 'create-road-item'
            ]))
            ->create([
                'city_id' => $city->id,
                'edarate_shahri_id' => $edarateShari->id
            ]);

        $response = $this->actingAs($user)->postJson('/v2/road_items/operator/store', [
            'before_image' => $this->faker->randomNumber()
        ]);

        $response->assertUnprocessable()
            ->assertInvalid([
                'before_image' => __('validation.image', ['attribute' => 'before image'])
            ]);
    }

    public function test_before_image_should_be_less_than_4096kb(): void
    {
        $city = City::factory()->create();
        $edarateShari = EdarateShahri::factory()->create();

        $user = User::factory()
            ->has(Permission::factory([
                'name' => 'create-road-item'
            ]))
            ->create([
                'city_id' => $city->id,
                'edarate_shahri_id' => $edarateShari->id
            ]);

        $image = UploadedFile::fake()->create('image.jpg', 5096);

        $response = $this->actingAs($user)->postJson('/v2/road_items/operator/store', [
            'before_image' => $image
        ]);

        $response->assertUnprocessable()
            ->assertInvalid([
                'before_image' => __('validation.max.file', ['attribute' => 'before image', 'max' => 4096])
            ]);
    }

    public function test_after_image_should_be_image(): void
    {
        $city = City::factory()->create();
        $edarateShari = EdarateShahri::factory()->create();

        $user = User::factory()
            ->has(Permission::factory([
                'name' => 'create-road-item'
            ]))
            ->create([
                'city_id' => $city->id,
                'edarate_shahri_id' => $edarateShari->id
            ]);

        $response = $this->actingAs($user)->postJson('/v2/road_items/operator/store', [
            'after_image' => $this->faker->randomNumber()
        ]);

        $response->assertUnprocessable()
            ->assertInvalid([
                'after_image' => __('validation.image', ['attribute' => 'after image'])
            ]);
    }

    public function test_after_image_should_be_less_than_4096kb(): void
    {
        $city = City::factory()->create();
        $edarateShari = EdarateShahri::factory()->create();

        $user = User::factory()
            ->has(Permission::factory([
                'name' => 'create-road-item'
            ]))
            ->create([
                'city_id' => $city->id,
                'edarate_shahri_id' => $edarateShari->id
            ]);

        $image = UploadedFile::fake()->create('image.jpg', 5096);

        $response = $this->actingAs($user)->postJson('/v2/road_items/operator/store', [
            'after_image' => $image
        ]);

        $response->assertUnprocessable()
            ->assertInvalid([
                'after_image' => __('validation.max.file', ['attribute' => 'after image', 'max' => 4096])
            ]);
    }

    public function test_observed_item_id_should_be_integer(): void
    {
        $city = City::factory()->create();
        $edarateShari = EdarateShahri::factory()->create();

        $user = User::factory()
            ->has(Permission::factory([
                'name' => 'create-road-item'
            ]))
            ->create([
                'city_id' => $city->id,
                'edarate_shahri_id' => $edarateShari->id
            ]);

        $response = $this->actingAs($user)->postJson('/v2/road_items/operator/store', [
            'observed_item_id' => $this->faker->name
        ]);

        $response->assertUnprocessable()
            ->assertInvalid([
                'observed_item_id' => __('validation.integer', ['attribute' => 'observed item id'])
            ]);
    }

    public function test_observed_item_id_should_be_existed_in_db(): void
    {
        $city = City::factory()->create();
        $edarateShari = EdarateShahri::factory()->create();
        $observedItem = ObservedItem::factory()->create();

        $user = User::factory()
            ->has(Permission::factory([
                'name' => 'create-road-item'
            ]))
            ->create([
                'city_id' => $city->id,
                'edarate_shahri_id' => $edarateShari->id
            ]);

        $response = $this->actingAs($user)->postJson('/v2/road_items/operator/store', [
            'observed_item_id' => $this->faker->numberBetween(10, 20)
        ]);

        $response->assertUnprocessable()
            ->assertInvalid([
                'observed_item_id' => __('validation.exists', ['attribute' => 'observed item id'])
            ]);
    }

    public function test_activity_date_is_required(): void
    {
        $city = City::factory()->create();
        $edarateShari = EdarateShahri::factory()->create();

        $user = User::factory()
            ->has(Permission::factory([
                'name' => 'create-road-item'
            ]))
            ->create([
                'city_id' => $city->id,
                'edarate_shahri_id' => $edarateShari->id
            ]);

        $response = $this->actingAs($user)->postJson('/v2/road_items/operator/store');

        $response->assertUnprocessable()
            ->assertInvalid([
                'activity_date' => __('validation.required', ['attribute' => 'تاریخ فعالیت'])
            ]);
    }

    public function test_activity_date_should_match_the_format(): void
    {
        $city = City::factory()->create();
        $edarateShari = EdarateShahri::factory()->create();

        $user = User::factory()
            ->has(Permission::factory([
                'name' => 'create-road-item'
            ]))
            ->create([
                'city_id' => $city->id,
                'edarate_shahri_id' => $edarateShari->id
            ]);

        $response = $this->actingAs($user)->postJson('/v2/road_items/operator/store', [
            'activity_date' => $this->faker->date('d-m-Y-H-i-s')
        ]);

        $response->assertUnprocessable()
            ->assertInvalid([
                'activity_date' => __('validation.date_format', ['attribute' => 'تاریخ فعالیت', 'format' => 'Y-m-d'])
            ]);
    }

    public function test_activity_time_is_required(): void
    {
        $city = City::factory()->create();
        $edarateShari = EdarateShahri::factory()->create();

        $user = User::factory()
            ->has(Permission::factory([
                'name' => 'create-road-item'
            ]))
            ->create([
                'city_id' => $city->id,
                'edarate_shahri_id' => $edarateShari->id
            ]);

        $response = $this->actingAs($user)->postJson('/v2/road_items/operator/store');

        $response->assertUnprocessable()
            ->assertInvalid([
                'activity_time' => __('validation.required', ['attribute' => 'ساعت فعالیت'])
            ]);
    }

    public function test_activity_time_should_match_the_format(): void
    {
        $city = City::factory()->create();
        $edarateShari = EdarateShahri::factory()->create();

        $user = User::factory()
            ->has(Permission::factory([
                'name' => 'create-road-item'
            ]))
            ->create([
                'city_id' => $city->id,
                'edarate_shahri_id' => $edarateShari->id
            ]);

        $response = $this->actingAs($user)->postJson('/v2/road_items/operator/store', [
            'activity_time' => $this->faker->date('d-m-Y-H-i-s')
        ]);

        $response->assertUnprocessable()
            ->assertInvalid([
                'activity_time' => __('validation.date_format', ['attribute' => 'ساعت فعالیت', 'format' => 'H:i'])
            ]);
    }

    public function test_validation_exception_will_throw_if_needs_end_point_is_not_null(): void
    {
        $city = City::factory()->create();
        $edarateShari = EdarateShahri::factory()->create();
        $item_id = $this->faker->numberBetween(1, 10);
        $sub_item_id = $this->faker->numberBetween(1, 10);
        $infoItem = InfoItem::factory()->create([
            'item' => $item_id,
            'sub_item' => $sub_item_id,
            'needs_end_point' => $this->faker->numberBetween(1, 10)
        ]);

        $user = User::factory()
            ->has(Permission::factory([
                'name' => 'create-road-item'
            ]))
            ->create([
                'city_id' => $city->id,
                'edarate_shahri_id' => $edarateShari->id
            ]);

        $response = $this->actingAs($user)->postJson('/v2/road_items/operator/store', [
            'start_point' => $this->faker->randomNumber(),
            'item_id' => $item_id,
            'sub_item_id' => $sub_item_id,
            'amount' => $this->faker->numberBetween(1, 10),
            'activity_date' => $this->faker->date(),
            'activity_time' => $this->faker->date('H:i'),
        ]);

        $response->assertUnprocessable()
            ->assertInvalid([
                'end_point' => __('validation.required', ['attribute' => 'end_point'])
            ]);
    }

    public function test_validation_exception_will_throw_if_needs_image_is_not_null(): void
    {
        $city = City::factory()->create();
        $edarateShari = EdarateShahri::factory()->create();
        $item_id = $this->faker->numberBetween(1, 10);
        $sub_item_id = $this->faker->numberBetween(1, 10);
        $infoItem = InfoItem::factory()->create([
            'item' => $item_id,
            'sub_item' => $sub_item_id,
            'needs_image' => $this->faker->numberBetween(1, 10)
        ]);

        $user = User::factory()
            ->has(Permission::factory([
                'name' => 'create-road-item'
            ]))
            ->create([
                'city_id' => $city->id,
                'edarate_shahri_id' => $edarateShari->id
            ]);

        $response = $this->actingAs($user)->postJson('/v2/road_items/operator/store', [
            'start_point' => $this->faker->randomNumber(),
            'item_id' => $item_id,
            'sub_item_id' => $sub_item_id,
            'amount' => $this->faker->numberBetween(1, 10),
            'activity_date' => $this->faker->date(),
            'activity_time' => $this->faker->date('H:i'),
        ]);

        $response->assertUnprocessable()
            ->assertInvalid([
                'before_image' => __('validation.required', ['attribute' => 'before_image'])
            ]);

        $response->assertUnprocessable()
            ->assertInvalid([
                'after_image' => __('validation.required', ['attribute' => 'after_image'])
            ]);
    }

    public function test_can_store_a_new_road_item_project(): void
    {
        $city = City::factory()->create();
        $province = Province::factory()->create();
        $edarateShari = EdarateShahri::factory()->create();
        $item_id = $this->faker->numberBetween(1, 10);
        $sub_item_id = $this->faker->numberBetween(1, 10);
        $infoItem = InfoItem::factory()->create([
            'item' => $item_id,
            'sub_item' => $sub_item_id,
            'needs_image' => 1
        ]);

        $logList = LogList::factory()->create([
            'log_unique_code' => 1154
        ]);
        $userActivityLog = UserActivityLog::factory()->create();

        $user = User::factory()
            ->has(Permission::factory([
                'name' => 'create-road-item'
            ]))
            ->create([
                'city_id' => $city->id,
                'province_id' => $province->id,
                'edarate_shahri_id' => $edarateShari->id
            ]);

        $before_image = UploadedFile::fake()->create('image.jpg', 10);
        $after_image = UploadedFile::fake()->create('image.jpg', 10);

        Storage::fake();

        $mock = $this->mock(NominatimService::class, function (MockInterface $mock) {
            $mock->shouldReceive('get_way_id_from_nominatim')
                ->once()
                ->andReturn(0);
        });

        $response = $this->actingAs($user)->postJson('/v2/road_items/operator/store', [
            'start_point' => '12,12',
            'item_id' => $item_id,
            'sub_item_id' => $sub_item_id,
            'amount' => $this->faker->numberBetween(1, 10),
            'activity_date' => $this->faker->date(),
            'activity_time' => $this->faker->date('H:i'),
            'before_image' => $before_image,
            'after_image' => $after_image
        ]);

        $response->assertOk()
            ->assertExactJson([
                'message' => 'succussful'
            ]);

        $this->assertDatabaseHas('road_items_projects', [
            'start_lat' => 12,
            'start_lng' => 12,
            'item' => $item_id,
            'sub_item' => $sub_item_id,
            'province_id' => $province->id,
            'city_id' => $city->id,
            'user_name' => $user->name,
            'start_way_id' => 0,
            'info_id' => $infoItem->id,
            'status' => 0,
            'status_fa' => 'در حال بررسی',
            'edarat_id' => $user->edarate_shahri_id,
        ]);
    }
}
