<?php

namespace App\Patient\Service;

use App\Auth\Entity\User;
use App\Auth\Repository\UserRepository;
use App\Shared\Constant\ErrorCodes;
use App\Shared\Exception\AppException;
use App\UserProfile\Entity\UserProfile;
use App\UserProfile\Repository\UserProfileRepository;

/**
 * Resolves (or creates) the patient User for an admin-side booking.
 *
 * Identity key is the national code, which is stored on the patient's
 * UserProfile (unique per person — profiles.national_code). Mobile is only a
 * contact detail; one national code may be booked under several mobiles, so
 * lookup prefers the national code and never overwrites an existing mobile.
 * Keeping resolution here (not duplicated in each controller) keeps the
 * case-file (PatientRecord, keyed on user_id) unique per national code.
 */
class PatientResolver
{
    public function __construct(
        private readonly UserRepository        $userRepo,
        private readonly UserProfileRepository $profileRepo,
    ) {}

    /**
     * @param string $nationalCode already normalized to English digits and validated
     */
    public function resolveForBooking(string $nationalCode, string $mobile, string $name): User
    {
        // 1) National code lives on the profile and is unique — the real identity.
        $profile = $this->profileRepo->findOneByNationalCode($nationalCode);
        if ($profile !== null) {
            $user = $profile->getUser();
            $this->fillNameIfEmpty($user, $name);
            return $user;
        }

        // 2) Fall back to mobile; bind the national code to that patient's profile.
        $user = $this->userRepo->findByMobile($mobile);
        if ($user !== null) {
            $profile  = $this->profileRepo->findByUser($user);
            $existing = $profile?->getNationalCode();
            if ($existing !== null && $existing !== $nationalCode) {
                throw new AppException(ErrorCodes::ERR_PROFILE_MOBILE_TAKEN, 'این شماره موبایل با کد ملی دیگری ثبت شده است', 422, 'patient_mobile');
            }
            if ($existing === null) {
                $this->bindNationalCode($profile ?? new UserProfile($user), $nationalCode);
            }
            $this->fillNameIfEmpty($user, $name);
            return $user;
        }

        // 3) New patient: create the user and its profile carrying the national code.
        $user = new User($mobile);
        $user->setRealName($name);
        $user->setRoles(['ROLE_USER']);
        $this->userRepo->save($user, false);

        $this->bindNationalCode(new UserProfile($user), $nationalCode);

        return $user;
    }

    private function bindNationalCode(UserProfile $profile, string $nationalCode): void
    {
        $profile->setNationalCode($nationalCode);
        $this->profileRepo->save($profile, false);
    }

    private function fillNameIfEmpty(User $user, string $name): void
    {
        if (($user->getRealName() ?? '') === '' && $name !== '') {
            $user->setRealName($name);
        }
    }
}
