<?php

namespace App\Resource\Service;

use App\Auth\Entity\User;
use App\Resource\Entity\ClinicResource;
use App\Resource\Entity\ResourcePool;
use App\Resource\Entity\ResourcePoolMember;
use App\Resource\Repository\ResourcePoolMemberRepository;
use App\Shared\Constant\ErrorCodes;
use App\Shared\Exception\AppException;
use Doctrine\ORM\EntityManagerInterface;

final class ResourcePoolService
{
    public function __construct(
        private readonly ResourcePoolMemberRepository $members,
        private readonly ResourceContext              $context,
        private readonly EntityManagerInterface       $em,
    ) {}

    /**
     * جایگزینی کامل اعضای استخر.
     *
     * هر عضو باید **همان شعبه و همان نوع** استخر را داشته باشد. تسک ۰۶ فرض می‌کند هر
     * عضو جایگزین کامل دیگری است: عضوی از شعبهٔ دیگر یعنی بیمار در ساختمان اشتباه
     * می‌ایستد، و عضوی از نوع دیگر یعنی صندلی به‌جای دستگاه لیزر پیشنهاد می‌شود.
     *
     * @param array<int, mixed> $rows
     * @return ResourcePoolMember[]
     */
    public function replaceMembers(User $user, ResourcePool $pool, array $rows): array
    {
        $validated = $this->validate($user, $pool, $rows);

        $this->members->deleteForPool($pool);
        $pool->getMembers()->clear();

        $created = [];
        foreach ($validated as $row) {
            $member = new ResourcePoolMember($pool, $row['resource'], $row['priority']);
            $this->em->persist($member);
            $pool->getMembers()->add($member);
            $created[] = $member;
        }

        $pool->touch();
        $this->em->flush();

        return $created;
    }

    /**
     * @param array<int, mixed> $rows
     * @return list<array{resource: ClinicResource, priority: int}>
     */
    private function validate(User $user, ResourcePool $pool, array $rows): array
    {
        $seen = [];
        $out  = [];

        foreach ($rows as $index => $row) {
            $uuid = is_array($row) ? ($row['resource_uuid'] ?? null) : $row;

            if (!is_string($uuid) || $uuid === '') {
                throw new AppException(ErrorCodes::ERR_VALIDATION_002, 'فیلد resource_uuid الزامی است', 422, 'resource_uuid');
            }

            if (isset($seen[$uuid])) {
                throw new AppException(ErrorCodes::ERR_VALIDATION_001, 'یک منبع دو بار فرستاده شده است', 422, 'resource_uuid');
            }
            $seen[$uuid] = true;

            $resource = $this->context->resource($user, $uuid);

            if ($resource->getAddress()->getId() !== $pool->getAddress()->getId()) {
                throw new AppException(
                    ErrorCodes::ERR_VALIDATION_001,
                    'همهٔ اعضای استخر باید در یک شعبه باشند',
                    422,
                    'resource_uuid',
                );
            }

            if ($resource->getType()->getId() !== $pool->getType()->getId()) {
                throw new AppException(
                    ErrorCodes::ERR_VALIDATION_001,
                    'همهٔ اعضای استخر باید از یک نوع منبع باشند',
                    422,
                    'resource_uuid',
                );
            }

            $priority = is_array($row) ? ($row['priority'] ?? $index) : $index;

            if (!is_numeric($priority)) {
                throw new AppException(ErrorCodes::ERR_VALIDATION_001, 'اولویت باید عدد باشد', 422, 'priority');
            }

            $out[] = ['resource' => $resource, 'priority' => (int) $priority];
        }

        return $out;
    }
}
