<?php

namespace App\Http\Controllers;

use App\Helpers\Helper;
use App\Http\Resources\ProductItemDetailResource;
use App\Jobs\ProcessFaceSwap;
use App\Keyword;
use App\Laravue\Acl;
use App\ProductCategory;
use App\ProductColor;
use App\ProductDetail;
use App\ProductImage;
use App\ProductKeyword;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use App\Http\Resources\ProductResource;
use App\Http\Resources\ProductDetailResource;
use App\Product;
use App\Category;
use DB;
use Validator;

class ProductController extends Controller
{
    const ITEM_PER_PAGE = 25;
    private $_user = null;

    public function __construct()
    {
        $this->_user = auth('api')->user();
    }

    public function index(Request $request)
    {
        $searchParams = $request->all();
        $limit = Arr::get($searchParams, 'limit', static::ITEM_PER_PAGE);
        $keyword = Arr::get($searchParams, 'keyword', '');
        $type = Arr::get($searchParams, 'type', '');
        $gender = Arr::get($searchParams, 'gender', '');
        $categoryIds = Arr::get($searchParams, 'category', null);
        $colorIds = Arr::get($searchParams, 'color', null);
        $priceFrom = Arr::get($searchParams, 'price_from', '');
        $priceTo = Arr::get($searchParams, 'price_to', '');

        $list = Product::select('*')->isPublished()->where('type', '!=', 0);

        if (!empty($keyword)) {
            $list->where('name', 'LIKE', '%' . $keyword . '%');
        }

        if (!empty($type) && in_array($type, [ 1, 2, 3 ])) {
            $list->where('type', $type);
        }

        if (!empty($gender) && in_array($gender, [ 0, 1 ])) {
            $list->where('gender', 1);
        }

        if (isset($categoryIds) && is_array($categoryIds)) {
            $productIds = ProductCategory::whereIn('category_id', $categoryIds)->pluck('product_id')->toArray();
            $list->whereIn('id', $productIds);
        }

        if (isset($colorIds) && is_array($colorIds)) {
            $productIds = ProductColor::whereIn('color_id', $colorIds)->pluck('product_id')->toArray();
            $list->whereIn('id', $productIds);
        }

        if (!empty($priceFrom)) {
            $list->where('default_price', '>=', $priceFrom);
        }

        if (!empty($priceTo)) {
            $list->where('default_price', '<=', $priceTo);
        }

        $list->orderBy('id', 'DESC');

        return ProductResource::collection($list->paginate($limit));
    }

    public function mypage(Request $request)
    {
        $searchParams = $request->all();
        $limit = Arr::get($searchParams, 'limit', static::ITEM_PER_PAGE);
        $keyword = Arr::get($searchParams, 'keyword', '');
        $status = Arr::get($searchParams, 'status', '');
        $categoryId = Arr::get($searchParams, 'categoryId', '');
        $subCategoryId = Arr::get($searchParams, 'subCategoryId', '');
        $priceFrom = Arr::get($searchParams, 'priceFrom', '');
        $priceTo = Arr::get($searchParams, 'priceTo', '');
        $type = Arr::get($searchParams, 'type', '');

        $list = Product::select('*')->where('is_deleted', false);

        if ($this->_user != null && $this->_user->hasRole([ 'user', 'owner' ]) && $this->_user->can(Acl::PERMISSION_PRODUCT_OWNER_MANAGE)) {
            $list->where('created_by', $this->_user->id);
        }

        if (!empty($keyword)) {
            $list->where(function ($query) use ($keyword) {
                $query->where('name', 'LIKE', '%' . $keyword . '%')
                    ->orWhere('price_from', 'LIKE', '%' . $keyword . '%')
                    ->orWhere('price_to', 'LIKE', '%' . $keyword . '%')
                    ->orWhere('discount', 'LIKE', '%' . $keyword . '%');
            });
        }

        if (!empty($type) && in_array($type, [ 0, 1, 2 ])) {
            $list->where('type', $type);
        }

        if (!empty($priceFrom)) {
            $list->where('price_from', '>=', $priceFrom);
        }

        if (!empty($priceTo)) {
            $list->where('price_from', '<=', $priceTo);
        }

        if ($status != '') {
            $list->where('is_activated', $status);
        }

        $list->orderBy('id', 'DESC');

        return ProductResource::collection($list->paginate($limit));
    }

    public function top(Request $request)
    {
        $searchParams = $request->all();
        $limit = Arr::get($searchParams, 'limit', static::ITEM_PER_PAGE);
        $list = Product::select('*')->isPublished()->orderBy('id', 'DESC');

        return ProductResource::collection($list->paginate($limit));
    }

    public function show($id = 0)
    {
        $product = Product::select('*')
            ->isPublished()
            ->where('id', $id)
            ->first();

        if (!isset($product)) return response()->json([ 'data' => null, 'errors' => 'Product is invalid' ], 200);

        return new ProductDetailResource($product);
    }

