<?php

namespace Modules\User\Models\Traits;

use Carbon\Carbon;
use Exception;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
use Modules\User\Events\UserJoinIdentity;
use Modules\User\Events\UserRemoveIdentity;
use Modules\User\Events\UserUpdateIdentity;
use Modules\User\Models\Identity;
use Modules\User\Models\IdentityLog;
use Modules\User\Models\IdentityMiddle;

trait JoinIdentity
{

    /**
     * 用户加入身份
     *
     * @param  int  $identity_id  身份ID
     * @param  string  $channel  加入渠道
     * @param  array  $source  其他溯源信息
     * @throws Exception
     */
    public function joinIdentity(
        int $identity_id = 0,
        string $channel = IdentityLog::CHANNEL_AUTO,
        array $source = []
    ) {

        // 单身份，并且已经开通身份
        if (config('identity.can_has_many_identity') == false && $this->identityMiddle->count() >= 1) {
            //续费
            if ($this->hasIdentity($identity_id)) {
                $this->renewIdentity($identity_id);
            } else {
                //升级
                self::updateIdentity($identity_id, $channel, $source);
            }
        } else {
            $identity = Identity::find($identity_id);
            if ($identity) {
                //未开通此身份
                if ($this->hasIdentity($identity_id) == false) {
                    $remark = Arr::get($source, 'remark', '加入身份');
                    $res    = self::identityLog(0, $identity_id, $channel, $remark, $source);
                    if ($res) {
                        $serial = $source['serial'] ?? '';
                        if ($identity->serial_open && empty($serial)) {
                            $serial = self::getNewSerial($identity->serial_places);
                        }

                        $value = [];
                        if ($identity->years) {
                            $value = [
                                'started_at' => now(),
                                'ended_at'   => now()->addMonths($identity->years),
                            ];
                        }

                        $this->identityMiddle()
                            ->updateOrCreate([
                                'identity_id' => $identity_id,
                                'serial'      => $serial,
                            ], $value);

                        event(new UserJoinIdentity($this, $identity));
                    } else {
                        throw new Exception('添加日志失败');
                    }
                } else {
                    //已开通此身份
                    $this->renewIdentity($identity_id);
                }
            } else {
                throw new Exception('身份信息不存在');
            }

        }
    }

    /**
     * Notes: 续费
     *
     * @Author: 玄尘
     * @Date  : 2021/6/8 9:49
     * @param  int  $identity_id
     */
    public function renewIdentity(int $identity_id)
    {
        $identity = Identity::find($identity_id);
        $before   = $this->identityMiddle()->where('identity_id', $identity_id)->first();

        //vip
        if ($identity->years) {
            IdentityMiddle::where('user_id', $this->id)
                ->where('identity_id', $identity_id)
                ->update([
                    'ended_at' => Carbon::parse($before->ended_at)->addMonths($identity->years),
                ]);
        } else {
            IdentityMiddle::where('user_id', $this->id)
                ->where('identity_id', $identity_id)
                ->update([
                    'started_at' => null,
                    'ended_at'   => null,
                ]);
        }

        event(new UserJoinIdentity($this, $before->identity));
    }

    /**
     * 用户身份调整，当多身份关闭时由join触发
     *
     * @param  int  $identity_id
     * @param  string  $channel
     * @param  array  $source
     * @throws Exception
     */
    public function updateIdentity(
        int $identity_id = 0,
        string $channel = IdentityLog::CHANNEL_AUTO,
        array $source = []
    ) {
        $before = $this->identityMiddle()->first();
        if ($this->identityMiddle()->count() > 1) {
            $this->identityMiddle()->where('identity_id', '!=', $before->identity_id)->delete();
        }
        $identity = Identity::find($identity_id);
        if ($identity) {
            $remark = Arr::get($source, 'remark', '身份变更');
            $res    = self::identityLog($before->identity_id, $identity_id, $channel, $remark, $source);
            if ($res) {
                $serial = $source['serial'] ?? '';
                if ($identity->serial_open && empty($serial)) {
                    $serial = self::getNewSerial($identity->serial_places);
                }

                $data = [
                    'identity_id' => $identity_id,
                    'serial'      => $serial,
                    'started_at'  => null,
                    'ended_at'    => null,
                ];

                if ($identity->years) {
                    $data['started_at'] = now();
                    $data['ended_at']   = now()->addMonths($identity->years);
                }

                IdentityMiddle::where('user_id', $this->id)
                    ->where('identity_id', $before->identity_id)
                    ->update($data);

                event(new UserUpdateIdentity($this, $before->identity, $identity));
            } else {
                throw new Exception('调整身份');
            }
        } else {
            throw new Exception('身份信息不存在');
        }
    }

    /**
     * 判断用户是否参与身份
     *
     * @param  int  $identity_id
     * @return bool
     */
    public function hasIdentity(int $identity_id = 0): bool
    {
        if ($identity_id) {
            $res = $this->identityMiddle()->where('identity_id', $identity_id)->first();

            return (bool) $res;
        } else {
            return true;
        }
    }

    /**
     * 用户移除身份
     *
     * @param  int  $identity_id  身份ID
     * @param  string  $channel  移除渠道
     * @param  array  $source  其他溯源信息
     * @throws Exception
     */
    public function removeIdentity(
        int $identity_id = 0,
        string $channel = IdentityLog::CHANNEL_AUTO,
        array $source = []
    ) {
        if ($this->identityMiddle()->where('identity_id', $identity_id)->first()) {
            $remark = Arr::get($source, 'remark', '身份移除');
            $res    = self::identityLog($identity_id, 0, $channel, $remark, $source);
            if ($res) {
                $this->identityMiddle()->where('identity_id', $identity_id)->delete();
                event(new UserRemoveIdentity($this, Identity::find($identity_id)));
            } else {
                throw new Exception('移除记录失败');
            }
        } else {
            throw new Exception('用户不在身份组中');
        }
    }

    /**
     * 生成数据库中部存在的号码
     *
     * @return int
     */
    public function getNewSerial($places = 8)
    {
        try {
            $min   = pow(10, $places - 1);
            $max   = 9 * $min;
            $query = 'SELECT code FROM (SELECT CEILING(RAND()*'.$max.'+'.$min.') AS code FROM user_identity UNION SELECT CEILING(RAND()*'.$max.'+'.$min.') AS code) AS ss WHERE "code" NOT IN (SELECT serial FROM user_identity where serial !=null) LIMIT 1';
            $res   = DB::select($query);

            return (int) $res[0]->code;
        } catch (Exception $e) {
            return '';
        }
    }

    public function identityLog(
        $before = 0,
        $after = 0,
        $channel = '',
        $remark = '',
        $source = []
    ): Model {
        return $this->identity_logs()->create([
            'before'  => $before,
            'after'   => $after,
            'channel' => $channel,
            'remark'  => $remark,
            'source'  => $source,
        ]);
    }

}
