<?php

namespace App\Http\Controllers\Group;

use App\Events\GroupSetEvent;
use App\Http\Controllers\Controller;
use App\Http\Requests\GroupsRequest;
use App\Http\Resources\GoodsSkuResource;
use App\Models\Goods;
use App\Models\GoodsSku;
use App\Models\Shop;
use App\Utils\ArrayUtils;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
use App\Models\Groups;
use App\Http\Resources\GroupsResource;
use App\Models\GroupGoods;

class GroupsController extends Controller
{
    public function __construct(Request $request)
    {

    }

    public function index(Request $request)
    {
        $groups = Groups::query()
            ->with(['shop:id,name'])
            ->where('parent_id', 0)
            ->filter()
            ->paginate($request->get('per_page'));
        foreach ($groups as &$group) {
            $group['children'] = Groups::query()->with(['shop:id,name'])->where('parent_id', $group->id)->get();
        }

        return GroupsResource::collection($groups);
    }

    public function store(Request $request)
    {
        $rules = (new GroupsRequest())->rules();
        $validator = Validator::make($request->all(), $rules);
        if ($validator->fails()) {
            $this->setValidatorFailResponse($validator->getMessageBag()->getMessages());

            return response($this->res, $this->res['httpCode']);
        }
        $skus = GoodsSku::query()
            ->whereIn('id', $request->new_ids)
            ->with(['goods' => function ($query) {
                $query->with(['type:id,name', 'brand:id,name']);
            }])
            ->get()
            ->toArray();
        $changeData = $request->change_data;
        $changeData = ArrayUtils::index($changeData, 'id');
        DB::beginTransaction();
        $shopIds = Shop::query()
            ->where('plat_id', Shop::$PLAT_KTT)
            ->where('expires_at', '>', time())
            ->pluck('id')
            ->toArray();
        try {
            $group = new Groups();
            $group->title = $request->title;
            $group->is_save_preview = $request->is_save_preview;
            $group->start_time = $request->datetimerange[0];
            $group->end_time = $request->datetimerange[1];
            $group->save();
            $shopGroups = [];
            foreach ($shopIds as $shopId) {
                $shopGroups[] = [
                    'parent_id' => $group->id,
                    'shop_id' => $shopId,
                    'title' => $group->title,
                    'is_save_preview' => $group->is_save_preview,
                    'start_time' => strtotime($request->datetimerange[0]) * 1000,
                    'end_time' => strtotime($request->datetimerange[1]) * 1000,
                ];
            }
            (new Groups())->batchInsert($shopGroups);
            $groupGoods = [];
            foreach ($skus as $sku) {
                $price = $sku['cost'] * 100;
                $groupGoods[] = [
                    'group_id' => $group->id,
                    'category_name' => $sku['goods']['type']['name'],
                    'type_id' => $sku['goods']['type']['id'],
                    'goods_name' => $sku['goods']['title'] . ' ' . $sku['title'],
                    'goods_id' => $sku['goods_id'],
                    'limit_buy' => isset($changeData[$sku['id']]) ? $changeData[$sku['id']]['limit_buy'] : 0,
                    'sku_id' => $sku['id'],
                    'price_in_fen' => isset($changeData[$sku['id']]) ? $changeData[$sku['id']]['price_in_fen'] * 100 : $price,
                    'external_sku_id' => $sku['goods']['goods_code'] . '_' . $sku['sku_code'],
                ];
            }
            (new GroupGoods())->batchInsert($groupGoods);
            DB::commit();
            event(new GroupSetEvent($group->id));
        } catch (\Exception $exception) {
            DB::rollBack();
            $this->res = [
                'httpCode' => 400,
                'errorCode' => 400500,
                'errorMessage' => $exception->getMessage(),
            ];
        }
        return response($this->res, $this->res['httpCode']);
    }

    public function show($id)
    {
        return new GroupsResource(Groups::query()
            ->where('parent_id', 0)
            ->find($id));
    }