    public function estimateCheck(Request $request, $id = 0)
    {
        $product = Product::select('*')
            ->isPublished()
            ->where('id', $id)
            ->first();

        if (!isset($product)) return response()->json([ 'data' => null, 'errors' => 'Product is invalid' ], 200);

        $params = $request->all();
        $listOptionIds = [];
        foreach ($params['options'] as $item) {
            $listOptionIds[] = $item['value'];
        }

        $productDetail = ProductDetail::select(
            'product_details.id as id',
            'product_details.product_id as product_id',
            'product_details.sku as sku',
            'product_details.code as code',
            'product_details.price as price',
            'product_option_details.id as option_detail_id',
            'product_option_details.name as option_detail_name'
        )
            ->join('product_detail_option_details', 'product_details.id', '=', 'product_detail_option_details.product_detail_id')
            ->join('product_option_details', 'product_detail_option_details.product_option_detail_id', '=', 'product_option_details.id')
            ->where('product_details.product_id', $product->id)
            ->whereIn('product_option_details.id', $listOptionIds)
            ->get();

        $list = [];
        foreach ($productDetail as $item) {
            if (!isset($list[$item->id])) {
                $list[$item->id] = [
                    'id'         => $item->id,
                    'product_id' => $item->product_id,
                    'sku'        => $item->sku,
                    'code'       => $item->code,
                    'price'      => $item->price,
                    'options'    => [],
                ];
            }
            $list[$item->id]['options'][] = $item->option_detail_id;
        }

        $checkDetailId = '';
        $checkDetailCode = '';
        foreach ($list as $item) {
            if (count($item['options']) == count($listOptionIds)) {
                $checkMatch = true;
                foreach ($listOptionIds as $oId) {
                    if (!in_array($oId, $item['options'])) $checkMatch = false;
                }
                if ($checkMatch) {
                    $checkDetailId = $item['id'];
                    $checkDetailCode = $item['code'];
                    break;
                }
            }
        }

        $status = 'error';
        $rs = [];
        if ($checkDetailCode != null && $checkDetailCode != "") {
            $status = 'success';
            $rs = [
                'id'          => $checkDetailId,
                'code'        => $checkDetailCode,
                'purchase_id' => $params['purchase_id'],
            ];
        }

        return response()->json([
            'status' => $status,
            'data'   => $rs
        ], 200);
    }

    public function estimateShow($id = 0, $code = '')
    {
        $product = Product::select('*')
            ->isPublished()
            ->where('id', $id)
            ->first();

        $productDetail = ProductDetail::where('product_id', $id)
            ->where('code', $code)
            ->first();

        if (!isset($product) || !isset($productDetail)) return response()->json([ 'status' => 'error', 'data' => null, 'errors' => 'Product is invalid' ], 200);

        return new ProductItemDetailResource($productDetail);
    }

    public function ranking(Request $request)
    {
        //$searchParams = $request->all();
        //$limit = Arr::get($searchParams, 'limit', static::ITEM_PER_PAGE);

        $listA = Product::select('id', 'category_id', 'name', 'slug', 'sku', 'discount', 'description', 'image', 'note', 'policy', 'possible_delivery_time', 'regular_price_from', 'regular_price_to', 'price_from', 'price_to')
            ->isPublished()
            ->orderBy('id', 'DESC')
            ->limit(6)
            ->get();

        $listB = Product::select('id', 'category_id', 'name', 'slug', 'sku', 'discount', 'description', 'image', 'note', 'policy', 'possible_delivery_time', 'regular_price_from', 'regular_price_to', 'price_from', 'price_to')
            ->with('category')
            ->isPublished()
            ->orderBy('id', 'DESC')
            ->limit(12)
            ->get();

        $listC = Product::select('id', 'category_id', 'name', 'slug', 'sku', 'discount', 'description', 'image', 'note', 'policy', 'possible_delivery_time', 'regular_price_from', 'regular_price_to', 'price_from', 'price_to')
            ->isPublished()
            ->orderBy('id', 'DESC')
            ->limit(12)
            ->get();

        $listD = Product::select('id', 'category_id', 'name', 'slug', 'sku', 'discount', 'description', 'image', 'note', 'policy', 'possible_delivery_time', 'regular_price_from', 'regular_price_to', 'price_from', 'price_to')
            ->isPublished()
            ->orderBy('id', 'DESC')
            ->limit(12)
            ->get();

        return response()->json([ 'data' => [
            'list_1' => $listA,
            'list_2' => $listB,
            'list_3' => $listC,
            'list_4' => $listD,
        ] ], 200);
    }

    public function rankingCategory(Request $request, $id = 0)
    {
        $searchParams = $request->all();
        $limit = Arr::get($searchParams, 'limit', static::ITEM_PER_PAGE);

        $list = Product::select('products.*', DB::raw('count(products.id) as total_sale'))
            ->join('order_details', 'order_details.product_id', '=', 'products.id')
            ->where('products.is_deleted', false)
            ->where('products.is_activated', true)
            ->groupBy('products.id');

        if ($id != null && $id != "" && $id != 0) {
            $category = Category::where('id', $id)->first();
            if (isset($category)) {
                $categories = Category::select('id', 'parent_id')
                    ->where('id', '!=', $category->parent_id)
                    ->where('id', '!=', $id)
                    ->where('parent_id', '!=', 0)
                    ->whereNotNull('parent_id')
                    ->get();

                $listIds = $this->detectChildCategoryId($categories, $id);
                $listIds[] = $category->id;
                $list->whereIn('products.category_id', $listIds);
            }
        }

        $list->orderBy('total_sale', 'DESC')->orderBy('products.id', 'ASC');

        return ProductResource::collection($list->paginate($limit));
    }

