<?php

namespace App\Services\Main\Products;

use App\Models\InventoryProp;
use App\Models\Product;
use App\Models\Setting;
use App\Models\User;
use Carbon\Carbon;
use DateTimeZone;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Cookie;
use Morilog\Jalali\Jalalian;

class ProductService
{
    /** affiliate cookie minute */
    public int $AFFILIATE_COOKIE_MINUTE = 10080;

    /** seo meta data */
    public array $seo = [
        'schema' => null,
        'site_name' => null,
        'title' => null,
        'store_name' => null,
        'description' => null,
        'keywords' => null,
        'canonical' => null,
        'author' => null,
        'image' => null,
        'type' => null,
    ];

    /** add product to last viewed list */
    public function addProductTolastViewedList(Request $request, Product $product)
    {
        $lastViewedProduct = $request->session()->get('last_viewed_product', []);
        if (count($lastViewedProduct) > 8) {
            $lastViewedProduct = array_slice($lastViewedProduct, -8, 8, true);
        }
        if (array_key_exists("product_" . $product->id, $lastViewedProduct)) {
            unset($lastViewedProduct["product_" . $product->id]);
        }
        $lastViewedProduct["product_" . $product->id] = [
            'id' => $product->id,
            'title' => $product->title,
            'slug' => $product->slug,
            'image' => $product->get_images[0],
        ];
        session(['last_viewed_product' => $lastViewedProduct]);
    }

    /** get product inventory list */
    public function getProductInventories(Product $product)
    {
        $inventories = $product->inventories()->where('status', 'publish')->where('count', '>', 0)->where(function ($query) {
            $query->doesntHave('store')->orWhereHas('store', function ($query) {
                $query->where('status', 'active');
            });
        })->get()->map(fn($inventory) => [
            'id' => $inventory->id,
            'price' => $inventory->price,
            'get_formatted_price' => $inventory->get_formatted_price,
            'discount_price' => $inventory->discount_price,
            'get_formatted_discount_price' => $inventory->get_formatted_discount_price,
            'discount_expire' => $inventory->discount_expire != null ? Jalalian::forge($inventory->discount_expire, new DateTimeZone("Asia/Tehran"))->getTimestamp() : null,
            'is_discount_valid' => $inventory->is_discount_valid,
            'count' => $inventory->count,
            'get_formatted_count' => $inventory->get_formatted_count,
            'min_sale' => $inventory->min_sale,
            'max_sale' => $inventory->max_sale,
            'original' => $inventory->original,
            'used' => $inventory->used,
            'get_discount_percent' => $inventory->get_discount_percent,
            'get_final_price' => $inventory->get_final_price,
            'get_formatted_final_price' => $inventory->get_formatted_final_price,
            'store' => $inventory->store_id != null ? $inventory->store->safe : null,
            'raw_props' => $inventory->raw_props,
            'get_customer_club_score' => $inventory->get_customer_club_score,
            'price_changes' => $inventory->price_changes,
            'get_image' => $inventory->get_image,
            'get_price_changes' => $inventory->get_price_changes,
            'get_price_changes_chart' => $inventory->get_price_changes_chart,
            'send_time' => $inventory->send_time,
        ])->toArray();

        return  $product->in_stock_status ? $inventories : [];
    }

    /** get related product list */
    public function getRelatedProducts(Product $product)
    {
        // تعداد محصولات
        $itemCount = 10;

        // کوئری آغازین
        $baseQuery = Product::where('status', 'publish')
            ->where('id', '!=', $product->id)
            ->where('category_id', $product->category_id);

        // محصولات دارای موجودی
        $inStockProducts = (clone $baseQuery)
            ->whereHas('inventories', fn($q) => $q->where('count', '>', 0))
            ->inRandomOrder()
            ->take($itemCount)
            ->get();

        if ($inStockProducts->count() >= $itemCount) {
            $relatedProducts = $inStockProducts;
        } else {
            $remaining = $itemCount - $inStockProducts->count();

            $outOfStockProducts = (clone $baseQuery)
                ->where(function ($q) {
                    $q->doesntHave('inventories')
                        ->orWhereHas('inventories', fn($q2) => $q2->where('count', '<=', 0));
                })
                ->inRandomOrder()
                ->take($remaining)
                ->get();

            $relatedProducts = $inStockProducts->concat($outOfStockProducts);
        }

        // اطمینان از محدودیت نهایی
        $relatedProducts = $relatedProducts->take($itemCount);

        return $relatedProducts->map(fn($product) => [
            'id' => $product->id,
            'title' => $product->title,
            'slug' => $product->slug,
            'get_images' => $product->get_images,
            'comments_info' => $product->comments_info,
            'in_stock_status' => $product->in_stock_status,
            'inventory' => $product->inventory,
            'best_normal_price' => $product->best_normal_price,
            'unique_color' => $product->unique_color,
            'best_price' => $product->best_price,
        ]);
    }

