<?php

namespace App\Modules\Book\Models;

use App\Consts\Channel\ChannelConst;
use App\Modules\Book\Services\BookTagsService;
use App\Modules\Book\Services\TestBookService;
use App\Modules\User\Services\ReadRecordService;
use App\Modules\Book\Services\BookConfigService;
use App\Modules\Channel\Services\ChannelService;
use App\Modules\OfficialAccount\Services\ForceSubscribeService;
use App\Modules\Promotion\Services\PromotionService;
use App\Modules\User\Services\UserService;
use DB;
use Exception;
use Hashids;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Log;
use Redis;

class BookConfig extends Model
{
    protected $table = 'book_configs';
    protected $fillable = [
        'bid', 'force_subscribe_chapter_seq', 'price', 'cover', 'book_name',
        'copyright', 'charge_type', 'hot', 'is_on_shelf', 'source_domain', 'recommend_index', 'roles', 'test_status', 'plan_push_user_num', 'test_update_time',
        'is_show_index_content', 'click_count', 'promotion_domain', 'copyright_limit_data', 'recommend_cid', 'is_high_quality', 'vip_seq', 'editor_recommend', 'is_current_week_promotion'
    ];

    /**
     * 根据条件获取图书
     * @param array $where
     * @param array $order
     * @param int   $page_size
     * @return mixed
     */
    public static function getBooks(array $where = [], array $order = [], $page_size = 15)
    {

        if (!$order) {
            $order = ['recommend_index', 'desc'];
        }
        $res = self::join('books', 'book_configs.bid', '=', 'books.id')
            ->leftjoin('book_categories', 'books.category_id', 'book_categories.id')
            ->select(
                'book_configs.bid',
                'book_configs.roles',
                'book_configs.force_subscribe_chapter_seq',
                'book_configs.cp_source',
                'book_configs.vip_seq',
                'book_configs.price',
                'book_configs.cover',
                'book_configs.book_name',
                'book_configs.copyright',
                'book_configs.charge_type',
                'book_configs.is_on_shelf',
                'books.author',
                'books.intro',
                'book_categories.category_name',
                'category_id',
                'status',
                'chapter_count',
                'book_configs.click_count',
                'first_cid',
                'last_cid',
                'books.size',
                'last_chapter',
                'books.keyword',
                'book_configs.recommend_index',
                'book_configs.is_show_index_content',
                'book_configs.product_id',
                'book_categories.channel_name',
                'books.last_cid',
                'books.last_chapter',
                'book_configs.product_id',
                'book_configs.copyright_limit_data',
                'books.updated_at as last_update_time',
                'book_configs.promotion_domain',
                'books.name as old_name',
                'book_configs.recommend_cid',
                'book_configs.is_high_quality',
                'is_current_week_promotion'
            );
        if ($where) {
            foreach ($where as $key => $v) {
                //关键词查询
                if ($key == 'key' && $v) {

                    $res = $res->where('book_configs.book_name', 'like', '%' . $v . '%');
                    //->orWhere('books.intro', 'like', '%' . $v . '%')
                    //->orWhere('books.category_name', 'like', '%' . $v . '%')->orWhere('books.author', 'like', '%' . $v . '%')
                    //->orWhere('books.keyword', 'like', '%' . $v . '%');
                }
                //分类id查询
                if ($key == 'category_id' && $v) {
                    $res = $res->where('books.category_id', '=', $v);
                }
                //上架查询
                if ($key == 'is_on_shelf' && $v != '') {
                    if (is_array($v)) {
                        $res = $res->whereIn('is_on_shelf', $v);
                    } else {
                        $res = $res->where('is_on_shelf', '=', $v);
                    }
                }
                //频道查询
                if ($key == 'channel_name' && $v) {
                    $res = $res->where('book_categories.channel_name', '=', $v);
                }
                if ($key == 'status') {
                    $res = $res->where('books.status', '=', $v);
                }
                if ($key == 'author') {
                    $res = $res->where('books.author', 'like', '%' . $v . '%');
                }
                if ($key == 'roles') {
                    $res = $res->where('book_configs.roles', 'like', '%' . $v . '%');
                }
                //旧书名查询
                if ($key == 'old_name') {
                    $res = $res->where('books.name', 'like', '%' . $v . '%');
                }
                //版权日期查询
                if ($key == 'copy_right_date') {
                    if (is_array($v)) {
                        $res = $res->whereBetween('book_configs.copyright_limit_data', $v);
                    } else {
                        $res = $res->where('book_configs.copyright_limit_data', '<=', $v);
                    }
                }

                if ($key == 'domain') {
                    $res = $res->where('book_configs.promotion_domain', 'like', '%' . $v . '%');
                }
                if ($key == 'bid') {
                    $res = $res->where('book_configs.bid', '=', $v);
                }

                if ($key == 'is_high_quality') {
                    $res = $res->where('book_configs.is_high_quality', '=', $v);
                }

                if ($key == 'charge_type') {
                    $res = $res->where('book_configs.charge_type', '=', $v);
                }

                if ($key == 'firstChapterContent') {
                    $res = $res->join('chapters', function ($query) use ($v) {
                        $query->on('book_configs.bid', '=', 'chapters.bid')
                            ->where('chapters.sequence', 1);
                    })->where('chapters.content', 'like', '%' . $v . '%');
                }

                if ($key == 'tags') {
                    $tags_filter = BookTagsService::getSearchBooks($v);
                    $res->whereIn('book_configs.bid', $tags_filter);
                }
                if ($key == 'is_current_week_promotion') {

                    $res->where('book_configs.is_current_week_promotion', $v);
                }
            }
        }
        //$res->orderBy('book_configs.updated_at','desc');
        return $res->orderBy($order[0], $order[1])->orderBy('book_configs.updated_at', 'desc')->paginate($page_size);
    }


