<?php

namespace App\Doctor\Service\Repair;

use App\Doctor\Entity\Doctor;
use App\Location\Entity\City;
use App\Shared\Util\PersianText;
use App\Specialty\Entity\Specialty;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

/**
 * گزارش خوشه‌های پزشکِ **مشکوک به تکراری** برای بازبینی دستی — هرگز ادغام خودکار نمی‌کند.
 *
 * معیار: نام نرمال‌شدهٔ یکسان + دست‌کم یک تخصص مشترک + دست‌کم یک شهر مشترک، ولی
 * source_profile_id (شناسهٔ authoritative نظام پزشکی) متفاوت. متفاوت بودن این شناسه یعنی
 * irimc آن‌ها را دو پروفایل جدا می‌داند؛ ممکن است دو نفر واقعی باشند، پس تصمیمِ ادغام
 * انسانی است. این گام فقط داده تغییر نمی‌دهد (changed=0).
 */
final class ReportSuspectedDuplicatesStep implements DoctorRepairStep
{
    public function __construct(private readonly EntityManagerInterface $em)
    {
    }

    public function name(): string
    {
        return 'report-suspected-duplicates';
    }

    public function description(): string
    {
        return 'گزارش خوشه‌های مشکوک به تکراری (بدون ادغام — فقط بازبینی دستی)';
    }

    public function run(RepairOptions $options, SymfonyStyle $io): RepairResult
    {
        $qb = $this->em->getRepository(Doctor::class)->createQueryBuilder('d');
        if (!$options->allSources) {
            $qb->andWhere('d.source = :src')->setParameter('src', 'irimc');
        }
        /** @var Doctor[] $doctors */
        $doctors = $qb->getQuery()->getResult();

        // خوشه‌بندی بر نام نرمال‌شده — normalize در DB ممکن نیست، پس در PHP.
        $byName = [];
        foreach ($doctors as $doctor) {
            $byName[PersianText::normalize($doctor->getName())][] = $doctor;
        }

        $ids = static fn (iterable $coll): array => array_map(
            static fn ($e) => $e->getId(),
            $coll instanceof \Traversable ? iterator_to_array($coll) : (array) $coll,
        );

        $clusters = 0;
        $suspected = 0;
        foreach ($byName as $group) {
            if (count($group) < 2) {
                continue;
            }
            // زوج‌های همان نام که تخصص و شهر مشترک دارند ولی شناسهٔ پروفایل متفاوت.
            $flagged = [];
            for ($i = 0; $i < count($group); $i++) {
                for ($j = $i + 1; $j < count($group); $j++) {
                    $a = $group[$i];
                    $b = $group[$j];
                    if ($a->getSourceProfileId() !== null
                        && $a->getSourceProfileId() === $b->getSourceProfileId()) {
                        continue; // همان پروفایل — dedup باید مهارش کند، تکراری مشکوک نیست
                    }
                    $specOverlap = array_intersect($ids($a->getSpecialties()), $ids($b->getSpecialties()));
                    $cityOverlap = array_intersect($ids($a->getCities()), $ids($b->getCities()));
                    if ($specOverlap !== [] && $cityOverlap !== []) {
                        $flagged[$a->getId()] = $a;
                        $flagged[$b->getId()] = $b;
                    }
                }
            }
            if ($flagged === []) {
                continue;
            }
            $clusters++;
            $suspected += count($flagged);
            $io->section(sprintf('«%s» — %d رکورد مشکوک', $group[0]->getName(), count($flagged)));
            $rows = [];
            foreach ($flagged as $doctor) {
                $rows[] = [
                    $doctor->getId(),
                    $doctor->getMedicalSystemCode(),
                    $doctor->getSourceProfileId() ?? '—',
                    implode('، ', array_map(static fn (Specialty $s) => $s->getName(), $doctor->getSpecialties()->toArray())),
                    implode('، ', array_map(static fn (City $c) => $c->getName(), $doctor->getCities()->toArray())),
                ];
            }
            $io->table(['#', 'کد نظام', 'profile_id', 'تخصص', 'شهر'], $rows);
        }

        return new RepairResult(
            scanned: count($doctors),
            changed: 0,
            skipped: $suspected,
            note: $suspected > 0
                ? "$suspected رکورد در $clusters خوشه — بازبینی دستی لازم، ادغام خودکار نشد"
                : 'خوشهٔ مشکوکی یافت نشد',
        );
    }
}