    /** get product comment list */
    public function getProductComments(Request $request, Product $product)
    {
        $comments = $product->productComments()->where('status', 'publish')->when($request->input('clatest'), function ($query, $clatest) {
            if ($clatest) {
                $query->orderBy('created_at', 'desc');
            }
        })->when($request->input('useful'), function ($query, $useful) {
            if ($useful) {
                $query->orderBy('vote_up', 'desc');
            }
        })->when($request->input('buyers'), function ($query, $buyers) {
            if ($buyers) {
                $query->whereHas('user', function ($query) {
                    $query->whereHas('consignments', function ($query) {
                        $query->whereHas('consignmentItems', function ($query) {
                            $query->where('status', 'sent')->orWhere('status', 'delivered');
                        });
                    });
                });
            }
        })->orderBy('created_at', 'desc')->paginate(5, ['*'], 'cpage')->through(fn($comment) => [
            'id' => $comment->id,
            'content' => $comment->content,
            'get_strengths' => $comment->get_strengths,
            'get_weakness' => $comment->get_weakness,
            'is_buyer' => $comment->is_buyer,
            'buy_suggest' => $comment->buy_suggest,
            'jalali_created_at' => $comment->jalali_created_at,
            'vote_up' => $comment->vote_up,
            'vote_down' => $comment->vote_down,
            'get_images' => $comment->get_images,
            'get_answer' => $comment->get_answer,

            'user' => [
                'id' => $comment->user->id,
                'get_name' => $comment->user->get_name,
            ],
        ]);
        $comments->withQueryString();

        return  $comments;
    }

    /** get product question list */
    public function getProductQuestions(Request $request, Product $product)
    {
        $questions = $product->questions()->where('status', 'publish')->when($request->input('qlatest'), function ($query, $qlatest) {
            if ($qlatest) {
                $query->orderBy('created_at', 'desc');
            }
        })->when($request->input('noanswer'), function ($query, $noanswer) {
            if ($noanswer) {
                $query->has('questionAnswers', 0);
            }
        })->when($request->input('answer'), function ($query, $answer) {
            if ($answer) {
                $query->has('questionAnswers', '>', 0);
            }
        })->orderBy('created_at', 'desc')->paginate(5, ['*'], 'qpage')->through(fn($question) => [
            'id' => $question->id,
            'question' => $question->question,
            'answers' => $question->answers->map(fn($answer) => [
                'id' => $answer['safe']['id'],
                'answer' => $answer['safe']['answer'],
                'is_buyer' => $answer['safe']['is_buyer'],
                'vote_up' => $answer['safe']['vote_up'],
                'vote_down' => $answer['safe']['vote_down'],
                'status' => $answer['safe']['status'],

                'user' => [
                    'id' => $answer['safe']['user']['id'],
                    'get_name' => $answer['safe']['user']['get_name'],
                    'type' => $answer['safe']['user']['type'],
                    'seller' => $answer['safe']['user']['seller'],
                ],
            ]),
        ]);
        $questions->withQueryString();

        return  $questions;
    }