    /**
     * 根据条件获取图书
     * @param array $where
     * @param array $order
     * @param int   $page_size
     * @return mixed
     */
    public static function getPromotionBooks(array $where = [], array $bids, array $order = [], $page_size = 15)
    {
        if (!$order) {
            $order = ['recommend_index', 'desc'];
        }
        $res1 = self::join('books', 'book_configs.bid', '=', 'books.id')
            ->leftjoin('book_categories', 'books.category_id', 'book_categories.id')
            ->select(
                'book_configs.bid',
                'book_configs.force_subscribe_chapter_seq',
                'book_configs.cp_source',
                'book_configs.vip_seq',
                'book_configs.price',
                'book_configs.cover',
                'book_configs.book_name',
                'book_configs.copyright',
                'book_configs.charge_type',
                'book_configs.is_on_shelf',
                'books.author',
                'books.intro',
                'book_categories.category_name',
                'category_id',
                'status',
                'chapter_count',
                'book_configs.click_count',
                'first_cid',
                'last_cid',
                'size',
                'last_chapter',
                'books.keyword',
                'book_configs.recommend_index',
                'book_configs.is_show_index_content',
                'book_configs.product_id',
                'book_categories.channel_name',
                'books.last_cid',
                'books.last_chapter',
                'book_configs.product_id',
                'book_configs.copyright_limit_data',
                'books.updated_at as last_update_time',
                'book_configs.promotion_domain',
                'books.name as old_name',
                'book_configs.recommend_cid',
                'book_configs.is_high_quality'
            );
        if ($where) {
            foreach ($where as $key => $v) {
                //关键词查询
                if ($key == 'key' && $v) {
                    $res1 = $res1->where('book_configs.book_name', 'like', '%' . $v . '%');
                }
                //分类id查询
                if ($key == 'category_id' && $v) {
                    $res1 = $res1->where('books.category_id', '=', $v);
                }
                //上架查询
                if ($key == 'is_on_shelf' && $v != '') {
                    if (is_array($v)) {
                        $res1 = $res1->whereIn('is_on_shelf', $v);
                    } else {
                        $res1 = $res1->where('is_on_shelf', '=', $v);
                    }
                }

                //频道查询
                if ($key == 'channel_name' && $v) {
                    $res1 = $res1->where('book_categories.channel_name', '=', $v);
                }
                if ($key == 'status') {
                    $res1 = $res1->where('books.status', '=', $v);
                }
                if ($key == 'author') {
                    $res1 = $res1->where('books.author', 'like', '%' . $v . '%');
                }
                //旧书名查询
                if ($key == 'old_name') {
                    $res1 = $res1->where('books.name', 'like', '%' . $v . '%');
                }
                //版权日期查询
                if ($key == 'copy_right_date') {
                    if (is_array($v)) {
                        $res1 = $res1->whereBetween('book_configs.copyright_limit_data', $v);
                    } else {
                        $res1 = $res1->where('book_configs.copyright_limit_data', '<=', $v);
                    }
                }

                if ($key == 'domain') {
                    $res1 = $res1->where('book_configs.promotion_domain', 'like', '%' . $v . '%');
                }
                if ($key == 'bid') {
                    $res1 = $res1->where('book_configs.bid', '=', $v);
                }

                if ($key == 'is_high_quality') {
                    $res1 = $res1->where('book_configs.is_high_quality', '=', $v);
                }

                if ($key == 'charge_type') {
                    $res1 = $res1->where('book_configs.charge_type', '=', $v);
                }

                if ($key == 'hidden_books') {
                    $res1 = $res1->whereNotIn('book_configs.bid', $v);
                }
            }
            if ($bids) {
                //$res1 = $res1->orwhereIn('book_configs.id', $bids);
                if ((isset($where['key']) && !empty($where['key'])) && (isset($where['channel_name']) && !empty($where['channel_name']))) {
                    $res1 = $res1->orWhere(function ($query) use ($bids, $where) {
                        $query->where('is_on_shelf', 1)
                            ->whereIn('book_configs.bid', $bids)
                            ->where('book_configs.book_name', 'like', '%' . $where['key'] . '%')
                            ->where('book_categories.channel_name', '=', $where['channel_name']);;
                    });
                } elseif (isset($where['key']) && !empty($where['key'])) {
                    $res1 = $res1->orWhere(function ($query) use ($bids, $where) {
                        $query->where('is_on_shelf', 1)
                            ->whereIn('book_configs.bid', $bids)
                            ->where('book_configs.book_name', 'like', '%' . $where['key'] . '%');
                    });
                } elseif (isset($where['channel_name']) && !empty($where['channel_name'])) {
                    $res1 = $res1->orWhere(function ($query) use ($bids, $where) {
                        $query->where('is_on_shelf', 1)
                            ->whereIn('book_configs.bid', $bids)
                            ->where('book_categories.channel_name', '=', $where['channel_name']);
                    });
                } else {
                    $res1 = $res1->orwhereIn('book_configs.bid', $bids);
                }
            }
        }


        return $res1->orderBy($order[0], $order[1])->orderBy('book_configs.updated_at', 'desc')->paginate($page_size);
    }

    /**
     * 根据id数组获取图书信息
     * @param array $bid_arr
     * @param array $order
     * @return mixed
     */
    public static function getBooksByIds(array $bid_arr, array $order = [])
    {
        $res = self::join('books', 'book_configs.bid', '=', 'books.id')
            ->leftjoin('book_categories', 'books.category_id', 'book_categories.id')
            ->select(
                'book_configs.bid',
                'book_configs.force_subscribe_chapter_seq',
                'book_configs.vip_seq',
                'book_configs.price',
                'book_configs.cover',
                'book_configs.book_name',
                'book_configs.copyright',
                'book_configs.charge_type',
                'book_configs.is_on_shelf',
                'books.author',
                'books.intro',
                'book_categories.category_name',
                'category_id',
                'status',
                'chapter_count',
                'book_configs.click_count',
                'first_cid',
                'last_cid',
                'size',
                'last_chapter',
                'books.keyword',
                'book_configs.recommend_index',
                'book_configs.is_show_index_content',
                'book_configs.product_id',
                'book_categories.channel_name',
                'books.last_cid',
                'books.last_chapter',
                'book_configs.product_id',
                'books.updated_at as last_update_time',
                'book_configs.copyright_limit_data',
                'book_configs.promotion_domain',
                'books.name as old_name',
                'book_configs.recommend_cid'
            )
            ->whereIn('book_configs.bid', $bid_arr);
        if ($order) {
            $res->orderBy($order[0], $order[1]);
        } else {
            $str   = implode(',', $bid_arr);
            $field = 'bid,' . $str;
            $res->orderBy(DB::raw('field(' . $field . ')'));
        }

        return $res->limit(30)->get();
    }


    /**
     * 根据bid获取图书信息
     * @param $bid
     * @return mixed
     */
    public static function getBookById($bid)
    {
        if (empty($bid)) return null;
        return self::join('books', 'book_configs.bid', '=', 'books.id')
            ->leftjoin('book_categories', 'books.category_id', 'book_categories.id')
            ->select(
                'book_configs.bid',
                'book_configs.is_on_shelf',
                'book_configs.force_subscribe_chapter_seq',
                'book_configs.vip_seq',
                'book_configs.cp_source',
                'book_configs.price',
                'book_configs.cover',
                'book_configs.book_name',
                'book_configs.copyright',
                'book_configs.created_at',
                'book_configs.charge_type',
                'book_configs.is_on_shelf',
                'books.author',
                'books.intro',
                'book_categories.category_name',
                'category_id',
                'status',
                'chapter_count',
                'first_cid',
                'last_cid',
                'size',
                'last_chapter',
                'books.keyword',
                'book_configs.recommend_index',
                'book_configs.is_show_index_content',
                'book_configs.click_count',
                'book_configs.product_id',
                'book_categories.channel_name',
                'books.last_cid',
                'books.updated_at as last_update_time',
                'books.last_chapter',
                'book_configs.product_id',
                'book_configs.copyright_limit_data',
                'book_configs.promotion_domain',
                'books.name as old_name',
                'book_configs.recommend_cid',
                'book_configs.is_high_quality'
            )->where('book_configs.bid', $bid)->first();
    }

