<?php
/**
 * Created by PhpStorm.
 * User: glsy
 * Date: 2018/6/28
 * Time: 下午2:20
 */

namespace App\Resps\Eloquents;

use App\Resps\Interfaces\Image as ImageInterface;
use App\Resps\Interfaces\Product as ProductInterface;
use App\Models\Product as ProductModel;
use App\Models\ProductsSorts as ProductsSortsModel;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;

class Product implements ProductInterface
{
    private $image;

    public function __construct(ImageInterface $image)
    {
        $this->image = $image;
    }

    public function index(array $condition = [])
    {
        $page = is_or($condition, 'page', 1);
        $list = DB::table('products as p')
            ->leftJoin('administrators as a', 'p.creator_id', '=', 'a.id')
            ->leftJoin('administrators as b', 'p.mender_id', '=', 'b.id')
            ->leftJoin('products_sorts as c', 'p.sort_id', '=', 'c.id');
        if ($name = urldecode(is_or($condition, 'name'))) {
            $list = $list->where('p.name', 'like', '%' . $name . '%');
        }
        if ($price = urldecode(is_or($condition, 'price'))) {
            $list = $list->whereBetween('p.price', explode(',', $price));
        }
        if ($keyword = urldecode(is_or($condition, 'keyword'))) {
            $list = $list->whereRaw("find_in_set(p.keyword,'" . $keyword . "')");
        }
        $list = $list->select(['p.*', 'a.username as creator_name', 'b.username as mender_name', 'c.name as sort_name'])
            ->orderBy('p.id', 'desc')
            ->paginate(20, ['*'], 'page', $page)
            ->toArray();
        return [
            'total' => $list['total'],
            'per_page' => $list['per_page'],
            'current_page' => $list['current_page'],
            'last_page' => $list['last_page'],
            'list' => array_map(function ($y) {
                $y['images'] = unserialize($y['images']);
                return $y;
            }, get_select($list['data']))
        ];
    }

    public function plist(array $condition = [])
    {
        $page = is_or($condition, 'page', 1);
        $per_page_num = is_or($condition, 'per_page_num', 20);
        $order_by = is_or($condition, 'order_by', 'hot');
        $order = is_or($condition, 'order', 'desc');
        $list = DB::table('products as p')
            ->leftJoin('products_sorts as c', 'p.sort_id', '=', 'c.id');
        if ($name = urldecode(is_or($condition, 'name'))) {
            //此处名称搜索附带分类名称
            $list = $list->where(function ($query) use ($name) {
                $query->where('p.name', 'like', '%' . $name . '%')
                    ->orWhere('c.name', 'like', '%' . $name . '%');
            });
        }
        if ($sort_id = urldecode(is_or($condition, 'sort_id'))) {
            $list = $list->where('p.sort_id', $sort_id);
        }else{
            //过滤掉券分类
            $list = $list->where('p.sort_id', '<>',1);
        }
        if ($price = urldecode(is_or($condition, 'price'))) {
            $prices = explode('_', $price);
            $list = $list->where(function ($query) use ($prices) {
                $query->where('p.is_off', 0)->whereBetween('p.price', $prices);
            })->orWhere(function ($query) use ($prices) {
                $query->where('p.is_off', 1)->whereBetween('p.off_price', $prices);
            });
        }
        $list = $list->where('p.status', 1);
        $list = $list->select([
            'p.pid',
            'p.name',
            'p.price',
            'p.is_off',
            'p.off_price',
            'p.index_image',
            'c.id as sort_id',
            'c.name as sort_name'
        ])
            ->orderBy('p.' . $order_by, $order)
            ->paginate($per_page_num, ['*'], 'page', $page)
            ->toArray();
        return [
            'total' => $list['total'],
            'per_page' => $list['per_page'],
            'current_page' => $list['current_page'],
            'last_page' => $list['last_page'],
            'list' => get_select($list['data'])
        ];
    }

    public function show($id)
    {
        $detail = ProductModel::leftJoin('products_sorts', 'products.sort_id', '=', 'products_sorts.id')
            ->where('products.id', $id)
            ->select('products.*', 'products_sorts.name as sort_name')
            ->first();
        $detail = $detail ? $detail->toArray() : [];
        !empty($detail) && $detail['images'] = unserialize($detail['images']);
        !empty($detail) && $detail['sorttree'] = $this->getSortTree($detail['sort_id'], true);
        return $detail;
    }