    /** get product props */
    public function getProductProps(Product $product)
    {
        $mainLevels = Cache::remember('get_product_props_' . $product->id, now()->addMonth(), function () use ($product) {
            // Get Main Level
            $inventories = $product->inventories()->where('status', 'publish')->where('count', '>', 0)->where(function ($query) {
                $query->doesntHave('store')->orWhereHas('store', function ($query) {
                    $query->where('status', 'active');
                });
            })->get();

            $mainLevels = [];
            $mainLevelName = null;
            $mainLevelIDs = [];

            foreach ($inventories as $inventory) {
                $mainLevelModel = $inventory->inventoryProps->where('child', 0)->first();

                if ($mainLevelModel != null) {
                    $mainLevelKey = $mainLevelModel->type == 'color' ? unserialize($mainLevelModel->value)['color'] : $mainLevelModel->value;
                    $mainLevelName = $mainLevelModel->name;
                    $mainLevelIDs[$mainLevelKey][] = $mainLevelModel->id;

                    $mainLevels[$mainLevelName][$mainLevelKey] = [
                        'id' => $mainLevelIDs[$mainLevelKey],
                        'name' => $mainLevelModel->name,
                        'type' => $mainLevelModel->type,
                        'value' => $mainLevelModel->type == 'color' ? unserialize($mainLevelModel->value) : $mainLevelModel->value,
                    ];
                }
            }

            // Get Sub Level
            if (count($mainLevels) > 0) {
                foreach ($mainLevels[$mainLevelName] as $key => $mainLevel) {
                    $mainLevels[$mainLevelName][$key]['child'] = $this->getProductPropsSubLevel($mainLevel);
                }
            }

            return $mainLevels;
        });

        return $product->in_stock_status ? $mainLevels : [];
    }

    /** get inventory props sub level */
    public function getProductPropsSubLevel($mainLevel)
    {
        // Get Sub Level
        $out = [];

        $inventoryChilds = InventoryProp::whereIn('child', $mainLevel['id'])->get()->map(fn($ip) => [
            'id' => $ip->id,
            'name' => $ip->name,
            'type' => $ip->type,
            'value' => $ip->value,
        ])->groupBy('value')->toArray();

        if (count($inventoryChilds) > 0) {
            $subLevels = [];
            $subLevelName = null;

            foreach ($inventoryChilds as $inventoryChild) {
                $subLevelIDs = [];
                foreach ($inventoryChild as $ich) {
                    $subLevelName = $ich['name'];
                    $subLevelIDs[] = $ich['id'];
                    $subLevels[$subLevelName][$ich['value']] = [
                        'id' => $subLevelIDs,
                        'name' => $ich['name'],
                        'type' => $ich['type'],
                        'value' => $ich['value'],
                    ];
                }
            }

            // Get Recursive Sub Level
            foreach ($subLevels[$subLevelName] as $key => $subLevel) {
                $subLevels[$subLevelName][$key]['child'] = $this->getProductPropsSubLevel($subLevel);
            }

            $out = $subLevels;
        } else {
            $out = null;
        }

        return $out;
    }

    /**
     * add affiliate user link
     */
    public function addAffiliate(Request $request, Product $product)
    {
        $user = User::find($request->u);

        if ($user == null) {
            return;
        }

        /** check current user */
        if (auth()->check()) {
            /** @var \App\Models\User $currentUser */
            $currentUser = auth()->user();

            // skip current user link with own affiliate link
            if ($user->id == $currentUser->id) {
                return;
            }
        }

        $affiliatesCookie = request()->cookie('affiliates');
        $affiliates = $affiliatesCookie != null ? unserialize($affiliatesCookie) : [];
        $affiliates[$product->uuid] = $user->id;

        // set cookie
        Cookie::queue('affiliates', serialize($affiliates), $this->AFFILIATE_COOKIE_MINUTE);
    }

    /** seo information */
    public function seo(Product $product)
    {
        $shopTitle = Cache::remember('setting_shop_title', now()->addMonth(), function () {
            return Setting::where('key', 'shop_title')->first() != null ? Setting::where('key', 'shop_title')->first()->value : null;
        });

        // schema
        $this->seo['schema'] = $this->productSchema($product);

        // main
        $this->seo['site_name'] = $shopTitle;
        $this->seo['title'] = ($product->seo_title != null ? $product->seo_title : $product->title);
        $this->seo['store_name'] = $product->user->store != null ? $product->user->store->title : $shopTitle;
        $this->seo['description'] = $product->seo_description;
        $this->seo['keywords'] = $product->get_seo_keywords;
        $this->seo['canonical'] = $product->seo_canonical;
        $this->seo['author'] = $product->user->name;
        $this->seo['image'] = $product->get_images[0]['link'];
        $this->seo['availability'] = $product->inventory ? 'in stock' : 'out of stock';
        $this->seo['type'] = 'product';

        // return information
        return $this->seo;
    }

