<?php

namespace App\Services\Customer;

use App\Entities\Customer\ServiceEntity;
use App\Entities\Equipment\CodeEntity;

use App\Entities\Equipment\SwitchEntity;
use App\Models\Customer\ServiceModel;
use App\Services\Customer\ServiceItemService;
use App\Services\Equipment\CodeService;
use App\Services\Equipment\SwitchService;

class ServiceService extends CustomerService
{
    private ?CodeService $_codeService = null;
    private ?SwitchService $_switchService = null;
    private ?ServiceItemService $_serviceItemService = null;
    private ?ServicePaymentService $_servicePaymentService = null;
    private ?string $_searchIP = null;
    public function __construct()
    {
        parent::__construct();
        $this->addClassName('Service');
    }
    public function getModelClass(): ServiceModel
    {
        return new ServiceModel();
    }
    public function getEntityClass(): ServiceEntity
    {
        return new ServiceEntity();
    }
    public function getFormFields(): array
    {
        return [
            "clientinfo_uid",
            "ownerinfo_uid",
            "type",
            "location",
            "switchinfo_uid",
            "codeinfo_uid",
            "raid",
            "billing_at",
            "start_at",
            "status"
        ];
    }
    public function getFilterFields(): array
    {
        return ["clientinfo_uid", 'ownerinfo_uid', 'user_uid', 'type', 'location', 'switchinfo_uid', 'codeinfo_uid',  'raid', 'status'];
    }
    public function getBatchJobFields(): array
    {
        return ['status'];
    }
    public function getIndexFields(): array
    {
        return ['clientinfo_uid', 'ownerinfo_uid', 'type', 'location', 'switchinfo_uid', 'codeinfo_uid', 'raid', 'billing_at', 'start_at', 'updated_at', 'status', 'user_uid'];
    }
    public function getCodeService(): CodeService
    {
        if (!$this->_codeService) {
            $this->_codeService = new CodeService();
        }
        return $this->_codeService;
    }
    public function getSwitchService(): SwitchService
    {
        if (!$this->_switchService) {
            $this->_switchService = new SwitchService();
        }
        return $this->_switchService;
    }
    public function getServiceItemService(): ServiceItemService
    {
        if (!$this->_serviceItemService) {
            $this->_serviceItemService = new ServiceItemService();
        }
        return $this->_serviceItemService;
    }
    public function getServicePaymentService(): ServicePaymentService
    {
        if (!$this->_servicePaymentService) {
            $this->_servicePaymentService = new ServicePaymentService();
        }
        return $this->_servicePaymentService;
    }
    //Entity의 관련객체정의용
    public function setSearchIp(string $ip): void
    {
        $this->_searchIP = $ip;
    }
    public function getSearchIp(): string|null
    {
        return $this->_searchIP;
    }
    protected function findAllDatas_process(array $columns = ['*']): mixed
    {
        $ip = $this->getSearchIp();
        if ($ip) {
            $sql = "SELECT serviceinfo.* FROM serviceinfo
            LEFT JOIN serviceinfo_items ON serviceinfo.uid = serviceinfo_items.serviceinfo_uid
            WHERE serviceinfo_items.item_type = ?
            AND serviceinfo_items.item_uid IN (SELECT uid FROM ipinfo WHERE ip = ?)";
            return $this->getModel()->query($sql, ['IP', $ip])->getResult(ServiceEntity::class);
        }
        return parent::findAllDatas_process($columns);
    }
    //기본 기능부분
    //FieldForm관련용
    public function getFormFieldOption(string $field, array $options = []): array
    {
        switch ($field) {
            case 'user_uid':
                $options = $this->getUserService()->getEntities();
                break;
            case 'codeinfo_uid':
                $options = $this->getCodeService()->getEntities();
                break;
            case 'switchinfo_uid':
                $options = $this->getSwitchService()->getEntities();
                break;
            default:
                $options = parent::getFormFieldOption($field, $options);
                break;
        }
        return $options;
    }
    //Service마다 ItemEntities 설정용
    public function setItemEntitiesByService(ServiceEntity $entity): ServiceEntity
    {
        foreach (SERVICE_ITEM_TYPES as $item_type => $label) {
            $itemEntities = $this->getServiceItemService()->getEntities([
                'serviceinfo_uid' => $entity->getPK(),
                'item_type' => $item_type
            ]);
            $entity->setItemEntities($item_type, $itemEntities);
        }
        return $entity;
    }
    //interval을 기준으로 최근 신규 서비스정보 가져오기
    final public function getEntitiesByNewService(int $interval, string $status = DEFAULTS['STATUS']): array
    {
        $entities = [];
        foreach ($this->getEntities(sprintf("start_at >= NOW()-INTERVAL {$interval} DAY AND status = '%s'", $status)) as $entity) {
            $entities[$entity->getPK()] = $this->setItemEntitiesByService($entity);
        };
        return $entities;
    }
    //서비스 방식에 따른 서비스별 Count
    final public function getTotalCountsByType(): array
    {
        $sql = "SELECT type,
                COUNT(CASE WHEN location = 'default' THEN 1 END) AS chiba,
                COUNT(CASE WHEN location = 'tokyo' THEN 1 END) AS tokyo,
                COUNT(CASE WHEN location IN ('default', 'tokyo') THEN 1 END) AS total
                FROM serviceinfo GROUP BY type;";

        $totalCounts = ['chiba_total' => 0, 'tokyo_total' => 0, 'all_total' => 0];
        foreach ($this->getModel()->query($sql)->getResult() as $row) {
            $totalCounts[$row->type] = [
                'chiba' => $row->chiba,
                'tokyo' => $row->tokyo,
                'total' => $row->total,
            ];
            $totalCounts['chiba_total'] += $row->chiba;
            $totalCounts['tokyo_total'] += $row->tokyo;
        }
        $totalCounts['all_total'] = $totalCounts['chiba_total'] + $totalCounts['tokyo_total'];
        return $totalCounts;
    }
    //다음 달로 결제일을 연장합니다.
    final public function extendBillingAt(string $billing_at, string $status): bool
    {
        $sql = "UPDATE serviceinfo SET billing_at =
                IF(DAY(billing_at) > DAY(LAST_DAY(billing_at)),
                    LAST_DAY(DATE_ADD(billing_at, INTERVAL 1 MONTH)),
                    DATE_ADD(billing_at, INTERVAL 1 MONTH)
                ) WHERE billing_at = ? AND status = ?";
        return $this->getModel()->query($sql, [$billing_at, $status]);
    }
    public function create(array $formDatas): ServiceEntity
    {
        //code의 경우 서비스중으로 설정작업
        $this->getCodeService()->setStatus($formDatas['codeinfo_uid'], CodeEntity::STATUS_OCCUPIED);
        //switch의 경우 서비스중으로 설정작업
        $this->getSwitchService()->setStatus($formDatas['switchinfo_uid'], SwitchEntity::STATUS_OCCUPIED);
        return parent::create($formDatas);
    }
    public function modify(mixed $entity, array $formDatas): ServiceEntity
    {
        //code가 기존과 다를경우 //toggle,batchjob의 경우 $formDatas에 code가 없을수도 있음
        if (array_key_exists('codeinfo_uid', $formDatas) && $formDatas['codeinfo_uid'] !== $entity->getCodeUID()) {
            //기존 code의 경우 반환처리
            $this->getCodeService()->setStatus($entity->getCodeUID(), CodeEntity::STATUS_AVAILABLE);
            //신규 설정된 code의 경우 서비스중 변경처리
            $this->getCodeService()->setStatus($formDatas['codeinfo_uid'], CodeEntity::STATUS_OCCUPIED);
        }
        //switch가 기존과 다를경우 //toggle,batchjob의 경우 $formDatas에 switch가 없을수도 있음
        if (array_key_exists('switchinfo_uid', $formDatas) && $formDatas['switchinfo_uid'] !== $entity->getSwitchUID()) {
            //기존 switch의 경우 반환처리
            $this->getSwitchService()->setStatus($entity->getSwitchUID(), SwitchEntity::STATUS_AVAILABLE);
            //신규 설정된 switch의 경우 서비스중 변경처리
            $this->getSwitchService()->setStatus($formDatas['switchinfo_uid'], SwitchEntity::STATUS_OCCUPIED);
        }
        //관리자가 바뀐경우 결제쪽에도 결제가 완료되지않은 것은 관리자를 변경해줘야함
        if (array_key_exists('ownerinfo_uid', $formDatas) && $entity->getOwnerUID() !== intval($formDatas['ownerinfo_uid'])) {
            $this->getServicePaymentService()->modifyOwnerByService($entity, $formDatas['ownerinfo_uid']);
        }
        return parent::modify($entity, $formDatas);
    }
    public function delete(mixed $entity): ServiceEntity
    {
        //기존 code의 경우 반환처리
        $this->getCodeService()->setStatus($entity->getCode(), CodeEntity::STATUS_AVAILABLE);
        //기존 switch의 경우 반환처리
        $this->getSwitchService()->setStatus($entity->getCode(), SwitchEntity::STATUS_AVAILABLE);
        //Item들 삭제
        foreach (SERVICE_ITEM_TYPES as $item_type => $label) {
            foreach ($entity->getItemEntities($item_type) as $itemEntity) {
                $this->getServiceItemService()->delete($itemEntity);
            }
        }
        return parent::delete($entity);
    }
    //List 검색용
    //검색어조건절처리
    public function setList_WordFilter(string $word): void
    {
        if ($this->isIPAddress($word, 'ipv4')) {
            $this->setSearchIp($word);
        } else {
            parent::setList_WordFilter($word);
        }
    }
}
