<?php

namespace App\Nova\Repos\Payouts;

use App\Models\Ecommerce\Product\Order\OrderItem;
use App\Models\Ecommerce\Product\Order\Status\OrderStatus;
use Closure;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;
use Laravel\Nova\Http\Requests\NovaRequest;

class PayoutsRepo
{
    /**
     * Order items ids element "depends on"
     */
    public static function orderItemIdsDependsOn(): Closure
    {
        return function ($field, $request, $formData) {
            if (
                ! $formData->channel_id ||
                ! $formData->start_date ||
                ! $formData->end_date ||
                $request->isUpdateOrUpdateAttachedRequest()
            ) {
                return;
            }

            $paid_products = DB::table('payout_items')
                ->where('channel_id', $formData->channel_id)
                ->distinct('order_item_id')
                ->pluck('order_item_id');

            $order_items = OrderItem::query()
                ->with(['product' => ['media']])
                ->join(
                    table: 'orders',
                    first: fn ($join) => $join->on('order_items.order_id', '=', 'orders.id')
                        ->where('orders.status', '=', OrderStatus::COMPLETED)
                )
                ->where('order_items.channel_id', $formData->channel_id)
                ->whereIntegerNotInRaw('order_items.id', $paid_products)
                ->whereRaw('(order_items.created_at >= ? AND order_items.created_at <= ?)', [
                    $formData->start_date.' 00:00:00',
                    $formData->end_date.' 23:59:59',
                ])
                ->orderBy('order_items.order_id')
                ->get([
                    'order_items.id',
                    'order_items.order_id',
                    'order_items.product_name',
                    'order_items.product_id',
                    'order_items.quantity',
                    'order_items.unit_price_amount',
                    'order_items.unit_cost_amount',
                    'order_items.channel_id',
                    'order_items.created_at',
                ])->map(fn ($orderItem) => [
                    'id' => $orderItem->id,
                    'product_name' => $orderItem->product_name,
                    'product_id' => $orderItem->product_id,
                    'order_id' => $orderItem->order_id,
                    'channel_id' => $orderItem->channel_id,
                    'quantity' => $orderItem->quantity,
                    'unit_price_amount' => $orderItem->unit_price_amount,
                    'product_cost_amount' => $orderItem->unit_cost_amount ?: $orderItem->product->cost_amount,
                    'created_at' => $orderItem->created_at,
                    'updated_at' => $orderItem->updated_at,
                    'product_thumbnail' => $orderItem->product->thumbnail() ?? null,
                ]);

            $field->products($order_items);
        };
    }

    /**
     * Total element "depends on"
     */
    public static function totalDependsOn(): Closure
    {
        return function ($field, $request, $formData) {
            if (! $formData->order_items_ids || ! $request->prices) {
                return;
            }

            $orderItems = OrderItem::whereIntegerInRaw('id', $formData->order_items_ids)->get();

            $products = collect($request->prices)
                ->map(fn ($product) => is_string($product) ? json_decode($product) : null)
                ->filter();

            $total_sum = 0;
            $entrepreneur_total = 0;
            $postshop_total = 0;
            foreach ($orderItems as $item) {
                $percentage_difference =
                    $item->unit_price_amount - $products->firstWhere('product_id', $item->product_id)->cost_amount;

                $total_sum += $item->unit_price_amount * $item->quantity;
                $postshop_total += $percentage_difference * $item->quantity;
                $entrepreneur_total += $products->firstWhere('product_id', $item->product_id)->cost_amount * $item->quantity;
            }

            $field->setValue(number_format($total_sum, 2, '.', ''));

            cache(['nova.entrepreneur_total' => number_format($entrepreneur_total, 2, '.', '')]);
            cache(['nova.postshop_total' => number_format($postshop_total, 2, '.', '')]);
        };
    }

    /**
     * Order item ids fill
     */
    public static function orderItemIdsFill(NovaRequest $request, Model $model): void
    {
        $model::withoutEvents(function () use ($request, $model) {
            $order_item_ids = [];

            $products = collect($request->prices)
                ->map(fn ($product) => is_string($product) ? json_decode($product) : null)
                ->filter()
                ->each(function ($product) {
                    DB::table('order_items')
                        ->where('id', $product->order_item_id)
                        ->update(['unit_cost_amount' => $product->cost_amount]);
                });

            if ($request->filled('order_items_ids')) {
                foreach ($request->order_items_ids as $id) {
                    if (! $id) {
                        continue;
                    }

                    $order_item_ids[] = [
                        'payout_id' => $model->id,
                        'channel_id' => $model->channel_id,
                        'order_item_id' => $id,
                        'created_at' => $model->created_at,
                        'updated_at' => now(),
                    ];
                }
            }

            if (! empty($order_item_ids)) {
                DB::table('payout_items')->insert($order_item_ids);
            }
        });
    }

    /**
     * Resolve order items
     */
    public static function resolveOrderItems($request, $resource): Closure
    {
        return function () use ($request, $resource) {
            if (! $request->isResourceDetailRequest()) {
                return;
            }

            $items = $resource->orderItems;

            $media = DB::table('media')
                ->where('model_type', 'product')
                ->whereIntegerInRaw('model_id', $items->pluck('product_id'))
                ->get(['id', 'model_id', 'file_name']);

            return $items->map(function ($orderItem) use ($media) {
                return [
                    'id' => $orderItem->id,
                    'product_name' => $orderItem->product_name,
                    'product_id' => $orderItem->product_id,
                    'order_id' => $orderItem->order_id,
                    'channel_id' => $orderItem->channel_id,
                    'quantity' => $orderItem->quantity,
                    'unit_price_amount' => $orderItem->unit_price_amount,
                    'unit_cost_amount' => $orderItem->unit_cost_amount,
                    'created_at' => $orderItem->created_at,
                    'updated_at' => $orderItem->updated_at,
                    'product_thumbnail' => url(
                        sprintf(
                            'storage/%s/%s',
                            $media->firstWhere(
                                'model_id',
                                $orderItem->product_id
                            )?->id,
                            $media->firstWhere(
                                'model_id',
                                $orderItem->product_id
                            )?->file_name
                        )
                    ),
                ];
            });
        };
    }
}
