<?php
/**
 * Created by PhpStorm.
 * User: tandunzhao
 * Date: 2017/12/4
 * Time: 下午1:57
 */

namespace App\Modules\Book\Services;

use App\Modules\Book\Models\Book;
use App\Modules\Book\Models\Chapter;
use OSS\Core\OssException;
use OSS\OssClient;
use Redis;
use Storage;
use Log;

class ChapterService
{
    public static $bucket ;
    public function __construct()
    {
        $this->bucket = env('OSS_BUCKET');
    }

    /**
     * 获取章节内容
     * @param $bid
     * @param $chapter_id
     * @return array|bool|mixed|null|string
     */
    public static function getChapter($bid,$chapter_id){
        if(empty($bid) || empty($chapter_id))
            return false;
        //Redis::incr('book_'.$bid.'_click_count');
        //从redis获取
        try{
            $res = self::getChapterFromRedis($bid,$chapter_id);
            if($res) {
                return json_decode($res);
            }
        }catch (\Exception $e){
            Log::info($e);
        }

        //从oss获取
        try{
            $res = self::getChapterFromOss($bid,$chapter_id);
            if($res) {
                try{
                    self::saveChapterToRedis($bid,json_decode($res));
                }catch (\Exception $redis){
                    Log::info($redis);
                }
                return json_decode($res);
            }
        }catch (\Exception $e){
            Log::info($e);
        }
        $res = self::getChapterFromDb($bid,$chapter_id);

        if(empty($res)) return false;
        try{
            self::saveChapterToRedis($bid,$res);
            self::saveChapterToOss($bid,$res);
        }catch (\Exception $e){
            Log::info($e);
        }
        return $res;
    }

    /**
     * 根据cid获取章节内容
     * @param $chapter_id
     * @return mixed
     */
    public static function getChapterById($chapter_id){
        return Chapter::getChapterById($chapter_id);
    }


    /**
     * 获取目录不分页
     * @param $bid
     * @return mixed
     */
    public static function getChapterLists($bid)
    {
        $lists = Chapter::getChapterLists($bid);
        return $lists;
    }


    /**
     * 获取目录分页
     * @param $bid
     * @param int $page_size
     * @return mixed
     */
    public static function getChapterListsPage($bid,$page_size=15){
        $lists = Chapter::getChapterListsPage($bid,$page_size);
        return $lists;
    }

    /**
     * 获取章节信息没有内容
     * @param $chapter_id
     * @return mixed
     */
    public static function getChapterNameById($chapter_id,$bid)
    {
        $chapter = Chapter::getChapterNameById($chapter_id);
        if($chapter && $chapter->bid == $bid){
            return $chapter;
        }
        return false;
    }

    /**
     * 获取章节信息没有内容 不做bid的验证
     * @param $chapter_id
     * @return mixed
     */
    public static function getChapterNameByIdNoCheck($chapter_id){
        return Chapter::getChapterNameById($chapter_id);
    }


    /**
     * 获取前五章内容(推广需要)
     * @param $bid
     * @return mixed
     */

    public static function getTopFiveChapter($bid)
    {
        $res = Chapter::getTopFiveChapter($bid);
        return $res;
    }



    /**
     * 从oss获取章节内容
     * @param $chapter_id
     * @param $bid
     */

    public static function getChapterFromOss($bid, $chapter_id)
    {
        $bucket = env('OSS_BUCKET');
        $oss = self::ossObject();
        $path_format = 'book/chapters/%s/%s.json';
        $path = sprintf($path_format, $bid, $chapter_id);
        if ($oss->doesObjectExist($bucket, $path)) {
            return $oss->getObject($bucket, $path);
        }
        return null;
    }

    /**
     * 从redis获取章节内容
     * @param $chapter_id
     * @param $bid
     */

    public static function getChapterFromRedis($bid, $chapter_id)
    {
        $key = sprintf('book_chapter_%s_%s', $bid, $chapter_id);
        //Redis::connection('chapter')
        return Redis::connection('chapter')->get($key);
    }

    /**
     * 从db获取章节内容
     * @param $chapter_id
     * @param $bid
     */

