<?php

namespace crmeb\basic;

use think\Model;

/**
 * Class BaseBusiness
 * @package crmeb\basic
 */
abstract class BaseBusiness implements \ArrayAccess
{
    /**
     * @var string
     */
    protected $pk = 'id';

    /**
     * 模型class
     * @var string
     */
    protected $modelClassName;

    /**
     * 模型实例
     * @var []
     */
    protected $modeHandle;

    /**
     * 数据列表
     * @var []
     */
    protected $list;

    /**
     * @var Model
     */
    protected $model;

    protected $where = [];

    /**
     * 获取模型
     * @param string|null $model
     * @return Model
     */
    public function getModel(string $model = null)
    {
        if (is_null($model)) {
            $model = $this->modelClassName;
        }
        if (isset($this->modeHandle[$model])) {
            return $this->modeHandle[$model];
        }
        return $this->modeHandle[$model] = new $model();
    }

    /**
     * 获取主键
     * @param string|null $pk
     * @return $this
     */
    protected function getPk(string $pk = null)
    {
        $pk = $pk ?: $this->pk;
        if (!$pk) {
            $pk = $this->getModel()->getPk();
        }
        return $pk;
    }

    /**
     * 状态开关
     * @param int $id
     * @param int $status
     * @return mixed
     */
    public function statusWitch(int $id, int $status, string $pk = null)
    {
        return $this->getModel()->where($this->getPk($pk), $id)->update(compact('status'));
    }

    /**
     * 删除开关
     * @param int $id
     * @param int $status
     * @return mixed
     */
    public function deleteWitch(int $id, int $is_del, string $pk = null)
    {
        return $this->getModel()->where($this->getPk($pk), $id)->update(compact('is_del'));
    }

    /**
     * 修改某个字段
     * @param int $id
     * @param $data
     * @param string|null $value
     * @param string $pk
     * @return bool
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function updateField(int $id, $data, string $value = null, string $pk = null)
    {
        $resource = $this->getModel()->where($this->getPk($pk), $id)->find();
        if (!$resource) {
            return false;
        }
        if (is_array($data)) {
            foreach ($data as $field => $val) {
                $resource->{$field} = $val;
            }
        } elseif ($data && $value) {
            $resource->{$data} = $value;
        }
        return $resource->save();
    }

    /**
     * @param array $where
     * @return $this
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getModelList(array $where = [])
    {
        if (!empty($where) && empty($this->where)) {
            $this->where = $where;
        }
        $count = $this->model->count($this->getPk($this->pk));
        $this->page();
        $this->list = $this->model->select();
        $this->model = null;
        return $this;
    }

    /**
     * @param int $id
     * @param array $where
     * @return $this
     */
    public function getFind(int $id, array $where = [])
    {
        $this->init()->beforeModel();
        $this->list = $this->model->get($id);
        $this->model = null;
        return $this;
    }

    /**
     * @return mixed
     */
    abstract protected function beforeModel();

    /**
     * @return mixed
     */
    abstract protected function afterModel();

    /**
     * 初始化model
     * @return $this
     */
    protected function init()
    {
        if (!$this->model) {
            $this->model = $this->getModel();
        }
        return $this;
    }

    /**
     * @param callable $callableModel
     * @return $this
     */
    public function callableWhere(callable $callableModel, array $where = [])
    {

        if (!empty($where) && empty($this->where)) {
            $this->where = $where;
        }
        $this->init()->beforeModel();
        $this->model = $callableModel($this->model, $this->where);
        return $this;
    }

    /**
     * @return $this
     */
    public function page()
    {
        if (isset($this->where['page']) && isset($this->where['limit'])) {
            $this->model = $this->model->page((int)$this->where['page'], (int)$this->where['limit']);
        }
        return $this;
    }

    /**
     * @param callable $each
     * @return mixed
     */
    public function each(callable $each = null)
    {
        $list = $this->list;
        if ($list) {
            if ($each) {
                $list = $list->each($each);
            }
            $list = $list->toArray();
        } else {
            $list = [];
        }
        $this->list = [];
        return $list;
    }

    protected function setAttr($name, $value)
    {
        $this->list[$name] = $value;
        return $this;
    }

    protected function getAttr($name)
    {
        return $this->list[$name];
    }

    /**
     * @param $name
     * @return mixed
     */
    public function __get($name)
    {
        return $this->list;
    }

    /**
     * @param $name
     * @param $arguments
     * @return mixed
     */
    public function __call($name, $arguments)
    {
        return $this->list->{$name}();
    }

    // ArrayAccess
    public function offsetSet($name, $value)
    {
        $this->setAttr($name, $value);
    }


    public function offsetGet($name)
    {
        return $this->getAttr($name);
    }

    public function offsetExists($offset)
    {
        // TODO: Implement offsetExists() method.
    }

    public function offsetUnset($offset)
    {
        // TODO: Implement offsetUnset() method.
    }
}