<?php

namespace App\Services;

use App\Entities\FormOptionEntity;
use App\Libraries\LogCollector;

abstract class CommonService
{
    private $_serviceDatas = [];
    private $_model = null;
    private $_classNames = [];
    protected function __construct() {}
    abstract public function getModelClass(): mixed;
    abstract public function getEntityClass(): mixed;
    abstract public function getFormFields(): array;
    abstract public function getFilterFields(): array;
    abstract public function getBatchJobFields(): array;
    public function getIndexFields(): array
    {
        return $this->getFormFields();
    }
    public function getViewFields(): array
    {
        return $this->getFormFields();
    }
    public function getBatchJobButtons(): array
    {
        return [
            'batchjob' => '일괄 처리',
            'batchjob_delete' => '일괄 삭제',
        ];
    }
    //기본 기능부분
    final public function __get($name)
    {
        if (!array_key_exists($name, $this->_serviceDatas)) {
            return null;
        }
        return $this->_serviceDatas[$name];
    }
    final public function __set($name, $value): void
    {
        $this->_serviceDatas[$name] = $value;
    }
    final protected function addClassName(string $className): void
    {
        $this->_classNames[] = $className;
    }
    final public function getClassName($delimeter = DIRECTORY_SEPARATOR): string
    {
        return implode($delimeter, $this->_classNames);
    }
    final protected function getModel(): mixed
    {
        if (!$this->_model) {
            $this->_model = $this->getModelClass();
        }
        return $this->_model;
    }
    final public function getEntity(mixed $where, ?string $message = null): mixed
    {
        try {
            $entity = is_array($where) ? $this->getModel()->where($where)->first() : $this->getModel()->find($where);
            if (!$entity) {
                throw new \Exception($message ?? __METHOD__ . "에서 해당 정보가 존재하지 않습니다");
            }
            return $entity;
        } catch (\Exception $e) {
            $message = sprintf(
                "\n------%s SQL오류-----\n%s\n------------------------------\n",
                __FUNCTION__,
                $this->getModel()->getLastQuery()
            );
            throw new \Exception($message);
        }
    }
    protected function findAllDatas_process(array $columns = ['*']): mixed
    {
        return $this->getModel()->select(implode(',', $columns))->findAll();
    }
    final public function getEntities(mixed $where = null, array $columns = ['*']): array
    {
        try {
            if ($where) {
                $this->getModel()->where($where);
            }
            $entities = [];
            foreach ($this->findAllDatas_process($columns) as $entity) {
                $entities[$entity->getPK()] = $entity;
            }
            return $entities;
        } catch (\Exception $e) {
            $message = sprintf(
                "\n------%s SQL오류-----\n%s\n------------------------------\n",
                __FUNCTION__,
                $this->getModel()->getLastQuery()
            );
            throw new \Exception($message);
        }
    } //
    final public function isIPAddress(string $ip, $type = false): bool
    {
        switch ($type) {
            case 'ipv4':
                $result = filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4);
                break;
            case 'ipv6':
                $result = filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6);
                break;
            case 'all':
                $result = filter_var($ip, FILTER_VALIDATE_IP);
                break;
            default:
                $result = filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE);
                break;
        }
        return $result;
    }
    //기본 기능부분

    //FieldForm관련용
    public function getFormFieldOption(string $field, array $options = []): array
    {
        switch ($field) {
            default:
                $options = [];
                foreach (lang($this->getClassName() . '.' . strtoupper($field)) as $key => $value) {
                    $options[$key] = new FormOptionEntity(['uid' => $key, 'title' => $value]);
                }
                // dd($options);
                break;
        }
        if (!is_array($options)) {
            throw new \Exception(__FUNCTION__ . "에서 field의 options 값이 array가 아닙니다.\n" . var_export($options, true));
        }
        return $options;
    }
    public function getFormFieldRule(string $action, string $field): string
    {
        if (is_array($field)) {
            throw new \Exception(__FUNCTION__ . "=> field가 array 입니다.\n" . var_export($field, true));
        }
        switch ($field) {
            default:
                $rule = $this->getModel()->getFormFieldRule($action, $field);
                break;
        }
        return $rule;
    }
    public function create(array $formDatas): mixed
    {
        $entity = $this->getModel()->create($formDatas);
        LogCollector::info("[{$entity->getTitle()}]" . MESSAGES["CREATED"] . ":");
        return $entity;
    }
    public function modify(mixed $entity, array $formDatas): mixed
    {
        $entity = $this->getModel()->modify($entity, $formDatas);
        LogCollector::info("[{$entity->getTitle()}]" . MESSAGES["UPDATED"] . ":");
        return $entity;
    }
    public function delete(mixed $entity): mixed
    {
        $result = $this->getModel()->delete($entity->getPK());
        if (!$result) {
            $message = sprintf(
                "\n------%s SQL오류-----\n%s\n------------------------------\n",
                __FUNCTION__,
                $this->getModel()->getLastQuery()
            );
            LogCollector::error($message);
            throw new \Exception($message);
        }
        LogCollector::info("[{$entity->getTitle()}]" . MESSAGES["DELETED"] . ":");
        return $entity;
    }

    //List 검색용
    final public function getTotalCount(): int
    {
        return $this->getModel()->countAllResults(false);
    }
    //Limit처리
    final public function setLimit(int $per_page): void
    {
        $this->getModel()->limit($per_page);
    }
    //Offset처리
    final public function setOffset(int $offset): void
    {
        $this->getModel()->offset($offset);
    }
    //FormFilter 조건절 처리
    public function setList_FormFilter(string $field, mixed $filter_value): void
    {
        switch ($field) {
            default:
                //일반검색
                $this->getModel()->where("{$this->getModel()->getTable()}.{$field}", $filter_value);
                break;
        }
    }
    //검색어조건절처리
    public function setList_WordFilter(string $word): void
    {
        $this->getModel()->orLike($this->getModel()->getTable() . "." . $this->getModel()->getTitleField(), $word, 'both');
    }
    //날자검색
    public function setList_DateFilter(string $start, string $end): void
    {
        $this->getModel()->where(sprintf("%s.created_at >= '%s 00:00:00'", $this->getModel()->getTable(), $start));
        $this->getModel()->where(sprintf("%s.created_at <= '%s 23:59:59'", $this->getModel()->getTable(), $end));
    }
    //OrderBy 처리
    public function setOrderBy(mixed $field = null, mixed $value = null): void
    {
        if ($field !== null && $value !== null) {
            $this->getModel()->orderBy(sprintf("%s.%s %s", $this->getModel()->getTable(), $field, $value));
        }
    }
}
