<?php

namespace Modules\Seo\Controllers;
use Modules\Seo\Models\Tag;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Route;
use Modules\Seo\Models\ProductVariant;
use Illuminate\Support\Facades\Session;
use Modules\Seo\Models\ProductSkuValue;
use Modules\Seo\Models\ProductVariantOption;

class CategoryController extends Controller
{
    public function decorCacheKey($key) {
        $locale = env('APP_LOCALE', '');
        return $locale . '::' . $key;
    }

    public function setFilter($request, $key, $value, $minute = 60) {
        Cache::put($this->decorCacheKey($key), json_encode($value), $minute);
        $request->merge([
            $key => $value
        ]);
    }

    public function index(Request $request, $slug, $slug2 = null, $slug3 = null) {
        $routeParameters = Route::current()->parameters();
        $slug = $routeParameters['slug'];
        $slug2 = isset($routeParameters['slug2']) ? $routeParameters['slug2'] : null;
        $slug3 = isset($routeParameters['slug3']) ? $routeParameters['slug3'] : null;
        if ("/$slug" == trans('routes.frontend.shop')) {
            return $this->seller($request, $slug2, $slug3);
        } if ("/$slug" == trans('routes.frontend.brand')) {
            return $this->brand($request, $slug2, $slug3);
        } else if ("/$slug/$slug2" == trans('routes.frontend.product-all')) {
            return $this->productAll($request, $slug3);
        } else {
            //@todo
            $item = $this->getMainSlug($slug);
            $this->cacheMainSlug($request, $item);
            if ($item && isset($item['type']) && $item['type'] == 'category') {
                $attrs = $this->getAttrs($request, [$slug2, $slug3]);
                return $this->category($request, $item, $attrs);
            } else if (\Module::isActive('ZSearch')) {
                if (config('seo::default.redirect_old_tag_url')
                    && ($request->has('category') || $request->has('size_variant_id'))) {
                    return $this->redirectOldTagUrl($request, $slug);
                }
                $attrs = $this->getAttrs($request, [$slug2, $slug3], ['tag', 'color', 'type'], 0);
                return $this->search($request, $item, $attrs);
            } else {
                return $this->tag($request, $slug);
            }
        }
    }


    public function getAttrs($request, $attrs = [], $typeNotIn = ['category', 'tag'], $i = 1) {
        $result = [];
        if ($attrs) {
            foreach ($attrs as $attr) {
                if (!$attr) {
                    continue;
                }
                if ($i > 0) {
                    $typeNotIn[] = 'category';
                }
                if ($i > 1) {
                    $typeNotIn[] = 'type';
                }
                $item = $this->getAttr($attr, $typeNotIn);

                $i++;
                if ($item) {
                    if (in_array($item->type, ['size', 'type', 'color'])) {
                        $itemResult = [
                            $item->type . '_variant_id' => $item->target_id
                        ];
                    } else {
                        $itemResult = [
                            $item->type => $item->target_id,
                        ];
                    }
                    $this->cacheAttr($request, $item);
                    $result = array_merge($result, $itemResult);
                }

            }
        }
        if ($result) {
            $request->merge($result);
        }
        return $result;
    }

    public function getAttr($slug, $typeExclude = []) {
        $result = [];
        $query = DB::table('slug_manager')
            ->where('slug', $slug)
            ->orderBy('priority', 'desc');
        if ($typeExclude) {
            $query->whereNotIn('type', $typeExclude);
        }
        $item = $query->first(['target_id', 'type', 'slug', 'target_id as id']);
        return $item;
    }

    protected function cacheAttr($request, $item) {
        $item = (array) $item;
        $cacheKey = 'cache_filter_' . $item['slug'];
        $this->setFilter($request, $cacheKey, $item, 60);
    }

    protected function getMainSlug($slug) {
        $item = DB::table('slug_manager')
            ->where('slug', $slug)
            ->whereIn('type', ['category', 'tag'])
            ->orderBy('priority', 'desc')
            ->first(['target_id', 'type', 'slug', 'target_id as id']);

        if ($item) {
            $result = (array) $item;
        } else {
            $result = $this->getCategoryBySlug($slug);
            if (!$result) {
                $result = $this->getTagBySlug($slug);
            }
        }
        return $result;

    }