    /**
     * 根据关键词获取图书
     * @param      $key
     * @param int  $page_size
     * @param null $is_on_shelf
     * @return mixed
     */
    public static function getBooksByKey($key, $page_size = 15, $is_on_shelf = null)
    {
        $res = self::join('books', 'book_configs.bid', '=', 'books.id')
            ->leftjoin('book_categories', 'books.category_id', 'book_categories.id')
            ->select(
                'book_configs.bid',
                'book_configs.force_subscribe_chapter_seq',
                'book_configs.vip_seq',
                'book_configs.price',
                'book_configs.cover',
                'book_configs.book_name',
                'book_configs.copyright',
                'book_configs.charge_type',
                'book_configs.is_on_shelf',
                'books.author',
                'books.intro',
                'book_categories.category_name',
                'category_id',
                'status',
                'chapter_count',
                'book_configs.click_count',
                'first_cid',
                'last_cid',
                'size',
                'last_chapter',
                'books.keyword',
                'book_configs.recommend_index',
                'book_configs.is_show_index_content',
                'book_configs.product_id',
                'book_categories.channel_name',
                'books.last_cid',
                'books.last_chapter',
                'book_configs.product_id',
                'books.updated_at as last_update_time',
                'book_configs.copyright_limit_data',
                'book_configs.promotion_domain',
                'books.name as old_name',
                'book_configs.recommend_cid',
                'book_configs.is_high_quality'
            )
            ->where('book_configs.book_name', 'like', '%' . $key . '%');
        //->orWhere('books.intro', 'like', '%' . $key . '%')
        //->orWhere('books.keyword', 'like', '%' . $key . '%')
        //->orWhere('books.category_name', 'like', '%' . $key . '%')
        //->orWhere('books.author', 'like', '%' . $key . '%');
        /*
        if ($is_on_shelf) {
            if (is_array($is_on_shelf)) {
                $res->whereIn('book_configs.is_on_shelf', $is_on_shelf);
            } else {
                $res->where('book_configs.is_on_shelf', '=', $is_on_shelf);
            }

        }*/

        $res->whereIn('book_configs.is_on_shelf', [1, 2]);
        $res = $res->paginate($page_size);
        foreach ($res as $v) {
            $v->book_url = '/detail?id=' . Hashids::encode($v->bid);
        }
        return $res;
    }

    /**
     * 根据product_id获取图书
     * @param $product_id
     * @return mixed
     */
    public static function getBookByProduct($product_id)
    {
        return self::join('books', 'book_configs.bid', '=', 'books.id')
            ->leftjoin('book_categories', 'books.category_id', 'book_categories.id')
            ->select(
                'book_configs.bid',
                'book_configs.force_subscribe_chapter_seq',
                'book_configs.vip_seq',
                'book_configs.price',
                'book_configs.cover',
                'book_configs.book_name',
                'book_configs.copyright',
                'book_configs.charge_type',
                'book_configs.is_on_shelf',
                'books.author',
                'books.intro',
                'book_categories.category_name',
                'category_id',
                'status',
                'chapter_count',
                'first_cid',
                'last_cid',
                'size',
                'last_chapter',
                'books.keyword',
                'book_configs.recommend_index',
                'book_configs.is_show_index_content',
                'book_configs.click_count',
                'book_configs.product_id',
                'book_categories.channel_name',
                'books.last_cid',
                'books.last_chapter',
                'book_configs.product_id',
                'book_configs.recommend_cid',
                'book_configs.is_high_quality'
            )->where('book_configs.product_id', $product_id)->first();
    }

    /**
     * 更新图书
     * @param       $bid
     * @param array $param
     * @return bool
     */
    public static function updateBookInfo($bid, array $param)
    {
        $book_info = self::getBookById($bid);
        if (!$book_info) return false;

        $update_data = [];
        if (isset($param['force_subscribe_chapter_seq']) && !empty($param['force_subscribe_chapter_seq'])) $update_data['force_subscribe_chapter_seq'] = $param['force_subscribe_chapter_seq'];

        if (isset($param['product_id']) && !empty($param['product_id'])) $update_data['product_id'] = $param['product_id'];
        if (isset($param['book_name']) && !empty($param['book_name'])) $update_data['book_name'] = $param['book_name'];
        if (isset($param['price']) && !empty($param['price'])) $update_data['price'] = $param['price'];
        if (isset($param['cover']) && !empty($param['cover'])) $update_data['cover'] = $param['cover'];

        if (isset($param['charge_type']) && !empty($param['charge_type'])) {
            $update_data['charge_type'] = $param['charge_type'];
            if (is_numeric($update_data['charge_type'])) {
                $update_data['charge_type'] = 'CHAPTER';
            }
        }

        if (isset($param['hot']) && !empty($param['hot'])) $update_data['hot'] = $param['hot'];
        if (isset($param['roles']) && !empty($param['roles'])) $update_data['roles'] = $param['roles'];
        if (isset($param['is_on_shelf']) && $param['is_on_shelf'] != '') $update_data['is_on_shelf'] = $param['is_on_shelf'];
        if (isset($param['recommend_index']) && !empty($param['recommend_index'])) $update_data['recommend_index'] = $param['recommend_index'];
        if (isset($param['is_show_index_content'])) $update_data['is_show_index_content'] = $param['is_show_index_content'];
        if (isset($param['click_count']) && $param['click_count'] != '') $update_data['click_count'] = $param['click_count'];
        if (isset($param['copyright_limit_data']) && $param['copyright_limit_data'] != '') $update_data['copyright_limit_data'] = $param['copyright_limit_data'];
        if (isset($param['promotion_domain']) && $param['promotion_domain'] != '') $update_data['promotion_domain'] = $param['promotion_domain'];
        if (isset($param['copyright']) && $param['copyright'] != '') $update_data['copyright'] = $param['copyright'];
        $res1 = null;
        if (isset($param['status'])) {
            $res1 = Book::where('id', $bid)->update(['status' => $param['status']]);
        }
        if (isset($param['book_category_id'])) {
            $catagory = BookCategory::select('category_name')->where('id', $param['book_category_id'])->first();
            Book::where('id', $bid)->update(['category_id' => $param['book_category_id'], 'category_name' => $catagory->category_name]);
        }
        if (empty($update_data) && !$res1) return false;
        return self::where('bid', $bid)->update($update_data);
    }

