<?php

namespace App\Services\Admin\Storage;

use App\Models\Inventory;
use App\Models\Product;
use App\Notifications\ProductNotification;
use Carbon\Carbon;
use Illuminate\Http\Request;

class InventoriesService
{
    /** get inventories list */
    public function getInventories(Product $product): array
    {
        $inventories = [
            'main' => $product->inventories()->where('store_id', null)->orderBy('created_at', 'desc')->get()->map(fn($inventory) => [
                'id' => $inventory->id,
                'store_id' => $inventory->store_id,
                'uuid' => $inventory->uuid,
                'props' => $inventory->props,
                'get_formatted_price' => $inventory->get_formatted_price,
                'discount_price' => $inventory->discount_price,
                'get_formatted_discount_price' => $inventory->get_formatted_discount_price,
                'jalali_discount_expire' => $inventory->jalali_discount_expire,
                'is_discount_valid' => $inventory->is_discount_valid,
                'count' => $inventory->count,
                'min_sale' => $inventory->min_sale,
                'max_sale' => $inventory->max_sale,
                'original' => $inventory->original,
                'used' => $inventory->used,
                'weight' => $inventory->weight,
                'get_image' => $inventory->get_image,
                'description' => $inventory->description,
                'get_discount_tree' => $inventory->get_discount_tree,
                'send_time' => $inventory->send_time,
                'purchase_price' => $inventory->purchase_price,
                'status' => $inventory->status,

                'storage' => $inventory->storage != null ? [
                    'id' => $inventory->storage->id,
                    'name' => $inventory->storage->name,
                ] : null,
                'store' => $inventory->store != null ? [
                    'id' => $inventory->store->id,
                    'uuid' => $inventory->store->uuid,
                    'name' => $inventory->store->name,
                    'get_logo' => $inventory->store->get_logo,
                ] : null,
            ]),
            'stores' => $product->inventories()->where('store_id', '!=', null)->orderByRaw("FIELD(status , 'awaiting', 'publish', 'deactive') ASC")->orderBy('created_at', 'desc')->get()->map(fn($inventory) => [
                'id' => $inventory->id,
                'store_id' => $inventory->store_id,
                'uuid' => $inventory->uuid,
                'props' => $inventory->props,
                'get_formatted_price' => $inventory->get_formatted_price,
                'discount_price' => $inventory->discount_price,
                'get_formatted_discount_price' => $inventory->get_formatted_discount_price,
                'jalali_discount_expire' => $inventory->jalali_discount_expire,
                'is_discount_valid' => $inventory->is_discount_valid,
                'count' => $inventory->count,
                'min_sale' => $inventory->min_sale,
                'max_sale' => $inventory->max_sale,
                'original' => $inventory->original,
                'used' => $inventory->used,
                'weight' => $inventory->weight,
                'get_image' => $inventory->get_image,
                'description' => $inventory->description,
                'get_discount_tree' => $inventory->get_discount_tree,
                'send_time' => $inventory->send_time,
                'purchase_price' => $inventory->purchase_price,
                'status' => $inventory->status,

                'storage' => $inventory->storage != null ? [
                    'id' => $inventory->storage->id,
                    'name' => $inventory->storage->name,
                ] : null,
                'store' => $inventory->store != null ? [
                    'id' => $inventory->store->id,
                    'uuid' => $inventory->store->uuid,
                    'name' => $inventory->store->name,
                    'get_logo' => $inventory->store->get_logo,
                ] : null,
            ]),
        ];

        return $inventories;
    }

    /** get price model */
    public function getPriceModel(Inventory $inventory)
    {
        $priceModel = [];
        foreach ($inventory->inventoryProps()->get() as $key => $inventoryProp) {
            $priceModel[$inventoryProp['id']] = [
                "child" => $inventoryProp['child'],
                "name" => $inventoryProp['name'],
                "type" => $inventoryProp['type'],
                "value" => $inventoryProp['type'] == 'color' ? unserialize($inventoryProp['value']) : $inventoryProp['value'],
            ];
        }

        return $priceModel;
    }

    /** validate Single Price */
    public function validateSinglePrice(Product $product): bool
    {
        if (count($product->price_model) == 0)
            if ($product->inventories()->where('store_id', null)->get()->count() > 0)
                return true;

        return false;
    }