    protected function cacheMainSlug($request, $item) {
        if ($item) {
            $parentFilter = ['id' => $item['id'], 'slug' => $item['slug'], 'type' => 'parent_filter', 'filter_type' => 'category'];
            $this->setFilter(
                $request,
                'cache_filter_parent_' . $item['slug'],
                $parentFilter,
                60
            );
        }

    }


    protected function getTagBySlug($slug) {
        $result = [];
        $item = DB::table('tag')
            ->where('slug', $slug)
            ->first(['id']);
        if ($item) {

            $result = [
                'type' => 'tag',
                'slug' => $slug,
                'target_id' => $item->id,
                'id' => $item->id,
            ];
        }
        return $result;
    }


    protected function getCategoryBySlug($slug) {
        $result = [];
        $item = DB::table('category')
            ->where('slug', $slug)
            ->whereIn('type', 'PRODUCT')
            ->first(['id']);
        if ($item) {
            $result = [
                'type' => 'category',
                'slug' => $slug,
                'target_id' => $item->id,
                'id' => $item->id,
            ];
        }
        return $result;
    }


    public function category($request, $item, $attrs = []) {
        $mergeData =  [
            'category_id' => $item['target_id'],
            'current_route_name' => 'category'
        ];
        $request->merge($mergeData);
        return app()->call('App\Http\Controllers\Frontend\ProductController@search', [
            'paramSlug' => $item['slug'],
            'paramId' => $item['target_id'],
            'request' => $request
        ]);

    }

    public function search($request, $item, $attrs) {
        $tagTitle = null;
        $mergeData = [
            'tag_id' => $item['target_id'],
            'current_route_name' => 'tag',
            'is_tag_page' => 1,
        ];
        $request->merge($mergeData);
        return app()->call('\Modules\ZSearch\Controllers\HomeController@index', [
            'tagTitle' => $tagTitle,
            'request' => $request]);
    }

    public function searchOld($request, $slug, $slug2 = null, $slug3 = null) {
        $tagTitle = null;
        $filter = $this->buildFilter($request, $slug, 1, null);
        if ($filter && count($filter) && in_array($filter['type'], ['category', 'tag'])) {
            if ($filter['type'] == 'tag') {
                $tagTitle = $slug;
                $request->merge([
                    'current_route_name' => 'tag'
                ]);
            } else {
                $request->merge([
                    'current_route_name' => 'search'
                ]);
            }
            $this->setFilter(
                $request, 
                'cache_filter_parent_' . $slug, 
                ['id' => null, 'slug' => $slug, 'type' => 'parent_filter'], 
                60
            );
        } else {
            if (!($filter && count($filter) && in_array($filter['type'], ['category', 'tag', 'color', 'type', 'size']))) {
                // \Log::useDailyFiles(storage_path() . '/logs/module-seo.log');
                // \Log::info('Module SEO search', [env('APP_LOCALE', 'us'), $request->all(), $slug, $slug2, $slug3]);
                abort(404);
            }
            else {
                $request->merge(['is_tag_page' => true]);
                $request->merge([
                    'current_route_name' => 'search'
                ]);
            }
        }
        $filter2 = null;
        if ($slug2) {
            $filter2 = $this->buildFilter($request, $slug2, 2, $filter);
        }
        $filter3 = null;
        if ($slug3) {
            $filter3 = $this->buildFilter($request, $slug3, 3, $filter2);
        }
        return app()->call('\Modules\ZSearch\Controllers\HomeController@index', ['tagTitle' => $tagTitle, 'request' => $request]);
    }

