<?php

namespace App\Models;

use App\Entities\BaseEntity;

//계층형구조구현용 모델(게시판,카테고리 등등)
abstract class BaseHierarchyModel extends BaseModel
{
    protected function __construct(string $className)
    {
        parent::__construct($className);
        $this->allowedFields = [...$this->allowedFields, "grpno", "grporder", "grpdepth"];
        $this->validationRules = [...$this->validationRules,];
    }
    abstract public function getContentField();
    abstract public function reply($parent_entity, array $formDatas): BaseEntity;
    protected function getFieldRule(string $field, array $rules, string $action = ""): array
    {
        switch ($field) {
            case "grpno":
            case "grporder":
            case "grpdepth":
                $rules[$field] = "if_exist|numeric"; //반드시숫자여야함
                break;
            default:
                $rules = parent::getFieldRule($field, $rules, $action);
                break;
        }
        return $rules;
    }

    final protected function create_process($entity, array $formDatas)
    {
        //생성시는 grpno의 max값을 구해서 넣는다.
        $entity->grpno = $this->selectMax("grpno")->get()->getResult()[0]->grpno + 1;
        if (!$entity->grpno) {
            throw new \Exception("grpno는 {$entity->grpno}의 값을 가질수 없습니다.");
        }
        return parent::create_process($entity, $formDatas);
    }

    final protected function reply_process($parent_entity, $entity, array $formDatas)
    {
        //부모의 그룹과 grpno가 같고, 부모의 grporder보다 1 큰것을 grporder+1을 해서 update
        //escape -> false옵션 반드시 있어야함
        $this->set("grporder", "grporder+1", false);
        $this->where([
            "grpno" => $parent_entity->grpno,
            "grporder >" => $parent_entity->grporder
        ]);
        $this->update();
        //reply용 설정
        $entity->grpno = $parent_entity->grpno;
        $entity->grporder = $parent_entity->grporder + 1;
        $entity->grpdepth = $parent_entity->grpdepth + 1;
        return parent::create_process($entity, $formDatas);
    }

    public function setIndexOrderBy(?string $field, ?string $order)
    {
        //계단식의 경우는 먼저 다른것보다 먼저 orderBy가 수행되어야 하므로
        $this->orderBy("grpno", "DESC");
        $this->orderBy("grporder", "ASC");
        parent::setIndexOrderBy($field, $order);
    }
}