    /*
     * 获取渠道,用户的全部书籍列表
    */
    public static function getLeftRecommendBook($channel_name, $is_high_quality, $force_update = false): array
    {
        if ($force_update) {
            Redis::set('full_book_channel_name:' . $channel_name, null);
        }

        // 存redis里面
        $full_book_bids = Redis::get('full_book_channel_name:' . $channel_name);
        $full_book_bids = json_decode($full_book_bids);
        if (!empty($full_book_bids)) {
        } else {
            // 获取全集
            $full_book_bids = self::join('books', 'book_configs.bid', '=', 'books.id')
                ->leftjoin('book_categories', 'books.category_id', 'book_categories.id')
                ->select('book_configs.bid')
                ->where('book_categories.channel_name', $channel_name)
                ->where('book_configs.is_high_quality', $is_high_quality)
                ->where('book_configs.test_status', 0) // 不含测书
                ->whereIn('book_configs.is_on_shelf', [2])
                ->orderBy('book_configs.id', 'desc')
                ->get()->pluck('bid')->all();
            if (!empty($full_book_bids)) {
                Log::info('set_full_book_channel_name:' . $channel_name . ' data:' . json_encode($full_book_bids));
                Redis::set('full_book_channel_name:' . $channel_name, json_encode($full_book_bids));
            }
        }

        return $full_book_bids;
    }

    /*
     * 获取渠道,用户的全部需要测试的书籍列表
    */
    public static function getLeftRecommendTestBook($channel_name)
    {
        // 获取test全集
        $test_bids = self::getLeftRecommendTestBookConfigs($channel_name);
        $last_bids = [];
        if (!empty($test_bids)) {
            foreach ($test_bids as $test_bid) {
                $bid                = $test_bid->bid;
                $redis_bid_push_num = Redis::hget('SmartPushBookUserNum', $bid);
                $plan_push_user_num = $test_bid->plan_push_user_num;
                Log::info('left_test_book,bid:' . $bid . ' redis_bid_push_num:' . $redis_bid_push_num . ' plan_push_user_num:' . $plan_push_user_num);

                if ($redis_bid_push_num >= $plan_push_user_num) {
                    Log::info('full_update_test_book,bid:' . $bid . ' redis_bid_push_num:' . $redis_bid_push_num . ' plan_push_user_num:' . $plan_push_user_num);
                    self::where('bid', $bid)->update(['test_status' => 2, 'test_update_time' => date('Y-m-d H:i:s')]);

                    continue;
                }
                $last_bids[] = $bid;
            }
        }
        return $last_bids;
    }

    /*
     * 获取渠道,用户的全部需要测试的书籍列表
    */
    public static function getLeftRecommendTestBookConfigs($channel_name)
    {
        // 获取全集
        return self::join('books', 'book_configs.bid', '=', 'books.id')
            ->leftjoin('book_categories', 'books.category_id', 'book_categories.id')
            ->select('book_configs.bid', 'book_configs.plan_push_user_num')
            ->where('book_categories.channel_name', $channel_name)
            ->where('book_configs.test_status', 1) // 待测
            ->groupBy('book_configs.bid')
            ->orderBy('book_configs.test_weight', 'desc')
            ->orderBy('book_configs.test_update_time', 'asc')
            ->limit(1) // 每次1本
            ->get();
    }

    /*
     * 获取用户的曾经推荐过的书籍列表
    */
    public static function getUserRecommendRecords($uid)
    {
        $recommend_bids = Redis::smembers('userRecommendBids:' . $uid);
        return $recommend_bids;
    }

    /*
     * 添加用户的曾经推荐过的书籍列表
    */
    public static function addUserRecommendRecords($uid, $bids)
    {
        foreach ($bids as $bid) {
            Redis::sadd('userRecommendBids:' . $uid, $bid);
        }
    }

    /*
     * 清楚用户的曾经推荐过的书籍列表
    */
    public static function truncateUserRecommendRecords($uid)
    {
        Log::info('truncateUserRecommendRecords:' . $uid);
        Redis::del('userRecommendBids:' . $uid);
    }

    /*
     * 书籍推送量+1
    */
    public static function incrBidPushNum($last_bids)
    {
        if (!empty($last_bids)) {
            foreach ($last_bids as $last_bid) {
                //     			Log::info('incrBidPushNum:test_bid' . $last_bid);
                Redis::hincrby('SmartPushBookUserNum', $last_bid, 1);
            }
        }
    }

    /*
     * 获取相同频道的4本高推荐图书
    * 1、新书倒序  2、用户推荐过的,有阅读记录的不再推荐
    */
    public static function getLeftRecommendBids($uid = '', $channel_name, $num = 4, $loop = 1)
    {
        // 获取用户阅读记录详情
        $read_bids = ReadRecordService::getSimpleReadRecord($uid);

        // 获取用户推荐过的详情
        $recommend_bids = self::getUserRecommendRecords($uid);

        // 获取全集,不含测试书籍
        $full_bids = $full_bid_no_tests = self::getLeftRecommendBook($channel_name, 1, false);

        //判断如果注册时间小于15天,不推测试书籍
        $test_book = null;

        $last_bids = array();
        try {
            if ($uid) {
                $user = UserService::getById($uid);
                if ($user && (time() - strtotime($user->created_at) > 15 * 86400)) {
                    $channel_sex = $channel_name == '男频' ? 1 : 2;
                    $temp        = TestBookService::getTestBook($channel_sex);
                    $test_res    = false;

                    if ($channel_sex == 2 && $guyan_test_book = TestBookService::getTestBook($channel_sex, 'GUYAN'))//女频古言优先判断
                    {
                        if (!in_array($guyan_test_book->bid, $read_bids)) {
                            $user_property = NovelUserPorperty::model(date('Ymd'))->where('uid', $uid)->first();
                            if ($user_property && in_array($user_property->category, TestBookService::gu_yan)) {
                                $test_book = $guyan_test_book;
                                $test_res  = true;
                            }
                        }
                    }
                    if (!$test_res) if ($temp && !in_array($temp->bid, $read_bids)) $test_book = $temp;
                }
            }

            $test_book && $full_bids = array_merge([$test_book->bid], $full_bid_no_tests);

            // 得到差集
            $left_bids    = array_diff($full_bids, $recommend_bids, $read_bids);
            $left_bid_num = count($left_bids);

            if ($left_bid_num) {
                $last_bids = array_slice($left_bids, 0, $num, false);
            } else {
                //判断推送的书都被阅读情况下 随机从优质书中取
                if (!$not_read_bids = array_diff($full_bids, $read_bids)) {
                    $last_bids[] = $full_bid_no_tests[array_rand($full_bid_no_tests)];
                } else {
                    //推送过但未阅读情况下,清空继续推
                    self::truncateUserRecommendRecords($uid);
                    $last_bids = array_slice($not_read_bids, 0, $num, false);
                }
            }

            // 加入已经推荐
            self::addUserRecommendRecords($uid, $last_bids);

            // 书籍推送量+1
            self::incrBidPushNum($last_bids);

            foreach ($last_bids as $_bid) {
                if ($test_book && $test_book->bid == $_bid) {
                    $redis_bid_push_num = Redis::hget('SmartPushBookUserNum', $_bid);
                    $plan_push_user_num = $test_book->plan_push_user_num;
                    $uid && TestBookService::record($test_book->id, $uid);

                    if ($redis_bid_push_num >= $plan_push_user_num) {
                        TestBookService::finishTest($_bid);
                    }
                }
            }
        } catch (Exception $e) {
            Log::error('get test book error:' . $e->getMessage() . $e->getLine());
            $last_bids = [$full_bid_no_tests[array_rand($full_bid_no_tests)]];
        }

        return $last_bids;
    }

