<?php

namespace Modules\User\Models\Traits;

use Exception;
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Eloquent\Relations\HasOneThrough;
use Illuminate\Support\Facades\DB;
use Modules\User\Models\Relation;
use Modules\User\Models\User;

trait HasRelations
{

    /**
     * 这个参数，是为了给用户创建事件监听模型使用的
     *
     * @var int
     */
    public int $parent_id = 0;

    /**
     * Notes: 创建的监听，转移到这里了
     *
     * @Author: <C.Jason>
     * @Date  : 2020/1/13 5:52 下午
     */
    public static function bootHasRelations()
    {
        self::created(function ($model) {
            if (isset($model->parent_id) && is_numeric($model->parent_id) && $model->parent_id != 0) {
                $parent = User::find($model->parent_id);
                if ($parent && $model->id != $model->parent_id) {
                    $model->relation()->create([
                        'parent_id' => $parent->id,
                        'bloodline' => $parent->relation->bloodline.$parent->id.',',
                        'layer'     => $parent->relation->layer + 1,
                    ]);
                } else {
                    $model->relation()->create([
                        'parent_id' => config('user.default_parent_id'),
                        'bloodline' => config('user.default_parent_id').',',
                        'layer'     => 1,
                    ]);
                }
            } else {
                $model->relation()->create([
                    'parent_id' => config('user.default_parent_id'),
                    'bloodline' => config('user.default_parent_id').',',
                    'layer'     => 1,
                ]);
            }
        });
    }

    /**
     * Notes: 这个方法，是为了给用户创建事件监听模型使用的
     * 目的是去除attribute里面的parent_id参数，防止数据库写入错误
     *
     * @Author: <C.Jason>
     * @Date  : 2020/1/13 5:58 下午
     * @param  int  $parentID
     */
    protected function setParentIdAttribute(int $parentID)
    {
        $this->parent_id = $parentID;
    }

    /**
     * Notes: 用户关联关系
     *
     * @Author: <C.Jason>
     * @Date  : 2020/1/13 5:51 下午
     * @return HasOne
     */
    public function relation(): HasOne
    {
        return $this->hasOne(Relation::class)->withDefault();
    }

    /**
     * Notes: 上级用户
     *
     * @Author: <C.Jason>
     * @Date  : 2020/1/13 5:51 下午
     * @return HasOneThrough
     */
    public function parent(): HasOneThrough
    {
        return $this->hasOneThrough(
            User::class,
            Relation::class,
            'user_id',
            'id',
            'id',
            'parent_id'
        );
    }

    /**
     * Notes: 所有下级用户
     *
     * @Author: <C.Jason>
     * @Date  : 2020/1/13 5:51 下午
     * @return mixed
     */
    public function children(): HasManyThrough
    {
        return $this->hasManyThrough(
            User::class,
            Relation::class,
            'parent_id',
            'id',
            'id',
            'user_id'
        );
    }

    /**
     * 调整隶属
     *
     * @param  int  $parent_id
     * @return bool
     * @throws Exception
     */
    public function updateParent(int $parent_id = 0): bool
    {
        if ($parent_id == $this->id) {
            throw new Exception('不能绑定自己');
        }
        if (Relation::where('user_id', $parent_id)
            ->where('bloodline', 'like', "%,".$this->id.",%")
            ->exists()) {
            throw new Exception('不能绑定自己的下级用户');
        }

        try {
            $relation = $this->relation;

            $new_blood     = '0,';
            $new_layer     = 1;
            $new_parent_id = 0;

            $blood  = $relation->bloodline;
            $layer  = $relation->layer;
            $parent = User::find($parent_id);
            if ($parent) {
                $new_parent_id = $parent->id;
                $new_blood     = $parent->relation->bloodline.$new_parent_id.',';
                $new_layer     = $parent->relation->layer + 1;
            }
            $relation->parent_id = $new_parent_id;
            $relation->bloodline = $new_blood;
            $relation->layer     = $new_layer;
            if ($relation->save()) {
                $diffLayer = $layer - $new_layer;
                DB::update("UPDATE `user_relations` SET `bloodline`=CONCAT(?,SUBSTRING(bloodline,LENGTH(?)+1)),`layer`=`layer`-? WHERE `bloodline` LIKE ?",
                    [$new_blood, $blood, $diffLayer, "%,".$this->id.",%"]);
            }

            return true;
        } catch (Exception $e) {
            return false;
        }
    }

    /**
     * Notes: 获取下级数量
     *
     * @Author: 玄尘
     * @Date  : 2021/9/24 11:42
     */
    public function getRelationCount(): array
    {
        return [
            'all' => Relation::query()
                ->whereIn('layer', [$this->relation->layer + 1, $this->relation->layer + 2])
                ->where('bloodline', 'like', "%,".$this->id.",%")
                ->count(),
            'one' => Relation::query()
                ->where('layer', $this->relation->layer + 1)
                ->where('bloodline', 'like', "%,".$this->id.",%")
                ->count(),
            'two' => Relation::query()
                ->where('layer', $this->relation->layer + 2)
                ->where('bloodline', 'like', "%,".$this->id.",%")
                ->count(),
        ];
    }

}
