<?

namespace Shop\Services;

use Diamond\Services\Notify;
use Diamond\Services\Report;
use Shop\Config\Main;
use Shop\Contracts\CustomerComplexInterface;
use Shop\DTO\CustomerRequest;

/**
 * Description of Customer
 *
 * @author Admin
 */
class Customer implements \Diamond\Contracts\CustomerEmailFinderInterface
{
    static $currentShop;
    
    static $currentCustomer;

    protected $customerRepo;
    protected $mainConfig;
    protected $reportService;
    protected $notifyService;
    protected $authService;
    protected $shopService;

    function __construct(\Shop\Repositories\Customer $customerRepo, Main $mainConfig, Report $reportService,
                         Notify $notifyService, \Shop\Services\Auth $authService, \Shop\Services\Shop $shopService)
    {
        $this->customerRepo  = $customerRepo;
        $this->mainConfig    = $mainConfig;
        $this->reportService = $reportService;
        $this->notifyService = $notifyService;
        $this->authService   = $authService;
        $this->shopService   = $shopService;
    }
    
    /**
     * 
     */
    public function findEmailsAll(): array
    {
        $customers = \Shop\Models\Customer\CustomerQuery::create()
                ->find();
        $emails = [];
        
        foreach($customers as $customer){
            $emails[]=$customer->getEmail();
        }
        
        return $emails;
    }
    
    /**
     * получение клиентов офиса 1 группы 3
     * @todo перевести на другой миханизм, путем сохранения фильтров клиентов
     */
    public function findEmailsgroup3ClientsOffice1(): array
    {
        $customers = \Shop\Models\Customer\CustomerQuery::create()
                ->useManagerQuery()
                    ->filterByShopId(1)
                ->endUse()
                ->filterByGroupId(3)
                ->find();
        $emails = [];
        
        foreach($customers as $customer){
            $emails[]=$customer->getEmail();
        }
        
        return $emails;         
    }
    
    /**
     * 
     */
    public function findEmailsblockClients(): array
    {
        $customers = \Shop\Models\Customer\CustomerQuery::create()
                ->filterByBlocked("Y")
                ->find();
        $emails = [];
        
        foreach($customers as $customer){
            $emails[]=$customer->getEmail();
        }
        
        return $emails;        
    }

    /**
     * 
     * @param string $email
     * @return array
     */
    public function findClientDataByEmail(string $email): array
    {
        if(!$customer = \Shop\Models\Customer\CustomerQuery::create()
                ->findOneByEmail($email)){
            return [];
        }
        
        return $customer->toArray();
    }

    /**
     * @param string $email
     * @return \Shop\Models\Customer\Customer|null
     */
    public function findClientByEmail(string $email): ?\Shop\Models\Customer\Customer
    {
        if(!$customer = \Shop\Models\Customer\CustomerQuery::create()
            ->findOneByEmail($email)){
            return null;
        }

        return $customer;
    }
    
    /**
     * 
     * @return array
     */
    public function findEmailsNoneAuthClients(): array
    {
        $customers = \Shop\Models\Customer\CustomerQuery::create()
                ->filterByBlocked("N")
                ->filterByLastauth(null, \Propel\Runtime\ActiveQuery\Criteria::EQUAL)//=
                ->find();
        $emails = [];
        
        foreach($customers as $customer){
            $emails[]=$customer->getEmail();
        }
        
        return $emails;         
    }
    
    /**
     * 
     * @return array
     */
    public function findEmailsAuthClients(): array
    {
        $customers = \Shop\Models\Customer\CustomerQuery::create()
                ->filterByBlocked("N")
                ->filterByLastauth("", \Propel\Runtime\ActiveQuery\Criteria::GREATER_THAN)//>=
                ->find();
        $emails = [];
        
        foreach($customers as $customer){
            $emails[]=$customer->getEmail();
        }
        
        return $emails;         
    }    

    
    /**
     * 
     * @param type $name
     * @param type $email
     * @param type $phone
     * @param type $cityId
     * @return \Shop\Models\Customer\Customer
     * @deprecated
     * @see \Shop\Services\Customer::regstration
     */
    public function regstrationCustomer($name, $email, $phone, $cityId): \Shop\Models\Customer\Customer
    {

        $newCustomer = new \Shop\DTO\CustomerRequest(
                $name, $email, $this->mainConfig->getDefault_customer_category(), $phone, $cityId
        );

        return $this->registration($newCustomer);
    }

    /**
     * Получение офиса текущего клиента
     * @deprecated self::getCurrentShop
     * @return int
     */
    public function getCurrentShopId(): int
    {
        $shop = $this->getCurrentShop();

        return $shop->getId();
    }
    
