<?php

namespace App\Command;

use App\Entity\Interval;
use App\Entity\Filial;
use App\Entity\Department;
use App\Entity\Specialist;
use App\Entity\Location;
use App\Entity\Review;
use App\Entity\Schedule;
use App\Entity\Idoctor;
use App\Entity\Price;
use App\Bundle\Infoclinica\Rest;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\DependencyInjection\ContainerInterface;
use App\Bundle\Bitrix\Request as Bitrix;

class UploadDoctorsCommand extends Command
{
    private $container;

    public function __construct(ContainerInterface $container)
    {
        parent::__construct();
        $this->container = $container;
    }

    protected static $defaultName = 'app:UploadDoctors';
    protected static $defaultDescription = 'Обновление и загрузка Врачей';
    protected $io = null;
    protected $bitrix = null;
    protected $entityManager = null;
    private $countPersisted;

    protected function configure(): void
    {
        $this
            ->setDescription(self::$defaultDescription)
            ->addArgument('regionId', InputArgument::OPTIONAL, 'region id')
        ;
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $infoclinica = new Rest();
        $this->entityManager = $this->container->get('doctrine')->getManager();
        $this->io = new SymfonyStyle($input, $output);
        $regionId = $input->getArgument('regionId');
        $this->bitrix = (\App\Bundle\Bitrix\Request::init())->setRegionId($regionId);
        $doctors = $this->bitrix->getDoctors(true);

        $this->io->info('start updating:' . count($doctors));
        
        foreach ($doctors as $doctor) {
            $params = $this->loadInfoclinicaIds($doctor);
            if($this->ioError($params['docIds'], 'INFOCLINICA_ID_DOC is NULL', $doctor['ID'])) {
                $params['docIds'][] = trim($doctor['ID']);
            }

            if($this->ioError($params['docDeps'], 'INFOCLINICA_ID_DEP is NULL', $doctor['ID'])) {
                $params['docDeps'][] = 0;
            }

            if($this->ioError($params['docFilials'], 'INFOCLINICA_ID_FILIAL is NULL', $doctor['ID'])) {
                $params['docFilials'][] = 0;
            }

            if ($this->bitrix->docPropsCode($doctor['ID'], 'HIDE_TIMETABLE', false)) {
                $this->createUpdateForDoctor($doctor, $params);
            } else {
                $this->createUpdateForiDoctor($doctor, $params);
            }
            
        }

        $this->io->info('update rows:' . $this->countPersisted);
        $this->entityManager->flush(); 

        return Command::SUCCESS;
    }

    private function createUpdateForDoctor($doctor, $params)
    {
        $nearestDate = \date('d.m.Y');

        foreach ($params['docFilials'] as $filialId) {
            foreach ($params['docIds'] as $dcode) {
                foreach ($params['docDeps'] as $departmentId) {
                    $attrs = [
                        'name' => trim($doctor['NAME']),
                        'dcode' => $dcode,
                        'department' => $departmentId,
                        'filial' => $filialId,
                        'onlineMode' => 0,
                        'nearestDate' => $nearestDate,
                        'infoclinica' => false
                    ];

                    $this->addDoctor($doctor, $params, $attrs);
                }
            }
        }
    }

    private function createUpdateForiDoctor($doctor, $params)
    {
        $getIdoc = function($dcode, $deps) {
            $iDoctors = [];

            foreach ($deps as $departmentId) {
                $iDoctors[] = $this->entityManager->getRepository(Idoctor::class)
                    ->findOneBy([
                        'dcode' => $dcode,
                        'departmentId' => $departmentId,
                        'onlineMode' => 0
                    ]);
            }

            return $iDoctors;
        };

        foreach ($params['docIds'] as $dcode) {
            foreach ($getIdoc($dcode, $params['docDeps']) as $iDoctor) {
                if (!empty($iDoctor)) {
                    $attrs = [
                        'name' => $iDoctor->getName(),
                        'dcode' => $iDoctor->getDcode(),
                        'department' => $iDoctor->getDepartmentId(),
                        'filial' => $iDoctor->getFilialId(),
                        'onlineMode' => $iDoctor->getOnlineMode(),
                        'nearestDate' => $iDoctor->getNearestDate(),
                        'infoclinica' => true
                    ];

                   $this->addDoctor($doctor, $params, $attrs);
                }      
            }
        }
    }

