<?php

namespace Modules\Bms\Services\Catalog;

use App\Product;
use App\Variation;
use Modules\Bms\Entities\BmsProductMedia;
use Modules\Bms\Entities\BmsProductMeta;
use Modules\Bms\Services\Contracts\MediaServiceContract;

/**
 * Resolves the funnel-facing presentation of a core ERP product — the single
 * source of truth shared by the package builder and the client funnel:
 *   name / name_ar / description / description_ar
 *   media[]    (image|video|360, from bms_product_media)
 *   base_cost / base_sell
 *   variants[] (variable product → its variations as swap options w/ price delta)
 *   contents[] (combo product → its components, localized + qty + unit)
 *
 * Per-package overrides (on the bms_package_items row) are layered on top by the
 * caller (null = inherit); this service returns only the product-derived values.
 */
class ProductPresentation
{
    /** @return array{name:string,name_ar:?string,description:?string,description_ar:?string,media:array,base_cost:float,base_sell:float,variants:array,contents:array}|null */
    public function for(int $businessId, ?int $productId, ?int $variationId = null): ?array
    {
        if (! $productId) {
            return null;
        }
        $product = Product::where('business_id', $businessId)->with('variations')->find($productId);
        if (! $product) {
            return null;
        }

        $meta = BmsProductMeta::where('product_id', $productId)->first();
        $default = $variationId ? $product->variations->firstWhere('id', $variationId) : $product->variations->first();
        $baseSell = (float) optional($default)->sell_price_inc_tax;
        $baseCost = (float) (optional($default)->dpp_inc_tax ?: optional($default)->default_purchase_price);

        return [
            'name'           => $product->name,
            'name_ar'        => $meta->name_ar ?? null,
            'description'    => $product->product_description,
            'description_ar' => $meta->description_ar ?? null,
            'media'          => $this->media($productId),
            'base_cost'      => round($baseCost, 2),
            'base_sell'      => round($baseSell, 2),
            'variants'       => $product->type === 'variable' ? $this->variants($product, $default, $meta) : [],
            'contents'       => $product->type === 'combo' ? $this->contents($businessId, $product) : [],
        ];
    }

    /** Media gallery rows shaped for the client (image/video/360). */
    public function media(int $productId): array
    {
        $svc = app(MediaServiceContract::class);
        return BmsProductMedia::where('product_id', $productId)->orderBy('sort_order')->get()
            ->map(fn ($m) => [
                'type'  => $m->type,
                'url'   => $m->url ?: $svc->url($m->disk, $m->path),
                'title' => $m->title,
            ])->values()->all();
    }

    /** Variations of a variable product as swap options (delta vs the default). */
    protected function variants(Product $product, $default, ?BmsProductMeta $meta): array
    {
        $baseSell = (float) optional($default)->sell_price_inc_tax;
        $labelsAr = $meta->variation_labels_ar ?? [];

        return $product->variations
            ->reject(fn ($v) => $default && $v->id === $default->id) // alternatives only; default is the base
            ->map(fn ($v) => [
                'variation_id' => $v->id,
                'label'        => trim(($product->name === $v->name ? '' : $v->name)) ?: $v->name,
                'label_ar'     => $labelsAr[$v->id] ?? null,
                'price_delta'  => round((float) $v->sell_price_inc_tax - $baseSell, 2),
            ])->values()->all();
    }

    /** Combo components as localized, quantified buffet contents. */
    protected function contents(int $businessId, Product $combo): array
    {
        $cv = optional($combo->variations->first())->combo_variations ?? [];
        if (empty($cv)) {
            return [];
        }
        $varIds = array_values(array_filter(array_map(fn ($r) => (int) ($r['variation_id'] ?? 0), $cv)));
        $vars = Variation::whereIn('id', $varIds)->with('product:id,name')->get()->keyBy('id');
        $metas = BmsProductMeta::whereIn('product_id', $vars->pluck('product_id')->filter()->unique())
            ->get()->keyBy('product_id');

        $out = [];
        foreach ($cv as $row) {
            $v = $vars->get((int) ($row['variation_id'] ?? 0));
            if (! $v) {
                continue;
            }
            $pm = $metas->get($v->product_id);
            $out[] = [
                'name'     => optional($v->product)->name ?? '—',
                'name_ar'  => $pm->name_ar ?? null,
                'quantity' => (float) ($row['quantity'] ?? 1),
                'unit'     => $pm->addon_unit ?? null,
                'unit_ar'  => $pm->default_unit_ar ?? null,
            ];
        }
        return $out;
    }
}