    /*
     * 获取相同频道的4本高推荐图书(循环获取)
     * 1、新书倒序  2、用户推荐过的,有阅读记录的不再推荐
     */
    public static function getSimpleChannelBookLoop($bid, $num = 4, $uid = '', $property = '')
    {
        if (empty($uid)) {
            return self::getSimpleChannelBook($bid, $num, $property);
        }

        // 站点设置的属性
        if (in_array($property, [ChannelConst::PROPERTY_MALE, ChannelConst::PROPERTY_FEMALE], true)) {
            $channel_name = $property === ChannelConst::PROPERTY_MALE ? '男频' : '女频';
        } else {
            $book_info    = self::getBookById($bid);
            $channel_name = getProp($book_info, 'channel_name', '女频');
        }

        // 获取全集,减去阅读记录和推荐过的书籍id
        $bids = self::getLeftRecommendBids($uid, $channel_name, $num, 1);

        $res = self::join('books', 'book_configs.bid', '=', 'books.id')
            ->leftjoin('book_categories', 'books.category_id', 'book_categories.id')
            ->select(
                'book_configs.bid',
                'book_configs.force_subscribe_chapter_seq',
                'book_configs.vip_seq',
                'book_configs.price',
                'books.updated_at as last_update_time',
                'book_configs.cover',
                'book_configs.book_name',
                'book_configs.copyright',
                'book_configs.charge_type',
                'book_configs.is_on_shelf',
                'books.author',
                'books.intro',
                'book_categories.category_name',
                'category_id',
                'status',
                'chapter_count',
                'first_cid',
                'last_cid',
                'size',
                'last_chapter',
                'books.keyword',
                'book_configs.recommend_index',
                'book_configs.is_show_index_content',
                'book_configs.click_count',
                'book_configs.product_id',
                'book_categories.channel_name',
                'books.last_cid',
                'books.last_chapter',
                'book_configs.product_id',
                'books.name as old_name',
                'book_configs.recommend_cid',
                'book_configs.is_high_quality'
            )
            ->whereIn('book_configs.bid', $bids)
            ->orderBy('book_configs.id', 'desc')
            ->get();
        foreach ($res as $v) {
            $v->url = '/reader?bid=' . Hashids::encode($v->bid) . '&cid=' . $v->first_cid;
        }
        return $res;
    }

    public static function getHotRandomRecommendBooks($uid, $num = 2)
    {
        $sex          = ForceSubscribeService::getSimpleSexByUid($uid);
        $channel_name = $sex == 1 ? '男频' : '女频';
        Log::info('getHotRandomRecommendBooks,uid:' . $uid . ' num:' . $num . ' channel_name:' . $channel_name);
        $bids = self::getRandomRecommendBooks($channel_name, $num);
        return $bids;
    }

    public static function getSpecialHotRandomRecommendBooks($num = 2, $channel_name = '女频')
    {
        $bids = self::getRandomRecommendBooks($channel_name, $num);
        return self::getBidRecommendBooks($bids);
    }

    public static function getHotRandomRecommendBookText($distribution_channel_id, $uid, $num)
    {
        $bids         = self::getHotRandomRecommendBooks($uid, $num);
        $recomm_books = BookConfigService::getBooksByIds($bids, ['bid', 'asc']);
        $content      = '';
        if ($recomm_books) {
            // 判断是否不展示书名
            $self_config      = ChannelService::check_channel_account_priv($distribution_channel_id, 'hide_book_name');
            $hide_type        = isset($self_config->type) ? $self_config->type : 'not_hide';
            $recommend_titles = [];
            if ($hide_type == 'hide_book_name') {
                Log::info('hide_book_name:' . $distribution_channel_id . ' uid:' . $uid);
                $sex              = ForceSubscribeService::getSimpleSexByUid($uid);
                $recommend_titles = PromotionService::getRandomHeadline($sex, count($recomm_books));
            }

            $content .= "\n\n" . '热门书籍推荐';
            foreach ($recomm_books as $key => $book) {
                $book_name = $book->book_name;
                if ($hide_type == 'hide_book_name') {
                    $book_name = isset($recommend_titles[$key]->title) ? $recommend_titles[$key]->title : $book->book_name;
                }

                $url     = env('PROTOCOL') . '://site' . encodeDistributionChannelId($distribution_channel_id) . '.' . env('CUSTOM_HOST') . '.com/reader?bid=' . Hashids::encode($book->bid) . '&cid=' . $book->first_cid;
                $content .= "\n\n" . '<a href="' . $url . '"> ☞ 《' . $book_name . '》</a>';
            }
        }
        return $content;
    }


    /**
     * 获取h5推荐的图书
     */
    public static function getH5RecommendBooks($uid, $pos, $num = 4)
    {

        $sex          = ForceSubscribeService::getSimpleSexByUid($uid);
        $channel_name = $sex == 1 ? '男频' : '女频';
        Log::info('getH5RecommendBooks:pos:' . $pos . ' uid:' . $uid . ' num:' . $num . ' channel_name:' . $channel_name);
        $bids = [];

        // 先从缓存取,1天有效期
        $h5_book_cache = Redis::get('userH5RecommendBids:' . $uid . ':' . $pos);
        if (!empty($h5_book_cache)) {
            Log::info('h5_book_cache_exist:' . $uid);
            return json_decode($h5_book_cache);
        }

        $bids             = [];
        $random_recommend = true;
        if ($random_recommend) {
            $bids = self::getRandomRecommendBooks($channel_name, $num);
        }

        $forceSubscribeUser      = ForceSubscribeService::forceSubscribeUsersByUid(['uid' => $uid]);
        $distribution_channel_id = isset($forceSubscribeUser->distribution_channel_id) ? $forceSubscribeUser->distribution_channel_id : '';

        Log::info('getH5RecommendBooks:uid:' . $uid . ' distribution_channel_id:' . $distribution_channel_id . ' bids:' . json_encode($bids));

        if (!empty($bids)) {
            $books = BookConfigService::getBooksByIds($bids, ['bid', 'asc']);
            $data  = $books->toArray();
            // 有效期24小时
            $redis_key = 'userH5RecommendBids:' . $uid . ':' . $pos;
            Redis::set($redis_key, json_encode(object_to_array($data)));
            Redis::expire($redis_key, 3600 * 24);
        }

        return $books;
    }

    /**
     * 获取随机的推荐书籍bid
     */
    public static function getRandomRecommendBooks($channel_name, $num)
    {
        $bids = self::join('books', 'book_configs.bid', '=', 'books.id')
            ->leftjoin('book_categories', 'books.category_id', 'book_categories.id')
            ->select('book_configs.bid')
            ->where('book_categories.channel_name', $channel_name)
            ->where('book_configs.is_high_quality', 1)
            ->where('book_configs.test_status', 0) // 不含测书
            ->whereIn('book_configs.is_on_shelf', [2])
            ->inRandomOrder()
            ->limit($num)
            ->get()->pluck('bid')->all();
        return $bids;
    }


