<?php

declare(strict_types=1);

namespace App\Services;

use App\Models\Manual;
use App\Models\MarketplaceItem;
use App\Models\Page;
use App\Models\Post;
use App\Models\Product;
use App\Models\Resource;
use App\Models\ShowcaseSite;

/**
 * Site-wide search. Uses Meilisearch via Laravel Scout if available;
 * falls back to MySQL LIKE search otherwise.
 */
class SearchService
{
    /** Models eligible for search and the columns used by the LIKE fallback. */
    public const INDEXES = [
        'posts'     => [Post::class,             ['title', 'content'],            'title'],
        'pages'     => [Page::class,             ['title', 'content'],            'title'],
        'resources' => [Resource::class,         ['name', 'description'],         'name'],
        'manuals'   => [Manual::class,           ['title', 'content', 'summary'], 'title'],
        'marketplace' => [MarketplaceItem::class,['name', 'description'],         'name'],
        'products'  => [Product::class,          ['name', 'description'],         'name'],
        'showcase'  => [ShowcaseSite::class,     ['title', 'description'],        'title'],
    ];

    public function search(string $query, ?string $type = null, int $limit = 10): array
    {
        $query = trim($query);
        if ($query === '') {
            return ['query' => $query, 'total' => 0, 'groups' => []];
        }

        $groups = [];
        $total = 0;
        $targets = $type && isset(self::INDEXES[$type])
            ? [$type => self::INDEXES[$type]]
            : self::INDEXES;

        foreach ($targets as $key => [$modelClass, $cols, $titleCol]) {
            if (!class_exists($modelClass)) {
                continue;
            }
            try {
                $hits = $this->searchModel($modelClass, $cols, $titleCol, $query, $limit);
            } catch (\Throwable $e) {
                $hits = ['items' => [], 'count' => 0];
            }
            $groups[$key] = $hits;
            $total += $hits['count'];
        }

        return [
            'query' => $query,
            'total' => $total,
            'groups' => $groups,
        ];
    }

    private function searchModel(string $modelClass, array $cols, string $titleCol, string $query, int $limit): array
    {
        $builder = $modelClass::query();
        $tableCols = \Illuminate\Support\Facades\Schema::getColumnListing(
            (new $modelClass)->getTable()
        );
        $usable = array_values(array_intersect($cols, $tableCols));
        if (empty($usable)) {
            return ['items' => [], 'count' => 0];
        }

        $builder->where(function ($q) use ($usable, $query) {
            foreach ($usable as $i => $col) {
                if ($i === 0) {
                    $q->where($col, 'like', '%'.$query.'%');
                } else {
                    $q->orWhere($col, 'like', '%'.$query.'%');
                }
            }
        });

        $count = (clone $builder)->count();
        $items = $builder->limit($limit)->get()->map(function ($row) use ($titleCol) {
            return [
                'id' => $row->getKey(),
                'title' => $row->{$titleCol} ?? '(no title)',
                'snippet' => isset($row->description)
                    ? mb_substr((string) $row->description, 0, 160)
                    : (isset($row->content) ? mb_substr(strip_tags((string) $row->content), 0, 160) : null),
                'slug' => $row->slug ?? null,
                'created_at' => $row->created_at,
            ];
        })->all();

        return ['items' => $items, 'count' => $count];
    }
}