    public function update(Request $request, $id)
    {
        $rules = (new GroupsRequest())->rules();
        $validator = Validator::make($request->all(), $rules);
        if ($validator->fails()) {
            $this->setValidatorFailResponse($validator->getMessageBag()->getMessages());

            return response($this->res, $this->res['httpCode']);
        }
        $deleteIds = $request->delete_ids;
        $groupHasGoods = GroupGoods::query()
            ->where('group_id', $id)
            ->whereNotIn('sku_id', $deleteIds)
            ->get(['id', 'sku_id', 'limit_buy', 'price_in_fen'])
            ->toArray();
        $groupHasGoods = ArrayUtils::index($groupHasGoods, 'sku_id');
        $skus = GoodsSku::query()
            ->whereIn('id', array_merge(array_keys($groupHasGoods), $request->new_ids))
            ->with(['goods' => function ($query) {
                $query->with(['type:id,name', 'brand:id,name']);
            }])
            ->get()
            ->toArray();
        $changeData = $request->change_data;
        $changeData = ArrayUtils::index($changeData, 'id');
        DB::beginTransaction();
        try {
            $group = Groups::query()->find($id);
            $group->title = $request->title;
            $group->start_time = $request->datetimerange[0];
            $group->end_time = $request->datetimerange[1];
            $group->save();
            DB::table('groups')
                ->where('parent_id', $group->id)
                ->update([
                    'title' => $group->title,
                    'start_time' => strtotime($request->datetimerange[0]) * 1000,
                    'end_time' => strtotime($request->datetimerange[1]) * 1000,
                ]);
            GroupGoods::where('group_id', $id)->whereIn('sku_id', $deleteIds)->delete();
            foreach ($skus as $sku) {
                $limitBuy = isset($groupHasGoods[$sku['id']]) ? $groupHasGoods[$sku['id']]['limit_buy'] : 0;
                $price = isset($groupHasGoods[$sku['id']]) ? $groupHasGoods[$sku['id']]['price_in_fen'] : $sku['cost'];
                $groupGoods = [
                    'category_name' => $sku['goods']['type']['name'],
                    'type_id' => $sku['goods']['type']['id'],
                    'goods_name' => $sku['goods']['title'] . ' ' . $sku['title'],
                    'goods_id' => $sku['goods_id'],
                    'limit_buy' => isset($changeData[$sku['id']]) ? $changeData[$sku['id']]['limit_buy'] : $limitBuy,
                    'price_in_fen' => isset($changeData[$sku['id']]) ? $changeData[$sku['id']]['price_in_fen'] * 100 : $price * 100,
                    'external_sku_id' => $sku['goods']['goods_code'] . '_' . $sku['sku_code'],
                ];
                GroupGoods::updateOrCreate(
                    ['group_id' => $group->id, 'sku_id' => $sku['id']],
                    $groupGoods
                );
            }
            DB::commit();
            event(new GroupSetEvent($id));
        } catch (\Exception $exception) {
            DB::rollBack();
            $this->res = [
                'httpCode' => 400,
                'errorCode' => 400500,
                'errorMessage' => $exception->getMessage(),
            ];
        }

        return response($this->res, $this->res['httpCode']);
    }

    public function destroy()
    {
    }

    public function getGoods(Request $request)
    {
        $deleteIds = $request->get('delete_ids') ?: [];
        $groupId = $request->get('group_id');
        $groupGoods = GroupGoods::query()
            ->select(['id', 'sku_id', 'limit_buy', 'price_in_fen'])
            ->where('group_id', $groupId)
            ->whereNotIn('sku_id', $deleteIds)
            ->get()
            ->toArray();
        $groupGoods = ArrayUtils::index($groupGoods, 'sku_id');
        $skuIds = array_keys($groupGoods);
        if ($newIds = $request->get('new_ids')) {
            $skuIds = array_merge($skuIds, $newIds);
        }
        $goodsCode = $skuCode = '';
        $externalSkuId = $request->get('external_sku_id');
        if (false !== strpos($externalSkuId, '_')) {
            [$goodsCode, $skuCode] = explode('_', $externalSkuId);
            $externalSkuId = '';
        }
        $goodsIds = Goods::query()
            ->when($externalSkuId, function ($query, $externalSkuId) {
                return $query->where('title', 'like', "%$externalSkuId%");
            })
            ->filter()
            ->when($goodsCode, function ($query, $goodsCode) {
                return $query->where('goods_code', $goodsCode);
            })
            ->pluck('id')
            ->toArray();
        $stockSelect = (int)$request->get('has_stock');
        $fields = implode(',', [
            'id',
            'goods_id',
            'title',
            'sku_code',
            'stock',
            'cost',
        ]);
        $goodsSkus = GoodsSku::query()
            ->select(DB::raw($fields))
            ->whereIn('id', $skuIds)
            ->whereIn('goods_id', $goodsIds)
            ->when($skuCode, function ($query, $skuCode) {
                return $query->where('sku_code', $skuCode);
            })
            ->when($stockSelect, function ($query, $stockSelect) {
                if ($stockSelect > 0) {
                    return $query->where('stock', '>', 0);
                }

                return $query->where('stock', '<=', 0);
            })
            ->filter()
            ->with(['goods' => function ($query) {
                $query->with(['type:id,name', 'brand:id,name']);
            }])
            ->orderBy('updated_at', 'desc')
            ->paginate($request->get('per_page'));
        foreach ($goodsSkus as &$goodsSku) {
            if (isset($groupGoods[$goodsSku['id']])) {
                $goodsSku['price_in_fen'] = $groupGoods[$goodsSku['id']]['price_in_fen'];
                $goodsSku['limit_buy'] = $groupGoods[$goodsSku['id']]['limit_buy'];
            } else {
                $goodsSku['price_in_fen'] = $goodsSku['cost'];
                $goodsSku['limit_buy'] = 0;
            }
            $goodsSku['goods_name'] = $goodsSku['goods']['title'] . ' ' . $goodsSku['title'];
            $goodsSku['external_sku_id'] = $goodsSku['goods']['goods_code'] . '_' . $goodsSku['sku_code'];
            $goodsSku['category_name'] = $goodsSku['goods']['type']['name'];
        }

        return GoodsSkuResource::collection($goodsSkus);
    }