    /**
     * 
     * @return int
     * @throws \RuntimeException
     */
    public function getCurrentShop(): \Shop\Models\Shop\Shop
    {

        if(isset(self::$currentShop)){
            return self::$currentShop;
        }        
        
        if ($customer = $this->authService->getAuthCustomer()) {

            $shop = $customer->getManager()->getShop();
            
            self::$currentShop = $shop;
            
            return $shop;
        }

        self::$currentShop = $this->shopService->getCurrentOrDefaultShop();
        
        

        return self::$currentShop;
    }
    
    /**
     * 
     * @return \Shop\Models\Manager\Manager
     */
    public function getCurrentManager(): \Shop\Models\Manager\Manager
    {
        $shop = $this->getCurrentShop();
       
        return $shop->getManagers()->getFirst();
    }
    
    /**
     * Возращает тек пользователя или false
     * @return \Shop\Models\Customer\Customer
     */
    public function getCurrentCustomer(){
        
        return $this->authService->getAuthCustomer();
    }
    
    /**
     * Заменить полностью на DTO
     * @return type
     */
    public function buildCurrentCustomer() : CustomerComplexInterface{

        if(is_a(self::$currentCustomer, CustomerComplexInterface::class)){
            return self::$currentCustomer;
        }
        
        $customerFind = $this->getCurrentCustomer();

        $customer = !$customerFind ? $this->buildDefaultComplexRate(): $customerFind;

        self::$currentCustomer = $customer;
        
        return $customer;
    }

    /**
     * создание дефолтного комплексного
     */
    protected function buildDefaultComplexRate(){
        $defaultCategory = $this->mainConfig->getDefault_customer_category();
        $curShop = $this->getCurrentShop();
       
        $pricesIds = [];
        
        $pricesQ = 
                \Shop\Models\PricelistSheet\PricelistSheetQuery::create("s")
                  
                ->usePricelistFileQuery()
                    ->useProviderQuery()
                        ->filterByShop($curShop)
                    ->endUse()
                ->endUse()
                //->_if($_GET["test"]>0)
                
		->addAlias("ac", "shop_price_access")
                ->addJoin("s.id","ac.price_scheet_id")
                ->_if($defaultCategory > "")
                ->where($defaultCategory . " LIKE ac.customer_group_id")
                ->_endif()
               
                ;
                
     
          
         $prices = $pricesQ ->find();

    
        if($prices->count()){
            $pricesIds = array_keys($prices->toArray("id"));
        }
        
        
        return (new \Shop\DTO\CustomerComplex())
                ->setGroupId($defaultCategory)
                ->setAccessPriceListScheetIds($pricesIds);
    }

    /**
     * 
     * @param type $email
     * @return \Shop\Models\Customer\Customer
     */
    public function recoveryPasswordByEmail($email): \Shop\Models\Customer\Customer
    {

        if ( ! $customer = $this->customerRepo->findByEmail($email)) {
            throw new \Core\Exceptions\LogicException("customer not exist");
        }

        $code = $this->generateCode();

        $customer
                ->setRegisterCode($code)
                ->setPassword(md5($code))
        ;

        if ( ! $customer->save()) {
            throw new \Core\Exceptions\LogicException("customer save error");
        }

        return $customer;
    }

    /**
     * @param string $password
     * @param \Shop\Models\Customer\Customer $customer
     */
    public function notifyRecoveryPassword(string $password,  \Shop\Models\Customer\Customer $customer): void
    {
        $data = $customer->toArray();
        $data["code"] = $password;
        $message = $this->reportService->buildMessageFromContent("recovery", $data );
        $this->notifyService->sendToEmail($customer->getEmail(), $message );
    }

    /**
     * Генерация кода
     * @param type $length
     * @param type $chars
     * @return type
     */
    function generateCode($length = 6, $chars = 'abdefhiknrstyzABDEFGHKNQRSTYZ23456789'): string
    {
        //здесь генерируем случайную комбинацию цифр
        $numChars = strlen($chars);
        $string = '';
        for ($i = 0; $i < $length; $i ++) {
            $string .= substr($chars, rand(1, $numChars) - 1, 1);
        }
        return $string;
    }