    public function seller(Request $request, $slug = null, $slug2 = null) {
        if(!$slug) {
            $request->merge([
                'current_route_name' => 'seller_list'
            ]);
            return app()->call('App\Http\Controllers\Frontend\ProductController@sellerList', ['request' => $request]);
        }
        $seller = DB::table('users')->where('slug', $slug)->orWhere('name', urldecode($slug))->select('id', 'slug')->first();
        if ($seller) {
            $sellerSlug = trans('routes.frontend.shop') . '/' . $seller->slug;
            $sellerSlug = substr($sellerSlug, 1);
            $parent = ['id' => null, 'slug' => $sellerSlug, 'type' => 'parent_filter'];
            $this->setFilter(
                $request, 
                'cache_filter_parent_' . $sellerSlug, 
                $parent, 
                60
            );
            $request->merge([
                'user_id' => $seller->id,
            ]);
            if ($slug2) {
                $this->buildFilter($request, $slug2, 2, $parent);
            }
            $request->merge([
                'current_route_name' => 'seller'
            ]);
            return app()->call('App\Http\Controllers\Frontend\ProductController@listBySeller', ['request' => $request, 'id' => $seller->id ]);    
        } else {
            \Log::info('Module SEO seller', [$request->all(), $slug]);

            abort(404);
        }
    }

    public function brand(Request $request, $slug = null, $slug2 = null) {
        $brand = DB::table('brand')->where('slug', $slug)->select('id', 'slug')->first();
        if ($brand) {
            $brandSlug = trans('routes.frontend.brand') . '/' . $brand->slug;
            $brandSlug = substr($brandSlug, 1);
            $parent = ['id' => null, 'slug' => $brandSlug, 'type' => 'parent_filter'];
            $this->setFilter(
                $request, 
                'cache_filter_parent_' . $brandSlug, 
                $parent, 
                60
            );
            $request->merge(['brand' => $brand->id]);
            if ($slug2) {
                $this->buildFilter($request, $slug2, 2, $parent);
            }
            $request->merge([
                'current_route_name' => 'brand'
            ]);
            return app()->call('App\Http\Controllers\Frontend\ProductController@search', [ 'paramSlug' => null, 'paramId' => null, 'request' => $request ]);    
        } else {
            \Log::info('Module SEO brand', [$request->all(), $slug]);
            abort(404);
        }
    }

    public function productAll(Request $request, $slug = null) {
        $parent = ['id' => null, 'slug' => substr(trans('routes.frontend.product-all'), 1), 'type' => 'parent_filter'];
        $this->setFilter(
            $request, 
            'cache_filter_parent_' . substr(trans('routes.frontend.product-all'), 1), 
            $parent, 
            60
        );
        if ($slug) {
            $this->buildFilter($request, $slug, 1, $parent);
        }
        $request->merge([
            'current_route_name' => 'search'
        ]);
        return app()->call('App\Http\Controllers\Frontend\ProductController@search', [ 'paramSlug' => null, 'paramId' => null, 'request' => $request ]);    
    }

    public function tag(Request $request, $slug) {
        $tags = Tag::where('slug', '=', $slug)->first();
        if (!empty($tags)) {
            $request->merge([
                'current_route_name' => 'tag'
            ]);
            return app()->call('App\Http\Controllers\Frontend\ProductController@listByTag', [ 'paramSlug' => $tags->slug, 'paramId' => $tags->id ]);
        } else {
            \Log::info('Module SEO tag', [$request->all(), $slug]);
            abort(404);
        }
    }

    public function buildFilter(&$request, $slug, $index = 1, $parent = null) {
        $filter = $this->slugToFilter($request, $slug, $index, $parent);
        if (count($filter)) {
            switch ($filter['type']) {
                case 'category':
                    $request->merge([
                        'category' => $filter['id']
                    ]);
                    break;
                case 'tag':
                    if ($request->has('category_id') && $request->has('id')) {
                        $request->merge([
                            'tag' => $filter['id']
                        ]);
                    } else {
                        $request->merge([
                            'id' => $filter['id']
                        ]);
                    }
                    break;
                case 'type':
                    $request->merge([
                        'type_variant_id' => $filter['id']
                    ]);
                    break;
                case 'color':
                    $request->merge([
                        'color_variant_id' => $filter['id']
                    ]);
                    break;
                case 'size':
                    $request->merge([
                        'size_variant_id' => $filter['id']
                    ]);
                    break;
                default:
                    break;
            }
        }

        return $filter;
    }