    /*
     * 获取相同频道的4本高推荐图书
    */
    public static function getSimpleChannelBook($bid, $num = 4, $property = '')
    {
        $book_info = self::getBookById($bid);
        if (!$book_info) return false;

        // 站点设置的属性
        $channel_name = $book_info->channel_name;
        if (in_array($property, [ChannelConst::PROPERTY_MALE, ChannelConst::PROPERTY_FEMALE], true)) {
            $channel_name = $property === ChannelConst::PROPERTY_MALE ? '男频' : '女频';
        }

        $res = self::join('books', 'book_configs.bid', '=', 'books.id')
            ->leftjoin('book_categories', 'books.category_id', 'book_categories.id')
            ->select(
                'book_configs.bid',
                'book_configs.force_subscribe_chapter_seq',
                'book_configs.vip_seq',
                'book_configs.price',
                'books.updated_at as last_update_time',
                'book_configs.cover',
                'book_configs.book_name',
                'book_configs.copyright',
                'book_configs.charge_type',
                'book_configs.is_on_shelf',
                'books.author',
                'books.intro',
                'book_categories.category_name',
                'category_id',
                'status',
                'chapter_count',
                'first_cid',
                'last_cid',
                'size',
                'last_chapter',
                'books.keyword',
                'book_configs.recommend_index',
                'book_configs.is_show_index_content',
                'book_configs.click_count',
                'book_configs.product_id',
                'book_categories.channel_name',
                'books.last_cid',
                'books.last_chapter',
                'book_configs.product_id',
                'books.name as old_name',
                'book_configs.recommend_cid',
                'book_configs.is_high_quality'
            )
            ->where('book_categories.channel_name', $channel_name)
            ->where('book_configs.is_high_quality', 1)
            ->whereIn('book_configs.is_on_shelf', [2])
            ->orderBy('recommend_index', 'desc')
            ->get()
            ->random($num);
        foreach ($res as $v) {
            $v->url = '/reader?bid=' . Hashids::encode($v->bid) . '&cid=' . $v->first_cid;
        }
        return $res;
    }

    /*
     * 获取托管智能推送的书籍,头条要95分以上,其余4条优质书库随机,按分数倒叙排列
     * 新版1条
    */
    public static function getTrusteeShipChannelBook($distribution_channel_id, $channel_name, $num = 4)
    {
        // 找头条
        $first_res = self::join('books', 'book_configs.bid', '=', 'books.id')
            ->leftjoin('book_categories', 'books.category_id', 'book_categories.id')
            ->select('book_configs.bid', 'book_configs.recommend_index')
            ->where('book_categories.channel_name', $channel_name)
            ->where('book_configs.is_high_quality', 1)
            //     	->where('book_configs.recommend_index', '>=',95)
            ->whereIn('book_configs.is_on_shelf', [2])
            ->orderBy('recommend_index', 'desc')
            ->limit(50)
            ->get()
            ->random(1);

        Log::info('$first_res');
        Log::info($first_res);

        $bids   = [];
        $bids[] = $first_res[0]->bid;

        Log::info('getTrusteeShipChannelBook_bids:' . json_encode($bids));

        $res = self::join('books', 'book_configs.bid', '=', 'books.id')
            ->leftjoin('book_categories', 'books.category_id', 'book_categories.id')
            ->select(
                'book_configs.bid',
                'book_configs.force_subscribe_chapter_seq',
                'book_configs.vip_seq',
                'book_configs.price',
                'books.updated_at as last_update_time',
                'book_configs.cover',
                'book_configs.book_name',
                'book_configs.copyright',
                'book_configs.charge_type',
                'book_configs.is_on_shelf',
                'books.author',
                'books.intro',
                'book_categories.category_name',
                'category_id',
                'status',
                'chapter_count',
                'first_cid',
                'last_cid',
                'size',
                'last_chapter',
                'books.keyword',
                'book_configs.recommend_index',
                'book_configs.is_show_index_content',
                'book_configs.click_count',
                'book_configs.product_id',
                'book_categories.channel_name',
                'books.last_cid',
                'books.last_chapter',
                'book_configs.product_id',
                'books.name as old_name',
                'book_configs.recommend_cid',
                'book_configs.is_high_quality'
            )
            ->where('book_categories.channel_name', $channel_name)
            ->where('book_configs.is_high_quality', 1)
            ->whereIn('book_configs.bid', $bids)
            ->orderBy('recommend_index', 'desc')
            ->get();

        foreach ($res as $v) {
            $v->url = '/reader?bid=' . Hashids::encode($v->bid) . '&cid=' . $v->first_cid;
        }
        Log::info('last_res');
        Log::info($res);
        return $res;
    }

    /*
     * 获取托管智能推送的书籍,头条要95分以上,其余4条优质书库随机,按分数倒叙排列
     * 老版多条
    */
    public static function getTrusteeShipChannelBookMulty($distribution_channel_id, $channel_name, $num = 4)
    {
        // TODO 内部渠道的书=内部+外部,外部渠道的书=外部
        // 内部上架判断有点复杂,先统一外部上架
        // 找头条
        $first_res = self::join('books', 'book_configs.bid', '=', 'books.id')
            ->leftjoin('book_categories', 'books.category_id', 'book_categories.id')
            ->select('book_configs.bid', 'book_configs.recommend_index')
            ->where('book_categories.channel_name', $channel_name)
            ->where('book_configs.is_high_quality', 1)
            //     	->where('book_configs.recommend_index', '>=',95)
            ->whereIn('book_configs.is_on_shelf', [2])
            ->orderBy('recommend_index', 'desc')
            ->limit(10)
            ->get()
            ->random(1);

        Log::info('$first_res');
        Log::info($first_res);

        $bids   = [];
        $bids[] = $first_res[0]->bid;

        // 找其余3条
        $left_res = self::join('books', 'book_configs.bid', '=', 'books.id')
            ->leftjoin('book_categories', 'books.category_id', 'book_categories.id')
            ->select('book_configs.bid')
            ->where('book_categories.channel_name', $channel_name)
            ->where('book_configs.is_high_quality', 1)
            ->whereNotIn('book_configs.bid', $bids)
            ->whereIn('book_configs.is_on_shelf', [2])
            ->orderBy('recommend_index', 'desc')
            ->get()
            ->random(3);
        Log::info('left_res');
        Log::info($left_res);

        foreach ($left_res as $left_r) {
            $bids[] = $left_r->bid;
        }

        Log::info('getTrusteeShipChannelBook_bids:' . json_encode($bids));

        $res = self::join('books', 'book_configs.bid', '=', 'books.id')
            ->leftjoin('book_categories', 'books.category_id', 'book_categories.id')
            ->select(
                'book_configs.bid',
                'book_configs.force_subscribe_chapter_seq',
                'book_configs.vip_seq',
                'book_configs.price',
                'books.updated_at as last_update_time',
                'book_configs.cover',
                'book_configs.book_name',
                'book_configs.copyright',
                'book_configs.charge_type',
                'book_configs.is_on_shelf',
                'books.author',
                'books.intro',
                'book_categories.category_name',
                'category_id',
                'status',
                'chapter_count',
                'first_cid',
                'last_cid',
                'size',
                'last_chapter',
                'books.keyword',
                'book_configs.recommend_index',
                'book_configs.is_show_index_content',
                'book_configs.click_count',
                'book_configs.product_id',
                'book_categories.channel_name',
                'books.last_cid',
                'books.last_chapter',
                'book_configs.product_id',
                'books.name as old_name',
                'book_configs.recommend_cid',
                'book_configs.is_high_quality'
            )
            ->where('book_categories.channel_name', $channel_name)
            ->where('book_configs.is_high_quality', 1)
            ->whereIn('book_configs.bid', $bids)
            ->orderBy('recommend_index', 'desc')
            ->get();

        foreach ($res as $v) {
            $v->url = '/reader?bid=' . Hashids::encode($v->bid) . '&cid=' . $v->first_cid;
        }
        Log::info('last_res');
        Log::info($res);
        return $res;
    }