    /** get props */
    public function getProps(Request $request, Product $product): array
    {
        if (count($product->price_model) > 0) {
            $request->validate([
                'props' => ['required', 'array'],
            ]);

            return $request->props;
        }

        return [];
    }

    /** get variables for api */
    public function getVariables(Request $request, Product $product): array
    {
        if (count($product->price_model) > 0) {
            $request->validate([
                'variables' => ['required', 'array'],
            ]);

            return $request->variables;
        }

        return [];
    }

    /** validate props */
    public function validateProps(array $props, Product $product, $inventory = null): bool | array
    {
        if ($inventory != null) {
            // edit mode
            foreach ($inventory->inventoryProps()->get() as $inventoryProp) {
                if (!array_key_exists($inventoryProp->id, $props))
                    return false;

                if ($props[$inventoryProp->id]['type'] == "warranty" && (!array_key_exists('value', $props[$inventoryProp->id]) || $props[$inventoryProp->id]['value'] == null || $props[$inventoryProp->id]['value'] == ''))
                    $props[$inventoryProp->id]['value'] = __('messages.sentence.default_warranty');

                if (!array_key_exists('value', $props[$inventoryProp->id]))
                    return false;

                if ($props[$inventoryProp->id]['value'] == null || $props[$inventoryProp->id]['value'] == '')
                    return false;
            }
        } else {
            // create mode
            foreach ($product->price_model as $key => $pm) {
                if (!array_key_exists($key, $props))
                    return false;

                if ($props[$key]['type'] == "warranty" && (!array_key_exists('value', $props[$key]) || $props[$key]['value'] == null || $props[$key]['value'] == ''))
                    $props[$key]['value'] = __('messages.sentence.default_warranty');

                if (!array_key_exists('value', $props[$key]))
                    return false;

                if ($props[$key]['value'] == null || $props[$key]['value'] == '')
                    return false;
            }
        }

        return $props;
    }

    /** validate duplicate props */
    public function validateDuplicateProps(array $props, Product $product, $currentInventory = null): bool
    {
        foreach ($product->inventories()->where('store_id', null)->get() as $inventory) {
            // in edit mode: continue if inventory is equal current
            if ($currentInventory != null && $currentInventory->id == $inventory->id)
                continue;

            // prev prop
            $prevProp = [];
            $inProps = $inventory->inventoryProps->map(fn($inp) => [
                $inp->name => $inp->type == 'color' ? unserialize($inp->value)['color'] : $inp->value,
            ])->toArray();
            foreach ($inProps as $value) {
                foreach ($value as $k => $v) {
                    $prevProp[$k] = $v;
                }
            }

            // current prop
            $currentProp = [];
            foreach ($props as $p) {
                $currentProp[$p['name']] = $p['type'] == 'color' ? $p['value']['color'] : $p['value'];
            }

            if (count($prevProp) > 0) {
                if (count(array_diff($prevProp, $currentProp)) == 0) {
                    return false;
                }
            }
        }

        return true;
    }

    /** handle product notifications */
    public function handleProductNotifications(Product $product)
    {
        // inventory notification
        if ($product->inventory) {
            foreach ($product->productNotifications()->where('type', 'inventory')->get() as $pn) {
                // notification
                $pn->user->notify(new ProductNotification($product, 'inventory'));
                $product->productNotifications()->where('user_id', $pn->user_id)->where('type', 'inventory')->delete();
            }
        }

        // discount notification
        if ($product->has_discount) {
            foreach ($product->productNotifications()->where('type', 'discount')->get() as $pn) {
                // notification
                $pn->user->notify(new ProductNotification($product, 'discount'));
                $product->productNotifications()->where('user_id', $pn->user_id)->where('type', 'discount')->delete();
            }
        }
    }

    /** handle price changes */
    public function handlePriceChanges($priceChanges, $price)
    {
        if (is_array($priceChanges)) {
            foreach ($priceChanges as $key => $value) {
                // delete all current day prices
                if ((Carbon::now()->timestamp - $key) < 86400) {
                    unset($priceChanges[$key]);
                    continue;
                }

                // delete all old price than 1month ago
                if ((Carbon::now()->timestamp - $key) > 2592000) {
                    unset($priceChanges[$key]);
                }
            }
        }
        // add to price changes
        $priceChanges[Carbon::now()->timestamp] = $price;

        return $priceChanges;
    }
}