    public static function getChapterFromDb($bid, $chapter_id)
    {
        $chapter = self::getChapterById($chapter_id);
        if ($chapter->bid != $bid) {
            return [];
        }
        return $chapter;
    }

    /**
     * 章节内容保存到oss
     * @param $chapter
     * @param $bid
     */
    public static function saveChapterToOss($bid, $chapter)
    {
        $bucket = env('OSS_BUCKET');
        $file = ('book/' . $bid . '_' . $chapter->id . '.json');
        Storage::put($file, json_encode($chapter));
        $path_format = 'book/chapters/%s/%s.json';
        self::ossObject()->uploadFile($bucket, sprintf($path_format, $bid, $chapter->id), storage_path('app/' . $file));
        Storage::delete($file);
    }

    /**
     * 章节内容保存到redis
     * @param $chapter
     * @param $bid
     */

    public static function saveChapterToRedis($bid, $chapter)
    {
        return Redis::connection('chapter')->setex(sprintf('book_chapter_%s_%s', $bid, $chapter->id),3600, json_encode($chapter));
    }

    /**
     * oss 对象
     * @return null|OssClient
     */

    public static function ossObject()
    {
        $accessKeyId = env('OSS_ACCESS_ID');
        $accessKeySecret = env('OSS_ACCESS_KEY');
        $endpoint = env('OSS_END_POINT');
        $ossClient = null;
        try {
            $ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint);
        } catch (OssException $e) {
            return null;
        }
        return $ossClient;
    }

    //编辑vip章节
    public static function editVip($bid,$seq){
        return Chapter::editVip($bid,$seq);
    }

    public  static function editChapter($chapter){
        $bucket = env('OSS_BUCKET');
        $bid = $chapter->bid;
        $res_db = Chapter::where('id',$chapter->id)->update(['content'=>$chapter->content,'size'=>$chapter->size]);
        //$res_db = true;
        if(self::getChapterFromOss($bid,$chapter->id)){
            $oss = self::ossObject();
            $path_format = 'book/chapters/%s/%s.json';
            $oss->deleteObject($bucket,sprintf($path_format, $bid, $chapter->id));
        }
        self::saveChapterToOss($bid,$chapter);
        $res_redis = self::saveChapterToRedis($bid,$chapter);
        return $res_db  && $res_redis;

    }

    //章节列表和内容
    public static function getChapterPage($bid,$page_size=15){
        return Chapter::getChapterPage($bid,$page_size);
    }

    /**
     * 根据bid和顺序获取章节信息
     * @param $bid
     * @param $seq
     * @return mixed
     */
    public static function getChapterInfoByBidAndSeq($bid,$seq){
        return Chapter::where('bid',$bid)->where('sequence',$seq)->select('id','name')->first();
    }

    public static function updateSequence(int $bid,int $sequence){
        Chapter::where('bid',$bid)->where('sequence','>',$sequence)->decrement('sequence',1);
    }

    public static function updateSequenceIncr(int $bid,int $sequence){
        Chapter::where('bid',$bid)->where('sequence','>=',$sequence)->increment('sequence',1);
    }


    public static function updateChapterName($cid,$name){
        Chapter::where('id',$cid)->update(['name'=>$name]);
    }

    public static function createChapter($param){
        return Chapter::create($param);
    }

    public static function updateOne(int $id,array $param){
        if($param){
            return Chapter::where('id',$id)->update($param);
        }
        return null;
    }

    public static function splitContentAll($bid,$sequence){
        $chapters = Chapter::where('bid',$bid)
        ->where('size','>=',3300)
        ->where('sequence','>=',$sequence)
        ->select('id','sequence')->orderBy('sequence')->get();
        $i = 0;
        $count = 0;
        $end_sequence = 0;
        $start_sequence = 0;
        foreach ($chapters as $k=>$chapter){
            if($k == 0){
                $start_sequence = $chapter->sequence;
            }
            $content = self::splitContent($chapter->id);
            if(!$content) continue;
            //\Log::info($chapter);
            $count += self::createSplitContent($chapter->id,$content,false);
            $end_sequence = $chapter->sequence;
            $i++;
        }
        //\Log::info('$start_sequence is: '.$start_sequence);
        //\Log::info('$end_sequence is: '.($end_sequence+$i+$count));
        self::adjustSequent($bid,$start_sequence,$end_sequence+$i+$count);

        return $count;
    }


    public static function splitContent($chapter_id)
    {
        $chapter = self::getChapterById($chapter_id);
        if(!$chapter || $chapter->bid <0 || $chapter->size < 3300) return [];
        $content_list = explode("\r\n",$chapter->content);
        //print_r($content_list);
        $count = 1;
        $temp_size= 0;
        $temp_content = '';
        $data = [];
        foreach ($content_list as $item){
            if($temp_size >2500){
                $count++;
                $temp_content = '';
                $temp_size = 0;
            }
            $temp_size += mb_strlen($item);
            $temp_content .= $item."\r\n";
            $data[$count-1] = [
                'bid'=>$chapter->bid,
                'is_vip'=>$chapter->is_vip,
                'name'=>sprintf('%s(%s)',$chapter->name,$count),
                'sequence'=>$chapter->sequence+$count-1,
                'size'=>$temp_size,
                'prev_cid'=>0,
                'next_cid'=>0,
                'recent_update_at'=>$chapter->recent_update_at,
                'content'=>$temp_content,
            ];
        }

        if($data && $data[$count-1]['size'] <800){
            $data[$count-2]['content'] = $data[$count-2]['content'].$data[$count-1]['content'];
            $data[$count-2]['size'] = $data[$count-2]['size']+$data[$count-1]['size'];
            unset($data[$count-1]);
        }

        return $data;
    }

    public static function createSplitContent($chapter_id,$data,$is_adjust = true)
    {
        if(count($data) <= 1){
            return 0;
        }
        Chapter::where('bid',$data[0]['bid'])->where('sequence','>=',$data[0]['sequence']+1)->increment('sequence',count($data)-1);
        Chapter::where('id',$chapter_id)->update([
            'content'=>$data[0]['content'],
            'size'=>$data[0]['size'],
            'name'=>$data[0]['name']
        ]);
        $i = 0;
        foreach ($data as $kye=>$item){
            if($kye == 0) continue;
            $i++;
            self::createChapter($item);
        }
        if($is_adjust){
            self::adjustSequent($data[0]['bid'],$data[0]['sequence'],$data[0]['sequence']+count($data)+5);
        }

        if(self::getChapterFromOss($data[0]['bid'],$chapter_id)){
            $oss = self::ossObject();
            $bucket = env('OSS_BUCKET');
            $path_format = 'book/chapters/%s/%s.json';
            $oss->deleteObject($bucket,sprintf($path_format, $data[0]['bid'], $chapter_id));
        }
        $key = sprintf('book_chapter_%s_%s', $data[0]['bid'], $chapter_id);
        //Redis::connection('chapter')
        try{
            Redis::connection('chapter')->delete($key);
        }catch (\Exception $e){}


        $last = Chapter::where('bid',$data[0]['bid'])
            ->select('id','bid','name','sequence')
            ->orderBy('sequence','desc')
            ->limit(1)
            ->first();
        Book::where('id',$data[0]['bid'])->update([
            'chapter_count'=>$last->sequence,
            'last_chapter'=>$last->name,
            'last_cid'=>$last->id,
        ]);
        return $i;
    }

    public static function adjustSequent($bid,$start_sequence,$end_sequence){
        $chapter_list = Chapter::where('bid',$bid);
        if($start_sequence){
            $chapter_list = $chapter_list->where('sequence','>=',$start_sequence);
        }
        if($end_sequence){
            $chapter_list = $chapter_list->where('sequence','<=',$end_sequence);
        }
        $chapter_list = $chapter_list->orderBy('sequence')->select('id')->get();
        $prev = 0;

        foreach ($chapter_list as $chapter){
            if($prev){
                Chapter::where('id',$chapter->id)->update(['prev_cid'=>$prev]);
                Chapter::where('id',$prev)->update(['next_cid'=>$chapter->id]);
            }
            $prev = $chapter->id;
        }
    }
}