    public function addGroupGoods(Request $request)
    {
        $ids = [];
        if ($newIds = $request->get('new_ids')) {
            $ids = array_merge($ids, $newIds);
        }
        if ($hasIds = $request->get('has_ids')) {
            $ids = array_merge($ids, $hasIds);
        }
        $goodsSkus = GoodsSku::query()
            ->whereIn('id', $ids)
            ->with(['goods' => function ($query) {
                $query->with(['type:id,name', 'brand:id,name']);
            }])
            ->orderBy('updated_at', 'desc')
            ->paginate($request->get('per_page'));
        foreach ($goodsSkus as &$goodsSku) {
            $goodsSku['price_in_fen'] = $goodsSku['cost'];
            $goodsSku['limit_buy'] = 0;
            $goodsSku['goods_name'] = $goodsSku['goods']['title'] . ' ' . $goodsSku['title'];
            $goodsSku['external_sku_id'] = $goodsSku['goods']['goods_code'] . '_' . $goodsSku['sku_code'];
            $goodsSku['category_name'] = $goodsSku['goods']['type']['name'];
        }

        return GoodsSkuResource::collection($goodsSkus);
    }

    public function goodsList(Request $request)
    {
        $goodsCode = $skuCode = '';
        $goodsKeyword = $request->get('goods_keyword');
        if (false !== strpos($goodsKeyword, '_')) {
            [$goodsCode, $skuCode] = explode('_', $goodsKeyword);
            $goodsKeyword = '';
        }
        $goodsIds = Goods::query()
            ->when($goodsKeyword, function ($query, $goodsKeyword) {
                return $query->where('title', 'like', "%$goodsKeyword%");
            })
            ->filter()
            ->when($goodsCode, function ($query, $goodsCode) {
                return $query->where('goods_code', $goodsCode);
            })
            ->pluck('id');
        $excludeIds = $request->get('has_ids') ?: [];
        $deleteIds = $request->get('delete_ids') ?: [];
        if ($groupId = $request->get('group_id')) {
            $skuIds = GroupGoods::query()
                ->where('group_id', $groupId)
                ->whereNotIn('sku_id', $deleteIds)
                ->pluck('sku_id')
                ->toArray();
            $excludeIds = array_merge($excludeIds, $skuIds);
        }
        $goodsSkus = GoodsSku::query()
            ->whereIn('goods_id', $goodsIds)
            ->whereNotIn('id', $excludeIds)
            ->when($skuCode, function ($query, $skuCode) {
                return $query->where('sku_code', $skuCode);
            })
            ->when((int)$request->get('has_stock'), function ($query) {
                return $query->where('stock', '>', 0);
            })
            ->filter()
            ->with(['goods' => function ($query) {
                $query->with(['type:id,name', 'brand:id,name']);
            }])
            ->orderBy('updated_at', 'desc')
            ->paginate($request->get('per_page'));

        return GoodsSkuResource::collection($goodsSkus);
    }
}