    public function rankingManufacturer(Request $request, $id = 0)
    {
        $searchParams = $request->all();
        $limit = Arr::get($searchParams, 'limit', static::ITEM_PER_PAGE);
        $list = Product::select('*')
            ->isPublished()
            ->where('manufacturer_id', $id)
            ->whereNotNull('rank')
            ->orderBy('rank', 'DESC')
            ->orderBy('updated_at', 'DESC');

        return ProductResource::collection($list->paginate($limit));
    }

    public function register(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'name' => [ 'required' ],
        ]);
        if ($validator->fails()) return response()->json([ 'errors' => $validator->errors() ], 403);
        $params = $request->all();

        $product = Product::create([
            'sku'                   => rand(1111, 9999),
            'code'                  => 'BA-' . rand(1111, 9999) . '-M',
            'type'                  => 0, //$params['type'],
            'name'                  => trim($params['name']),
            'slug'                  => Helper::slug(trim($params['name'])),
            'image'                 => isset($params['sliders'][0]) ? $params['sliders'][0] : 'no-image.png',
            'gender'                => (in_array($params['gender'], [ 0, 1 ])) ? $params['gender'] : 0,
            'size'                  => $params['size'],
            'height'                => trim($params['height']),
            'sleeve'                => trim($params['sleeve']),
            'sleeve_length'         => trim($params['sleeve_length']),
            'hip'                   => trim($params['hip']),
            'primary_width'         => trim($params['front_width']),
            'second_width'          => trim($params['rear_width']),
            'explanation'           => trim($params['address']),
            'is_cleaning_service'   => $params['is_cleaning_service'],
            'is_storage_period'     => $params['is_storage_period'],
            'is_pricing_manual'     => 1,
            'is_available_in_stock' => 1,
            'created_by'            => ($this->_user != null) ? $this->_user->id : 1,
            'is_activated'          => 0,
            'is_deleted'            => false,
            'created_at'            => date('Y-m-d H:i:s'),
            'updated_at'            => date('Y-m-d H:i:s')
        ]);

        //Images
        foreach ($params['sliders'] as $item) {
            ProductImage::create([
                'product_id' => $product->id,
                'name'       => $item,
                'file_name'  => $item,
                'position'   => 0,
                'created_at' => date('Y-m-d H:i:s'),
                'updated_at' => date('Y-m-d H:i:s')
            ]);
        }

        //Category
        foreach ($params['category'] as $item) {
            ProductCategory::create([
                'product_id'  => $product->id,
                'category_id' => $item,
                'created_at'  => date('Y-m-d H:i:s'),
                'updated_at'  => date('Y-m-d H:i:s')
            ]);
        }

        //Color
        foreach ($params['color'] as $item) {
            ProductColor::create([
                'product_id' => $product->id,
                'color_id'   => $item,
                'created_at' => date('Y-m-d H:i:s'),
                'updated_at' => date('Y-m-d H:i:s')
            ]);
        }

        return response()->json([
            'status' => 'success',
            'id'     => $product->id,
        ], 200);
    }

    public function faceswap(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'source' => [ 'required' ],
            'target' => [ 'required' ],
        ]);
        if ($validator->fails()) return response()->json([ 'errors' => $validator->errors() ], 403);
        $params = $request->all();
        $key = md5(rand(1, 99999999) . date('YmdHis'));
        $sourceImg = public_path('uploads/files/') . $params['source'];
        $targetImg = public_path('uploads/files/') . $params['target'];

        if (!file_exists($sourceImg) || !file_exists($targetImg)) {
            return response()->json([
                'status' => 'error',
                'key'    => null,
            ], 200);
        }

        //Progressing Image
        $imgParams = [
            'key'    => $key,
            'source' => $sourceImg,
            'target' => $targetImg,
        ];
        ProcessFaceSwap::dispatch($imgParams)->onQueue(config('queue.connections.redis.queue'));

        return response()->json([
            'status' => 'progressing',
            'key'    => $key,
        ], 200);
    }

    public function faceswapChecking($code)
    {
        $resultImg = public_path('uploads/files/') . $code . ".jpg";

        if (!file_exists($resultImg)) {
            return response()->json([
                'status' => 'progressing',
                'key'    => $code,
            ], 200);
        }

        return response()->json([
            'status' => 'success',
            'key'    => $code,
        ], 200);
    }

    private function detectChildCategoryId($list = [], $categoryId = '')
    {
        $listIds = [];
        foreach ($list as $item) {
            if ($item->parent_id == $categoryId) {
                $listIds[] = $item->id;
                $subIds = $this->detectChildCategoryId($list, $item->id);
                $listIds = array_merge($listIds, $subIds);
            }
        }

        return $listIds;
    }
}