    /*
    * H5专用,用户阅读完推荐
    * 获取相同推荐
    */
    public static function getRecommendBooks($bid, $channel_name, $num = 4)
    {
        $res   = self::join('books', 'book_configs.bid', '=', 'books.id')
            ->leftjoin('book_categories', 'books.category_id', 'book_categories.id')
            ->select(
                'book_configs.bid',
                'book_configs.force_subscribe_chapter_seq',
                'book_configs.vip_seq',
                'book_configs.price',
                'book_configs.cover',
                'book_configs.book_name',
                'book_configs.copyright',
                'book_configs.charge_type',
                'book_configs.is_on_shelf',
                'books.author',
                'books.intro',
                'book_categories.category_name',
                'category_id',
                'status',
                'chapter_count',
                'first_cid',
                'last_cid',
                'size',
                'last_chapter',
                'books.keyword',
                'book_configs.recommend_index',
                'book_configs.is_show_index_content',
                'book_configs.click_count',
                'book_configs.product_id',
                'book_categories.channel_name',
                'books.last_cid',
                'books.last_chapter',
                'book_configs.product_id',
                'books.name as old_name',
                'book_configs.recommend_cid',
                'book_configs.is_high_quality',
                'books.updated_at as last_update_time'
            )
            ->where('book_categories.channel_name', $channel_name)
            ->where('book_configs.bid', '!=', $bid)
            ->where('book_configs.is_high_quality', 1)
            ->orderBy('recommend_index', 'desc')->get();
        $count = $res->count() >= $num ? $num : $res->count();
        return $res->random($count);
    }

    /*
    * 签到专用
    * 获取相同推荐
    */
    public static function getSignRecommendBooks(array $bid, $channel_name, $num = 2)
    {
        $res   = self::join('books', 'book_configs.bid', '=', 'books.id')
            ->leftjoin('book_categories', 'books.category_id', 'book_categories.id')
            ->select(
                'book_configs.bid',
                'book_configs.force_subscribe_chapter_seq',
                'book_configs.vip_seq',
                'book_configs.price',
                'book_configs.cover',
                'book_configs.book_name',
                'book_configs.copyright',
                'book_configs.charge_type',
                'book_configs.is_on_shelf',
                'books.author',
                'books.intro',
                'book_categories.category_name',
                'category_id',
                'status',
                'chapter_count',
                'first_cid',
                'last_cid',
                'size',
                'last_chapter',
                'books.keyword',
                'book_configs.recommend_index',
                'book_configs.is_show_index_content',
                'book_configs.click_count',
                'book_configs.product_id',
                'book_categories.channel_name',
                'books.last_cid',
                'books.last_chapter',
                'book_configs.product_id',
                'books.name as old_name',
                'book_configs.recommend_cid',
                'book_configs.is_high_quality',
                'books.updated_at as last_update_time'
            )
            ->where('book_categories.channel_name', $channel_name)
            ->where('book_configs.is_on_shelf', 2)
            ->whereNotIn('book_configs.bid', $bid)
            ->where('book_configs.is_high_quality', 1)
            ->get();
        $count = $res->count() >= $num ? $num : $res->count();
        return $res->random($count);
    }

    /*
    * 获取指定bid的书籍推荐
    */
    public static function getBidRecommendBooks(array $bids)
    {
        $res = self::join('books', 'book_configs.bid', '=', 'books.id')
            ->leftjoin('book_categories', 'books.category_id', 'book_categories.id')
            ->select(
                'book_configs.bid',
                'book_configs.force_subscribe_chapter_seq',
                'book_configs.vip_seq',
                'book_configs.price',
                'book_configs.cover',
                'book_configs.book_name',
                'book_configs.copyright',
                'book_configs.charge_type',
                'book_configs.is_on_shelf',
                'books.author',
                'books.intro',
                'book_categories.category_name',
                'category_id',
                'status',
                'chapter_count',
                'first_cid',
                'last_cid',
                'size',
                'last_chapter',
                'books.keyword',
                'book_configs.recommend_index',
                'book_configs.is_show_index_content',
                'book_configs.click_count',
                'book_configs.product_id',
                'book_categories.channel_name',
                'books.last_cid',
                'books.last_chapter',
                'book_configs.product_id',
                'books.name as old_name',
                'book_configs.recommend_cid',
                'book_configs.is_high_quality',
                'books.updated_at as last_update_time'
            )
            ->whereIn('book_configs.bid', $bids)
            ->get();

        if (!empty($res)) {
            foreach ($res as $v) {
                $v->url = '/reader?bid=' . Hashids::encode($v->bid) . '&cid=' . $v->first_cid;
            }
        }
        return $res;
    }