    /**
     * 
     * @param type $name
     * @param type $email
     * @param type $phone
     * @param type $cityId
     * @return \Shop\Models\Customer\Customer
     * @deprecated
     * @see \Shop\Services\Customer::registrationWithNotify
     */
    public function regstrationCustomerAndNotify($name, $email, $phone, $cityId): \Shop\Models\Customer\Customer
    {
        $newCustomer = new \Shop\DTO\CustomerRequest();
        $newCustomer
                ->setName($name)
                ->setCityId($cityId)
                ->setEmail($email)
                ->setGroupId($this->mainConfig->getDefault_customer_category())
                ->setPhone($phone)
        ;

        return $this->registrationWithNotify($newCustomer);
    }

    
    
    /**
     * 
     * @param CustomerRequest $newCustomer
     * @return \Shop\Models\Customer\Customer
     */
    public function registrationWithNotify(CustomerRequest $newCustomer): \Shop\Models\Customer\Customer
    {

        $customer = $this->registration($newCustomer);

        //Формируем сообщение
        $data = $customer->toArray();
        $data["region"] = $customer->getCustomerCity()->getCityRegion()->getName();
        $data["city"] = $customer->getCustomerCity()->getName();
        $data["code"] = $customer->getRegisterCode();
        $data["registred"] = date(\Diamond\Helpers\Date::formatDisplay());
        $data["link"] = anchor('/personal/data', 'личном кабинете');
        $data["phone"] = $customer->getPhone();
        $data["group"] = $customer->getCustomerGroup()->getName();
        $data["address"] = $customer->getFullAddress();

        $message = $this->reportService->buildMessageFromContent("client_registration", $data);

        //отправляем уведомление
        if ($message) {
            $this->notifyService->sendToEmail($customer->getEmail(), $message);
        }

        $manager = $customer->getManager();
        $messageManager = $this->reportService->buildMessageFromContent("client_registration_manager", $data);

        if ($manager && $messageManager) {
            $this->notifyService->sendToEmail($manager->getEmail(), $messageManager);
        }

        return $customer;
    }

    /**
     * Регистрация клиента
     * @param CustomerRequest $newCustomer
     * @return \Shop\Models\Customer\Customer
     * @throws \Core\Exceptions\LogicException
     */
    public function registration(CustomerRequest $newCustomer): \Shop\Models\Customer\Customer
    {

        $code = $this->generateCode();
        
        //если менеджер не определен автопоиск магазина и менеджера по адресу
        if(!$managerId = $newCustomer->getManagerId()){
            $managerId = $this->getManagerByCityId($newCustomer->getCityId())->getId();
        }
 
        $customer = $this->customerRepo->buildEntity()
                ->setName($newCustomer->getName())
                ->setEmail($newCustomer->getEmail())
                ->setPhone($newCustomer->getPhone())
                ->setCityId($newCustomer->getCityId())
                ->setManagerId($managerId)
                ->setPassword(md5($code))
                ->setRegisterCode($code)
                ->setGroupId($newCustomer->getGroupId())//новая группа
                ->setBlocked("N")
        ;

        if ( ! $customer->save()) {
            throw new \Core\Exceptions\LogicException("customer not save");
        }

        return $customer;
    }

    /**
     * 
     * @param type $cityId
     * @return \Shop\Models\Manager\Manager
     * @throws \RuntimeException
     */
    public function getManagerByCityId($cityId): \Shop\Models\Manager\Manager
    {

        $manager = \Shop\Models\Manager\ManagerQuery::create()
                ->useShopQuery()
                ->filterByCityId($cityId)
                ->filterByType(["main", "dealer"])
                ->endUse()
                ->findOne()
        ;

        if ( !$manager) {
            $region = \Shop\Models\Region\RegionQuery::create()
                    ->useCityQuery()
                    ->filterById($cityId)
                    ->endUse()
                    ->findOne();
            if ($region) {
                $manager = \Shop\Models\Manager\ManagerQuery::create()
                        ->useShopQuery()
                        ->useAddressQuery()
                        ->useCityQuery()
                        ->useCityRegionQuery()
                        ->filterById($region->getId())
                        ->endUse()
                        ->endUse()
                        ->endUse()
                        ->filterByType(["main", "dealer"])
                        ->endUse()
                        ->findOne()
                ;
            }
        }

        if ( ! $manager) {
            $manager = \Shop\Models\Manager\ManagerQuery::create()
                    ->useShopQuery()
                    ->filterByType("main")
                    ->endUse()
                    ->findOne()
            ;
        }

        if ( ! $manager) {
            throw new \Core\Exceptions\LogicException("manager not find");
        }

        return $manager;
    }

    /**
     * 
     * @return type
     */
    public function getNotifyTypes(): array
    {
        return [
            "sms"       => "смс",
            "sms_email" => "смс и email",
            "email"     => "email"
        ];
    }

}