<?php

namespace Modules\ProductCompat\Entities\Services;

use App\Product;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Modules\ProductCompat\Entities\PcChangeReport;
use Modules\ProductCompat\Entities\PcSearchQueue;

/**
 * Parse / enrichment coverage metrics for the catalogue — shared by the
 * productcompat:coverage command and the Control Panel UI so both show the same
 * numbers.
 */
class CoverageReport
{
    /**
     * @return array{
     *   total:int, parseable:int, parsed:int, unparsed:int, with_parts:int,
     *   queue:array{queued:int,processing:int,done:int,failed:int}
     * }
     */
    public static function gather(?int $businessId = null): array
    {
        $fields = config('productcompat.parse_fields', []);
        $scope = fn ($q) => $businessId ? $q->where('business_id', $businessId) : $q;

        $total = $scope(Product::query())->count();

        // Parseable = has non-empty data in any configured custom field.
        $parseable = fn () => $scope(Product::query())->where(function ($w) use ($fields) {
            foreach ($fields as $f) {
                $w->orWhere($f, '!=', '');
            }
        });
        $parseableCount = (clone $parseable())->count();

        $parsedIds = PcChangeReport::where('action', 'parse')
            ->when($businessId, fn ($q) => $q->where('business_id', $businessId))
            ->distinct()->pluck('product_id')->all();

        $parsed   = (clone $parseable())->whereIn('id', $parsedIds)->count();
        $unparsed = (clone $parseable())->whereNotIn('id', $parsedIds)->count();

        $withParts = $scope(Product::query())->whereExists(fn ($s) => $s->select(DB::raw(1))
            ->from('pc_part_numbers')->whereColumn('pc_part_numbers.product_id', 'products.id'))->count();

        $queue = ['queued' => 0, 'processing' => 0, 'done' => 0, 'failed' => 0];
        if (Schema::hasTable('pc_search_queue')) {
            $counts = PcSearchQueue::when($businessId, fn ($q) => $q->where('business_id', $businessId))
                ->select('status', DB::raw('COUNT(*) as c'))->groupBy('status')->pluck('c', 'status')->toArray();
            foreach ($queue as $k => $_) {
                $queue[$k] = (int) ($counts[$k] ?? 0);
            }
        }

        return [
            'total'      => $total,
            'parseable'  => $parseableCount,
            'parsed'     => $parsed,
            'unparsed'   => $unparsed,
            'with_parts' => $withParts,
            'queue'      => $queue,
        ];
    }

    /** First N SKUs of parseable products not yet parsed. */
    public static function unparsedSkus(?int $businessId, int $limit = 20): array
    {
        $fields = config('productcompat.parse_fields', []);
        $parsedIds = PcChangeReport::where('action', 'parse')
            ->when($businessId, fn ($q) => $q->where('business_id', $businessId))
            ->distinct()->pluck('product_id')->all();

        return Product::when($businessId, fn ($q) => $q->where('business_id', $businessId))
            ->where(function ($w) use ($fields) {
                foreach ($fields as $f) {
                    $w->orWhere($f, '!=', '');
                }
            })
            ->whereNotIn('id', $parsedIds)
            ->orderBy('id')->limit($limit)->pluck('sku')->all();
    }
}