    /** Product Schema */
    public function productSchema(Product $product)
    {
        $shopFullTitle = Cache::remember('setting_shop_full_title', now()->addMonth(), function () {
            return Setting::where('key', 'shop_full_title')->first() != null ? Setting::where('key', 'shop_full_title')->first()->value : null;
        });
        $productImages = [];
        foreach ($product->get_images as $image) {
            $productImages[] = $image['link'];
        }

        $productSchema = [
            "@context" => "https://schema.org",
            "@type" => "Product",
            "name" => $product->title,
            "alternateName" => $product->title_en,
            "image" => $productImages,
            "description" => mb_strlen(strip_tags($product->seo_description), 'UTF-8') > 500 ? mb_substr(strip_tags($product->seo_description), 0, 497, 'UTF-8') . '...' : strip_tags($product->seo_description),
            "category" => urldecode(route('main.products.index', ['cat' => $product->productCategory->slug])),
            "brand" => $product->brand != null ? [
                "@type" => "Brand",
                "name" => $product->brand->title,
                "url" => urldecode(route('main.products.index', ['brand' => $product->brand->slug])),
            ] : null,
            "offers" => [
                "@type" => "Offer",
                "url" => urldecode(route('main.products.show', $product->slug)),
                "priceCurrency" => "IRR",
                "price" => (int)str_replace(',', '', $product->best_price) * 10,
                "itemCondition" => "https://schema.org/NewCondition",
                "availability" => $product->inventory ? "https://schema.org/InStock" : "https://schema.org/OutOfStock",
                "priceValidUntil" => Carbon::now()->addYears(5)->toDateString(),
                "seller" => [
                    "@type" => "Organization",
                    "name" => $shopFullTitle,
                    "url" => urldecode(route('index'))
                ]
            ],

        ];

        if (str_replace(',', '', $product->comments_info['count']) > 0) {
            $productSchema["aggregateRating"] = [
                "@type" => "AggregateRating",
                "ratingValue" => (float)$product->comments_info['rating'],
                "reviewCount" => !empty($product->comments_info['count']) ? (int)$product->comments_info['count'] : 1,
                "bestRating" => 5,
                "worstRating" => 1
            ];

            $lastReview = Cache::remember('product_first_comment_' . $product->id, now()->addMonth(), function () use ($product) {
                return $product->productComments()->where('status', 'publish')->orderBy('created_at', 'desc')->first();
            });
            if ($lastReview != null) {
                $productSchema["review"] = [
                    "@type" => "Review",
                    "reviewRating" => [
                        "@type" => "Rating",
                        "bestRating" => 5,
                        "worstRating" => 1,
                        "ratingValue" => (int)$lastReview->rating
                    ],
                    "author" => [
                        "@type" => "Person",
                        "name" => $lastReview->user->name,
                    ],
                    "datePublished" => Carbon::create($lastReview->created_at)->format('Y-m-d'),
                    "reviewBody" => $lastReview->content,
                ];
            }
        }

        $breadcrumbSchema = [
            "@context" => "https://schema.org",
            "@type" => "BreadcrumbList",
            "itemListElement" => [
                [
                    "@type" => "ListItem",
                    "position" => 1,
                    "name" => $shopFullTitle,
                    "item" => urldecode(route('index'))
                ],
                [
                    "@type" => "ListItem",
                    "position" => 2,
                    "name" => $product->productCategory->title,
                    "item" => urldecode(route('main.products.index', ['cat' => $product->productCategory->slug]))
                ],
                [
                    "@type" => "ListItem",
                    "position" => 3,
                    "name" => $product->title,
                    "item" => urldecode(route('main.products.show', $product->slug))
                ]
            ],
        ];

        return [
            'product' => json_encode($productSchema, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
            'breadcrumb' => json_encode($breadcrumbSchema, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
        ];
    }
}
