<?php

namespace Modules\ActivityLog\Entities\Services;

use Illuminate\Support\Facades\DB;

/**
 * Flattens a public share link's `products_data` JSON into the searchable
 * `shared_product_items` table, resolving each SKU to its product, category
 * and sub-category so the Activity Log can filter share links by product
 * name, SKU, or category.
 *
 * The operation is idempotent: existing rows for a share are replaced.
 */
class SharedLinkIndexer
{
    /**
     * Index a single share link.
     *
     * @param  int          $sharedProductId  shared_products.id
     * @param  int|null     $businessId       shared_products.business_id
     * @param  array|string $productsData     decoded array or raw JSON string
     * @return int                            number of item rows written
     */
    public function index(int $sharedProductId, ?int $businessId, $productsData): int
    {
        $items = $this->normalize($productsData);

        // Idempotent: clear any previous index for this share first.
        DB::table('shared_product_items')->where('shared_product_id', $sharedProductId)->delete();

        if (empty($items)) {
            return 0;
        }

        $productsBySku = $this->resolveProductsBySku($items, $businessId);

        $rows = [];
        foreach ($items as $item) {
            $sku     = $item['sku'] ?? null;
            $product = ($sku !== null && $sku !== '') ? ($productsBySku[$sku] ?? null) : null;

            $name = $item['name'] ?? ($product->name ?? null);

            $rows[] = [
                'shared_product_id' => $sharedProductId,
                'business_id'       => $businessId,
                'product_id'        => $product->id ?? null,
                'sku'               => $sku !== null ? mb_substr((string) $sku, 0, 191) : null,
                'product_name'      => $name !== null ? mb_substr((string) $name, 0, 255) : null,
                'category_id'       => $product->category_id ?? null,
                'sub_category_id'   => $product->sub_category_id ?? null,
            ];
        }

        DB::table('shared_product_items')->insert($rows);

        return count($rows);
    }

    /**
     * Batch-load products for the SKUs found in a share, scoped to the
     * business when known. Avoids N+1 lookups during backfill.
     */
    protected function resolveProductsBySku(array $items, ?int $businessId): array
    {
        $skus = [];
        foreach ($items as $item) {
            $sku = $item['sku'] ?? null;
            if ($sku !== null && $sku !== '') {
                $skus[(string) $sku] = true;
            }
        }

        if (empty($skus)) {
            return [];
        }

        $query = DB::table('products')
            ->whereIn('sku', array_keys($skus))
            ->select('id', 'sku', 'name', 'category_id', 'sub_category_id');

        if ($businessId) {
            $query->where('business_id', $businessId);
        }

        $bySku = [];
        foreach ($query->get() as $product) {
            // Keep the first match per SKU (SKUs are unique within a business).
            $bySku[$product->sku] ??= $product;
        }

        return $bySku;
    }

    /**
     * Coerce products_data into a list of ['sku' => ?, 'name' => ?] entries.
     */
    protected function normalize($productsData): array
    {
        if (is_string($productsData)) {
            $productsData = json_decode($productsData, true);
        }

        if (!is_array($productsData)) {
            return [];
        }

        $out = [];
        foreach ($productsData as $row) {
            if (!is_array($row)) {
                continue;
            }
            $out[] = [
                'sku'  => $row['sku']  ?? null,
                'name' => $row['name'] ?? null,
            ];
        }

        return $out;
    }
}
