<?php

namespace App\Tests\Resource;

class SkillAssignmentTest extends ResourceTestCase
{
    public function testSkillsAreReplacedWholesale(): void
    {
        [$user, , $address] = $this->clinicWithAddress();
        $resource = $this->createResource($user, $address, $this->resourceType($address));
        $laser    = $this->createSkill($user, 'لیزر آلکساندرایت');
        $botox    = $this->createSkill($user, 'بوتاکس');

        $withBoth = $this->authJson('PUT', "/api/v1/resource/{$resource['data']['uuid']}/skills", $user, [
            'skills' => [
                ['skill_uuid' => $laser['data']['uuid'], 'level' => 4],
                ['skill_uuid' => $botox['data']['uuid']],
            ],
        ]);

        self::assertSame(200, $this->responseCode(), json_encode($withBoth, JSON_UNESCAPED_UNICODE));
        self::assertCount(2, $withBoth['data']['skills']);
        self::assertSame(1, $withBoth['data']['skills'][1]['level'], 'سطح پیش‌فرض ۱ است');

        // PUT جایگزینی کامل است: مهارتی که نیامده، برداشته می‌شود.
        $onlyLaser = $this->authJson('PUT', "/api/v1/resource/{$resource['data']['uuid']}/skills", $user, [
            'skills' => [['skill_uuid' => $laser['data']['uuid'], 'level' => 5]],
        ]);

        self::assertCount(1, $onlyLaser['data']['skills']);
        self::assertSame($laser['data']['uuid'], $onlyLaser['data']['skills'][0]['skill_uuid']);
        self::assertSame(5, $onlyLaser['data']['skills'][0]['level']);
    }

    public function testEmptyListClearsAllSkills(): void
    {
        [$user, , $address] = $this->clinicWithAddress();
        $resource = $this->createResource($user, $address, $this->resourceType($address));
        $skill    = $this->createSkill($user);

        $this->authJson('PUT', "/api/v1/resource/{$resource['data']['uuid']}/skills", $user, [
            'skills' => [['skill_uuid' => $skill['data']['uuid']]],
        ]);

        $body = $this->authJson('PUT', "/api/v1/resource/{$resource['data']['uuid']}/skills", $user, ['skills' => []]);

        self::assertSame(200, $this->responseCode());
        self::assertSame([], $body['data']['skills']);
    }

    public function testLevelOutsideOneToFiveIsRejected(): void
    {
        [$user, , $address] = $this->clinicWithAddress();
        $resource = $this->createResource($user, $address, $this->resourceType($address));
        $skill    = $this->createSkill($user);

        foreach ([0, 6] as $level) {
            $body = $this->authJson('PUT', "/api/v1/resource/{$resource['data']['uuid']}/skills", $user, [
                'skills' => [['skill_uuid' => $skill['data']['uuid'], 'level' => $level]],
            ]);

            self::assertSame(422, $this->responseCode(), "level=$level باید رد شود");
            self::assertSame('level', $body['errors'][0]['field']);
        }
    }

    /**
     * اعتبارسنجی پیش از حذف: ورودی نامعتبر در انتهای فهرست نباید مهارت‌های درستِ
     * قبلی را پاک کند و بعد ۴۲۲ برگرداند.
     */
    public function testInvalidRowLeavesTheStoredSkillsUntouched(): void
    {
        [$user, , $address] = $this->clinicWithAddress();
        $resource = $this->createResource($user, $address, $this->resourceType($address));
        $laser    = $this->createSkill($user, 'لیزر');
        $botox    = $this->createSkill($user, 'بوتاکس');

        $this->authJson('PUT', "/api/v1/resource/{$resource['data']['uuid']}/skills", $user, [
            'skills' => [['skill_uuid' => $laser['data']['uuid'], 'level' => 3]],
        ]);

        $this->authJson('PUT', "/api/v1/resource/{$resource['data']['uuid']}/skills", $user, [
            'skills' => [
                ['skill_uuid' => $botox['data']['uuid']],
                ['skill_uuid' => $laser['data']['uuid'], 'level' => 99],
            ],
        ]);
        self::assertSame(422, $this->responseCode());

        $read = $this->authJson('GET', "/api/v1/resource/{$resource['data']['uuid']}", $user);
        self::assertCount(1, $read['data']['skills']);
        self::assertSame(3, $read['data']['skills'][0]['level']);
    }