    public function slugToFilter($request, $slug, $index = 1, $parent = null) {
        $cacheKey = 'cache_filter_' . $slug;

        if (Cache::get($this->decorCacheKey($cacheKey))) {
            $retVal = json_decode(Cache::get($this->decorCacheKey($cacheKey)), true);
            $this->setFilter($request, $cacheKey, $retVal, 60);
            return $retVal;
        }
        $retVal = [];
        $filter = null;
        if ((!$parent && $index < 3) || $parent) {
            $query = DB::table('category')
                ->select('id', 'name', 'slug', 'parent_id')
                ->where('type', '=', 'PRODUCT')
                ->where('slug', '=', $slug)
                ->orderBy('id', 'asc');     
            if ($parent && $parent['type'] == 'category') {
                $query->where('parent_id', $parent['id']);
            }
            $filter = $query->first();
        }
        if ($filter) {
            $retVal = [
                'id' => $filter->id,
                'slug' => $slug,
                'type' => 'category'
            ];
        } else {
            $tag = null;
            if ((!$parent && $index == 1) || ($parent && $parent['type'] == 'category')) {
                $tag = Tag::where('slug', '=', $slug)->orderBy('id', 'asc')->first();
            }
            $locale = env('APP_LOCALE', 'us') ?? 'us';
            if (config('seo::default.variant_slug.' . $locale . '.' . $slug)) {
                $id = config('seo::default.variant_slug.' . $locale . '.' . $slug);
                $option = ProductVariantOption::with('variant')->where('id', $id)->first();
            } else {
                $variantIds = ProductVariant::whereIn('name', config('seo::default.filter_option', []))
                    ->orderBy('id', 'asc')
                    ->get(['id'])
                    ->pluck('id');
                $option = ProductVariantOption::where('slug', $slug)
                    ->whereIn('variant_id', $variantIds)
                    ->orderBy('id', 'asc')
                    ->first();
            }
            if ($tag && !$option) {
                $retVal = [
                    'id' => $tag->id,
                    'slug' => $slug,
                    'type' => 'tag'
                ];

            } else if ($option) {
                $retVal = [
                    'id' => $option->id,
                    'slug' => $option->slug,
                    'type' => $option->variant->slug
                ];
            }
        }
        if (count($retVal)) {
            $this->setFilter($request, $cacheKey, $retVal, 60);
        }

        return $retVal;
    }

    private function redirectOldTagUrl($request, $slug) {
        $urlQueryParams = $request->all();
        if ($request->has('size_variant_id') && $request->has('category')) {
            $variantOptions = DB::table('product_variant_option')->where('id', $request->get('size_variant_id'))->first(['slug']);
            $categorySlug = DB::table('category')->where('id', '=', $request->get('category'))->select('id', 'name', 'slug')->first();
            if (!empty($categorySlug) && !empty($variantOptions)) {
                unset($urlQueryParams['size_variant_id']);
                unset($urlQueryParams['category']);
                $urlQueryParams['slug'] = $slug;
                $urlQueryParams['slug2'] = $categorySlug->slug;
                $urlQueryParams['slug3'] = $variantOptions->slug;
            }
        } else if ($request->has('size_variant_id')) {
            $variantOptions = DB::table('product_variant_option')->where('id', $request->get('size_variant_id'))->first(['slug']);
            if (!empty($variantOptions)) {
                unset($urlQueryParams['size_variant_id']);
                $urlQueryParams['slug'] = $slug;
                $urlQueryParams['slug2'] = $variantOptions->slug;
            }
        } else if ($request->has('category')) {
            $categorySlug = DB::table('category')->where('id', '=', $request->get('category'))->select('id', 'name', 'slug')->first();
            if (!empty($categorySlug)) {
                unset($urlQueryParams['category']);
                $urlQueryParams['slug'] = $slug;
                $urlQueryParams['slug2'] = $categorySlug->slug;
            }
        }
        return redirect()->route('categoryOrTag', $urlQueryParams);
    }
}