    private function addDoctor($doctor, $params, $attrs)
    {
        $active = ($doctor['ACTIVE'] == 'Y')? true : false;

        if (empty($attrs['department']) || empty($attrs['filial'])) {
            $active = false;
        }

        $filial = $this->entityManager->getRepository(Filial::class)
            ->findOneBy(['fid' => $attrs['filial']]);

        if (is_null($filial)) {
            $filial = $this->entityManager->getRepository(Filial::class)
                ->findOneBy(['fid' => 0]);
        }

        $department = $this->entityManager->getRepository(Department::class)
            ->findOneBy(['did' => $attrs['department']]);

        if (is_null($department)) {
            $department = $this->entityManager->getRepository(Department::class)
                ->findOneBy(['did' => 0]);                
        }

        $locationSearch = ['dcode' => $attrs['dcode']];
        $locationSearch['department'] = $department;   
        $locationSearch['filial'] = $filial;   

        $locationEntity = $this->entityManager->getRepository(Location::class)
            ->findOneBy($locationSearch);

        if (is_null($locationEntity)) {
            $locationEntity = new Location();
        }
        
        $specialist = $this->entityManager->getRepository(Specialist::class)
            ->findByDcode($attrs['dcode']);

        if (is_null($specialist)) {
            $params['docIds'][] = trim($doctor['ID']);
            $specialist = new Specialist();
            $specialist->setDcode(json_encode($params['docIds'], JSON_FORCE_OBJECT));
        } else {
            $dcodes = json_decode($specialist->getDcode(), true);
            $dcodes[] = $doctor['ID'];
            $dcodes = array_unique($dcodes);
            $specialist->setDcode(json_encode($dcodes, JSON_FORCE_OBJECT));
        }
        
        $specialist = $this->setSpecialist($specialist, $doctor);
        $nearestDate = \DateTime::createFromFormat(
            'Y-m-d',
            date('Y-m-d', strtotime($attrs['nearestDate']))
        );

        $specialist
            ->setImg($doctor['ID'])
            ->setNearestDate($nearestDate)
            ->setInfoclinica($attrs['infoclinica']);

        $locationEntity
            ->setActive($active)
            ->setOnlineMode(0)
            ->setDcode($attrs['dcode']) 
            ->setFilial($filial)  
            ->setDepartment($department)
            ->setSpecialist($specialist);

        try {
            $this->countPersisted++;
            $this->entityManager->persist($locationEntity);
        } catch (Exception $e) {
            $this->io->error( $e->getMessage());
        }
        
    }

    private function setSpecialist($specialist, $doctor)
    {
        $specialist->setName(trim($doctor['NAME']))
            ->setAlias('')
        ;

        $post = $this->bitrix->docPropsCode($doctor['ID'], 'POST', false);

        if (! empty($post['VALUE'])) {
            $specialist->setSpeciality($post['VALUE']);
        }

        if (! empty($doctor['DETAIL_TEXT'])) {
            $specialist->setDescription($doctor['DETAIL_TEXT']);
        }

        $category = $this->bitrix->docPropsCode($doctor['ID'], 'CATEGORY', false);

        if (! empty($category['VALUE'])) {
            $specialist->setCategory(mb_strtolower(trim($category['VALUE'])));
        } 

        $kinder = $this->bitrix->docPropsCode($doctor['ID'], 'KIDS_AGE', false);

        if (! empty($kinder['VALUE'])) {
            $specialist->setKinder((int) $kinder['VALUE']);
        }
        
        $expirience = $this->bitrix->docPropsCode($doctor['ID'], 'EXPERIENCE', false);

        if (! empty($expirience['VALUE'])) {
            if (iconv_strlen($expirience['VALUE']) == 4) {
                $specialist->setExpirience(date('Y') - $expirience['VALUE']);
            } else {
                $specialist->setExpirience((int) $expirience['VALUE']);
            }
        }
        
        $linkPriceIds = $this->bitrix->docPropsCode($doctor['ID'], 'LINK_PRICE_1');

        if ($linkPriceIds) {
            foreach ($specialist->getPrices() as $delPrice) {
                $specialist->removePrice($delPrice);
            }

            foreach ($linkPriceIds as $linkPrice) {
                $price = $this->bitrix->docPropsCode($linkPrice['VALUE'], 'PRICE', false);

                if (! empty($price)) {
                    $priceEntity = $this->entityManager->getRepository(Price::class)
                        ->findOneBy(['propertyValueId' => (int) $price['ID']]);

                    if (! $priceEntity) {
                        $priceEntity = new Price();
                    }

                    if (! empty($price['BIE_NAME'])) {
                        $priceEntity
                            ->setName(trim($price['BIE_NAME']))
                            ->setValue((int) str_replace(',', '.', $price['VALUE']))
                            ->setDateUpdate(new \DateTime())
                            ->setPropertyValueId($price['ID'] . '.' . $doctor['ID']);
                        
                        $specialist->addPrice($priceEntity);
                    }
                }
            }   
        }

        return $specialist;
    }

    private function ioError($prop, $msg, $id, $continue = true)
    {
        if (empty($prop[0])) {
            return true;
        }
        
        return false;
    }

    private function loadInfoclinicaIds($doctor)
    {
        $data = [
            'docIds' => [], 
            'docDeps' => [],
            'docFilials' => []
        ];

        if (trim($doctor['XML_ID']) !== trim($doctor['ID'])) {
            $data['docIds'][] = preg_replace( '/[^0-9]/', '', $doctor['XML_ID']);
        }

        foreach ($this->bitrix->docPropsCode($doctor['ID'], 'INFOCLINICA_ID') as $prop) {
            $data['docIds'][] = preg_replace( '/[^0-9]/', '', $prop['VALUE']);
        }

        foreach ($this->bitrix->docPropsCode($doctor['ID'], 'DEPARTMENT_INFO') as $prop) {
            $data['docDeps'][] = preg_replace( '/[^0-9]/', '', $prop['VALUE']);
        }
        
        foreach ($this->bitrix->docPropsCode($doctor['ID'], 'INFOCLINICA_ID_DEP') as $prop) {
            $data['docDeps'][] = preg_replace( '/[^0-9]/', '', $prop['VALUE']);
        }

        foreach ($this->bitrix->docPropsCode($doctor['ID'], 'FILIAL_INFO') as $prop) {
            $data['docFilials'][] = preg_replace( '/[^0-9]/', '', $prop['VALUE']);
        }

        $data['docFilials'] = array_diff(array_unique($data['docFilials']), ['']);
        $data['docIds'] = array_diff(array_unique($data['docIds']), ['', 0, '0', '00']);
        $data['docDeps'] = array_diff(array_unique($data['docDeps']), ['']);
   
        return $data;
    }
}