    public function testDuplicateSkillInOnePayloadIsRejected(): void
    {
        [$user, , $address] = $this->clinicWithAddress();
        $resource = $this->createResource($user, $address, $this->resourceType($address));
        $skill    = $this->createSkill($user);

        $this->authJson('PUT', "/api/v1/resource/{$resource['data']['uuid']}/skills", $user, [
            'skills' => [
                ['skill_uuid' => $skill['data']['uuid']],
                ['skill_uuid' => $skill['data']['uuid'], 'level' => 2],
            ],
        ]);

        self::assertSame(422, $this->responseCode());
    }

    public function testForeignSkillIsNotFound(): void
    {
        [$user, , $address] = $this->clinicWithAddress();
        $resource = $this->createResource($user, $address, $this->resourceType($address));

        [$otherUser] = $this->clinicWithAddress('شعبهٔ دیگر');
        $foreignSkill = $this->createSkill($otherUser, 'مهارت بیگانه');

        $this->authJson('PUT', "/api/v1/resource/{$resource['data']['uuid']}/skills", $user, [
            'skills' => [['skill_uuid' => $foreignSkill['data']['uuid']]],
        ]);

        self::assertSame(404, $this->responseCode());
    }

    /** مهارتی که روی منبعی نشسته حذف نمی‌شود؛ وگرنه FK خطای خام دیتابیس می‌داد. */
    public function testSkillInUseCannotBeDeleted(): void
    {
        [$user, , $address] = $this->clinicWithAddress();
        $resource = $this->createResource($user, $address, $this->resourceType($address));
        $skill    = $this->createSkill($user);

        $this->authJson('PUT', "/api/v1/resource/{$resource['data']['uuid']}/skills", $user, [
            'skills' => [['skill_uuid' => $skill['data']['uuid']]],
        ]);

        $body = $this->authJson('DELETE', "/api/v1/skill/{$skill['data']['uuid']}", $user);
        self::assertSame(422, $this->responseCode());
        // رقم لاتین عمدی است: قرارداد پیام‌های درون‌ریزیِ بک‌اند همین است
        // (BackfillServiceDurationCommand، WorkingHoursService و …) و قالب‌بندی فارسی
        // کارِ نمایش در کلاینت است.
        self::assertStringContainsString('1 منبع', $body['errors'][0]['message']);

        // بعد از برداشتن از منبع، حذف مجاز است.
        $this->authJson('PUT', "/api/v1/resource/{$resource['data']['uuid']}/skills", $user, ['skills' => []]);
        $this->authJson('DELETE', "/api/v1/skill/{$skill['data']['uuid']}", $user);
        self::assertSame(200, $this->responseCode());
    }

    public function testSkillListReportsUsageCount(): void
    {
        [$user, , $address] = $this->clinicWithAddress();
        $resource = $this->createResource($user, $address, $this->resourceType($address));
        $skill    = $this->createSkill($user);

        $before = $this->authJson('GET', '/api/v1/skills', $user);
        self::assertSame(0, $before['data'][0]['resources_count']);

        $this->authJson('PUT', "/api/v1/resource/{$resource['data']['uuid']}/skills", $user, [
            'skills' => [['skill_uuid' => $skill['data']['uuid']]],
        ]);

        $after = $this->authJson('GET', '/api/v1/skills', $user);
        self::assertSame(1, $after['data'][0]['resources_count']);
    }

    public function testBlankSkillNameIsRejected(): void
    {
        [$user] = $this->clinicWithAddress();

        $body = $this->authJson('POST', '/api/v1/skills', $user, ['name' => '  ']);

        self::assertSame(422, $this->responseCode());
        self::assertSame('name', $body['errors'][0]['field']);
    }
}