    public function getDetailByPid($pid)
    {
        $detail = ProductModel::leftJoin('products_sorts', 'products.sort_id', '=', 'products_sorts.id')
            ->where('products.pid', $pid)
            ->select(
                'products.pid as id',
                'products.name',
                'products.desc',
                'products.index_image',
                'products.images',
                'products.price',
                'products.off_price',
                'products.sort_id',
                'products_sorts.name as sort_name'
            )
            ->first();
        $detail = $detail ? $detail->toArray() : [];
        !empty($detail) && $detail['images'] = unserialize($detail['images']);
        return $detail;
    }

    public function create(array $params)
    {
        $insertData = [];
        if (!isset($params['name']) || !$insertData['name'] = trim($params['name'])) {
            return ['code' => 501];
        }
        if (!isset($params['price']) || !$insertData['price'] = trim($params['price'])) {
            return ['code' => 509];
        }
//        $insertData['is_off'] = is_or($params, 'is_off', 0);
        $insertData['is_off'] = 1;
        $insertData['off_price'] = is_or($params, 'off_price', $insertData['price']);
        $insertData['storage'] = is_or($params, 'storage', 0);
        if (!isset($params['sort_id']) || !$insertData['sort_id'] = intval($params['sort_id'])) {
            return ['code' => 502];
        }
        if (!ProductsSortsModel::find($insertData['sort_id'])) {
            return ['code' => 410];
        }
        $insertData['keyword'] = is_or($params, 'keyword');
        $insertData['abstract'] = is_or($params, 'abstract');
        $insertData['index_image'] = is_or($params, 'index_image');
        $insertData['images'] = is_or($params, 'images');
        if (empty($insertData['images'])) {
            return ['code' => 508];
        }
        $insertData['images'] = serialize($insertData['images']);
        $insertData['hot'] = is_or($params, 'hot', 0);
        $insertData['is_promote'] = is_or($params, 'is_promote', 0);
        $insertData['desc'] = is_or($params, 'desc');
        $insertData['creator_id'] = $insertData['mender_id'] = Auth::id();
        $insertData['pid'] = $this->createPid();

        try {
            ProductModel::create($insertData);
            return ['code' => 0];
        } catch (\Exception $e) {
            return ['code' => 503];
        }
    }

    private function createPid()
    {
        return strtoupper(md5(sha1(microtime(1) . Auth::id() . rand(1, 10000000))));
    }

    public function update($id, array $params)
    {
        $updateData = [];
        if (!$id || !$product = ProductModel::find($id)) {
            return ['code' => 504];
        }
        if (!isset($params['name']) || !$updateData['name'] = trim($params['name'])) {
            return ['code' => 501];
        }
        if (!isset($params['price']) || !$updateData['price'] = trim($params['price'])) {
            return ['code' => 509];
        }
//        $updateData['is_off'] = is_or($params, 'is_off', 0);
        $updateData['is_off'] = 1;
        $updateData['off_price'] = is_or($params, 'off_price', $updateData['price']);
        $updateData['storage'] = is_or($params, 'storage', 0);

        if (!isset($params['sort_id']) || !$updateData['sort_id'] = intval($params['sort_id'])) {
            return ['code' => 502];
        }
        if (!ProductsSortsModel::find($updateData['sort_id'])) {
            return ['code' => 410];
        }

        $updateData['keyword'] = is_or($params, 'keyword');
        $updateData['index_image'] = is_or($params, 'index_image');
        $newImages = is_or($params, 'images');
        if (empty($newImages)) {
            return ['code' => 508];
        }
        $this->handleImagesUpdate(unserialize($product->images), $newImages);
        $updateData['images'] = serialize($newImages);
        $updateData['hot'] = is_or($params, 'hot', 0);
        $updateData['is_promote'] = is_or($params, 'is_promote', 0);
        $updateData['desc'] = is_or($params, 'desc');
        $updateData['mender_id'] = Auth::id();
        try {
            ProductModel::where('id', $id)->update($updateData);
            return ['code' => 0];
        } catch (\Exception $e) {
            return ['code' => 506];
        }

    }