    /*
     * 获取指定bid的阅读链接  
    */
    public static function getBidReadUrl($bid, $chapter_num)
    {
        $offset_chapter_num = $chapter_num - 2;
        $res                = DB::select('select chapters.bid,chapters.sequence,chapters.next_cid
    			from chapters where bid=' . $bid . '
    			order by sequence asc
    			limit 1
    			offset ' . $offset_chapter_num);

        $read_url = '';
        if (!empty($res)) {
            foreach ($res as $v) {
                $read_url = '/reader?bid=' . Hashids::encode($v->bid) . '&cid=' . $v->next_cid;
                break;
            }
        }
        if (empty($read_url)) $read_url = '?';

        Log::Info('getBidReadUrl,$bid:' . $bid . ' $chapter_num:' . $chapter_num . ' $read_url:' . $read_url);
        return $read_url;
    }

    /**
     * 修改vip章节
     */
    public static function updateVipSeq($bid, $seq)
    {
        return self::where('bid', $bid)->update(['vip_seq' => $seq]);
    }

    public static function getAllBooks($on_shelf, $order)
    {
        if (!$order) {
            $order = ['id', 'asc'];
        }
        return self::whereIn('is_on_shelf', $on_shelf)->select('bid', 'book_name')->orderBy($order[0], $order[1])->get();
    }

    /**
     * 根据条件获取书籍,没有分页
     */
    public static function getBooksNoPage(array $where = [], array $order = [], array $on_shelf, $limit = 20)
    {
        if (!$order) {
            $order = [['recommend_index', 'desc']];
        }
        $res = self::join('books', 'book_configs.bid', '=', 'books.id')
            ->leftjoin('book_categories', 'books.category_id', 'book_categories.id')
            ->select(
                'book_configs.bid',
                'book_configs.force_subscribe_chapter_seq',
                'book_configs.cp_source',
                'book_configs.vip_seq',
                'book_configs.price',
                'book_configs.cover',
                'book_configs.book_name',
                'book_configs.copyright',
                'book_configs.charge_type',
                'book_configs.is_on_shelf',
                'books.author',
                'books.intro',
                'book_categories.category_name',
                'category_id',
                'status',
                'chapter_count',
                'book_configs.click_count',
                'first_cid',
                'last_cid',
                'size',
                'last_chapter',
                'books.keyword',
                'book_configs.recommend_index',
                'book_configs.is_show_index_content',
                'book_configs.product_id',
                'book_categories.channel_name',
                'books.last_cid',
                'books.last_chapter',
                'book_configs.product_id',
                'book_configs.copyright_limit_data',
                'books.updated_at as last_update_time',
                'book_configs.promotion_domain',
                'books.name as old_name',
                'book_configs.recommend_cid',
                'book_configs.is_high_quality'
            );
        if ($where) {
            foreach ($where as $v) {
                $res->where($v[0], $v[1], $v[2]);
            }
        }
        $res->whereIn('is_on_shelf', $on_shelf);
        foreach ($order as $v) {
            $res->orderBy($v[0], $v[1]);
        }

        return $res->limit($limit)->get();
    }


    public static function getAllCps()
    {
        $cps    = self::select('cp_source')->groupBy('cp_source')->get();
        $result = array();
        foreach ($cps as $cp) {
            if (!empty($cp['cp_source'])) {
                $result[] = $cp['cp_source'];
            }
        }
        return $result;
    }

    public static function getAllCpBooks()
    {
        $result   = array();
        $cp_books = self::select('cp_source', 'bid')->groupBy('cp_source')->groupBy('bid')->get();
        foreach ($cp_books as $cp_book) {
            $result[$cp_book['cp_source']][] = $cp_book['bid'];
        }
        return $result;
    }

    /*
     * 得到cp某段时间某本书的消费
    */
    public static function getAllCpBookConsume($start_date, $end_date, $cps, $yestoday)
    {
        $result = self::leftjoin('book_order_statistical', 'book_order_statistical.bid', '=', 'book_configs.bid')
            // 
            ->leftjoin('cp_book_time_configs', function ($join) {
                $join->on('cp_book_time_configs.bid', '=', 'book_configs.bid')
                    ->on('cp_book_time_configs.cp_source', '=', 'book_configs.cp_source');
            })
            ->select(
                'book_order_statistical.bid',
                DB::raw('sum(book_order_statistical.charge_balance) as charge_balance'),
                DB::raw('(select book_order_statistical.charge_balance from book_order_statistical where book_order_statistical.bid=book_configs.bid and day="' . $yestoday . '" limit 1) as yestoday_charge_balance'),
                'book_configs.book_name',
                'book_configs.is_on_shelf',
                'book_configs.cp_source'
            )
            ->whereIn('book_configs.cp_source', $cps)
            // 2个起始值取最大值
            ->where('book_order_statistical.day', '>=', DB::raw("ifnull(cp_book_time_configs.start_date,'')"))
            ->where('book_order_statistical.day', '>=', $start_date)
            ->where('book_order_statistical.day', '<=', $end_date)
            ->groupBy('book_configs.cp_source')
            ->groupBy('book_order_statistical.bid')
            ->get();
        return $result;
    }

    public static function getBookByIdAndStatus($bid, $status)
    {
        return self::where('bid', $bid)->whereIn('is_on_shelf', $status)->first();
    }

    public static function get_all_test_books($is_all = false)
    {
        if ($is_all) {
            return self::where('test_status', '<>', 0)->orderBy('test_status', 'asc')->orderBy('test_update_time', 'desc')->get();
        } else {
            return self::where('test_status', '<>', 0)->orderBy('test_status', 'asc')->orderBy('test_update_time', 'desc')->paginate();
        }
    }

    public static function get_test_books($test_status)
    {
        return self::where('test_status', $test_status)->get();
    }

    public static function updateTestBook($bid, $test_status, $plan_push_user_num = 10000)
    {
        return self::where('bid', $bid)->update(['test_status' => $test_status, 'plan_push_user_num' => $plan_push_user_num, 'test_update_time' => date('Y-m-d H:i:s')]);
    }

    public static function get_all_smart_push_books($is_all = false)
    {
        if ($is_all) {
            return self::where('is_on_shelf', 2)->where('is_high_quality', 1)->orderBy('id', 'desc')->get();
        } else {
            return self::where('is_on_shelf', 2)->where('is_high_quality', 1)->orderBy('id', 'desc')->paginate();
        }
    }


    /**
     * 获取书本的id,名称,作者,封面 并带分页
     * @param bool $isAll 是否查询所有
     * @param int  $pageSize 每页的条数
     * @param int  $pageCount 页数
     * @return mixed
     */
    static function getBookCoverInfos($isAll = false, $pageSize = 200, $pageCount = 0)
    {
        $obj = self::join('books', 'book_configs.bid', '=', 'books.id')->select('book_configs.bid', 'book_configs.book_name', 'books.author', 'book_configs.cover');
        if ($isAll) {
            return $obj->get();
        } else {
            return $obj->limit($pageSize)->offset($pageCount * $pageSize)->get();
        }
    }

    /**
     * 获取书本的总数
     * @return mixed
     */
    static function getBooksCount()
    {
        return self::count();
    }

    /**
     * 通过书名模糊搜索bid
     * @param $book_name
     * @return mixed
     */
    static function getIdByName($book_name)
    {
        return self::select('bid')->where('book_name', 'like', '%' . $book_name . '%')->get();
    }
    
    
    static function getBooksByBid($bid)
    {
        return self::where('id', '>', $bid)
        ->where('is_on_shelf', 2)
        ->where('test_status', 0)
        ->orderBy('id', 'asc')->limit(500)->get();
    }
    
    static function getOneByBid($bid)
    {
        return self::where('bid',  $bid)->first();
    }
    
    static function getBooksByOffsetTime($offset_time=30,$is_full_push=false)
    {
        if($is_full_push){
            return self::whereIn('is_on_shelf', [1,2])
            ->orderBy('id', 'asc')->get();
        }else{
            $start_updated_time = date("Y-m-d H:i:s",time() - $offset_time*60);
            return self::where('updated_at', '>=', $start_updated_time)
            ->whereIn('is_on_shelf', [1,2])
            ->orderBy('id', 'asc')->limit(500)->get();
        }
        
    }
    
    
}