    public function edit($id, $status)
    {
        if (!$id || !ProductModel::find($id)) {
            return ['code' => 504];
        }
        if (is_null($status) || !in_array($status, [0, 1])) {
            return ['code' => 510];
        }
        try {
            ProductModel::where('id', $id)->update(['status' => $status]);
            return ['code' => 0];
        } catch (\Exception $e) {
            return ['code' => 511];
        }

    }

    private function handleImagesUpdate(array $oldImages, array $newImages)
    {
        $delete_ids = array_diff(array_column($oldImages, 'id'), array_column($newImages, 'id'));
        !empty($delete_ids) && $this->image->destroy($delete_ids);
    }

    public function destroy($id)
    {
        if (!$id || !$product = ProductModel::find($id)) {
            return ['code' => 504];
        }
        $image_ids = array_column(unserialize($product->images), 'id');
        $res = $this->image->destroy($image_ids);
        if ($res['code']) {
            return $res;
        }
        try {
            ProductModel::destroy($id);
            return ['code' => 0];
        } catch (\Exception $e) {
            return ['code' => 505];
        }
    }


    public function getSort($fid = 0, $is_web = false)
    {
        $return = ProductsSortsModel::where('fid', $fid);
        $return = $is_web ? $return->where('id', '<>', 1) : $return;
        return $return->get()->toArray();

    }

    public function addSort(array $params)
    {
        $fid = intval(is_or($params, 'fid'));
        if ($fid > 0 && (!$father = ProductsSortsModel::find($fid))) {
            return ['code' => 405];
        }
        if (!$name = trim(is_or($params, 'name'))) {
            return ['code' => 406];
        }
        $inserData = ['fid' => $fid, 'level' => $fid === 0 ? 1 : $father->level + 1, 'name' => $name];
        if (ProductsSortsModel::where($inserData)->count()) {
            return ['code' => 407];
        }
        try {
            $res = ProductsSortsModel::create($inserData);
            return ['code' => 0, 'data' => ['id' => $res->id, 'level' => $res->level, 'name' => $res->name]];
        } catch (\Exception $e) {
            return ['code' => 408];
        }
    }

    public function updateSort($id, array $params)
    {
        if (!$id = intval($id)) {
            return ['code' => 409];
        }
        if ((!$res = ProductsSortsModel::find($id))) {
            return ['code' => 410];
        }
        if (!$name = trim(is_or($params, 'name'))) {
            return ['code' => 406];
        }
        if (ProductsSortsModel::where(['fid' => $res->fid, 'name' => $name])->count() > 1) {
            return ['code' => 407];
        }
        $updateData = ['name' => $name];
        if (isset($params['index_image']) && !is_null($params['index_image'])) {
            $updateData['index_image'] = $params['index_image'];
        }
        try {
            ProductsSortsModel::where('id', $id)->update($updateData);
            return ['code' => 0];
        } catch (\Exception $e) {
            return ['code' => 414];
        }
    }

    public function deleteSort($id)
    {
        if ($id == 1) {
            return ['code' => 421];
        }
        if (!$id) {
            return ['code' => 409];
        }
        if (!$res = ProductsSortsModel::find($id)) {
            return ['code' => 410];
        }
        if (ProductsSortsModel::where('fid', $id)->count()) {
            return ['code' => 411];
        }
        if (ProductModel::where('sort_id', $id)->count()) {
            return ['code' => 412];
        }
        try {
            ProductsSortsModel::destroy($id);
            return ['code' => 0];
        } catch (\Exception $e) {
            return ['code' => 413];
        }
    }

    public function getSortTree($id, $symbol = false)
    {
        if (!$id) {
            return ['code' => 409];
        }
        if (!$res = ProductsSortsModel::find($id)) {
            return ['code' => 410];
        }
        $level = $res->level;
        $ids = [$res->id];
        $names = [$res->name];
        $where = ['id' => $res->fid];
        while ($level > 1) {
            $sort = ProductsSortsModel::where($where)->first();
            if ($sort) {
                array_unshift($ids, $sort->id);
                array_unshift($names, $sort->name);
                $where = ['id' => $sort->fid];
                $level--;
            }
        }
        $data = ['ids' => $ids, 'names' => $names];
        return $symbol ? $data : ['code' => 0, 'data' => $data];
    }
}