<?php

namespace App\Services;

use App\Models\HealthInstitution;
use App\Models\DigitalMachine;
use Illuminate\Support\Collection;
use Illuminate\Pagination\LengthAwarePaginator;

/**
 * DirectorySearchService
 *
 * Provides search and filtering functionality for the health directory.
 * Used for real-time search on public pages.
 *
 * Requirements: 5.2, 5.3, 6.5
 */
class DirectorySearchService
{
    /**
     * Search health institutions.
     *
     * @param string $query Search term
     * @param array $filters Optional filters (city, country, services)
     * @param int $perPage Number of results per page
     * @return LengthAwarePaginator
     */
    public function searchInstitutions(string $query = '', array $filters = [], int $perPage = 15): LengthAwarePaginator
    {
        $query = (string) ($query ?? '');
        $institutions = HealthInstitution::query()
            ->published()
            ->when($query, function ($q) use ($query) {
                $q->search($query);
            })
            ->when($filters['city'] ?? null, function ($q, $city) {
                $q->byCity($city);
            })
            ->when($filters['country'] ?? null, function ($q, $country) {
                $q->byCountry($country);
            })
            ->when($filters['services'] ?? null, function ($q, $services) {
                if (is_array($services)) {
                    foreach ($services as $service) {
                        $q->whereJsonContains('services', $service);
                    }
                } else {
                    $q->whereJsonContains('services', $services);
                }
            })
            ->orderBy('name')
            ->paginate($perPage);

        return $institutions;
    }

    /**
     * Search digital machines.
     *
     * @param string $query Search term
     * @param array $filters Optional filters (category, brand, price_range)
     * @param int $perPage Number of results per page
     * @return LengthAwarePaginator
     */
    public function searchMachines(string $query = '', array $filters = [], int $perPage = 15): LengthAwarePaginator
    {
        $query = (string) ($query ?? '');
        $machines = DigitalMachine::query()
            ->published()
            ->when($query, function ($q) use ($query) {
                $q->search($query);
            })
            ->when($filters['category'] ?? null, function ($q, $category) {
                $q->byCategory($category);
            })
            ->when($filters['brand'] ?? null, function ($q, $brand) {
                $q->byBrand($brand);
            })
            ->when($filters['price_visible'] ?? null, function ($q) {
                $q->priceVisible();
            })
            ->when($filters['price_min'] ?? null, function ($q, $min) {
                $currency = $filters['currency'] ?? 'SSP';
                $column = $currency === 'USD' ? 'price_usd' : 'price_ssp';
                $q->where($column, '>=', $min);
            })
            ->when($filters['price_max'] ?? null, function ($q, $max) {
                $currency = $filters['currency'] ?? 'SSP';
                $column = $currency === 'USD' ? 'price_usd' : 'price_ssp';
                $q->where($column, '<=', $max);
            })
            ->latestPublished()
            ->paginate($perPage);

        return $machines;
    }

    /**
     * Get real-time search results (for AJAX/API calls).
     *
     * @param string $query Search term
     * @param string $type 'institutions', 'machines', or 'all'
     * @param int $limit Maximum results to return
     * @return array
     */
    public function realtimeSearch(string $query, string $type = 'all', int $limit = 10): array
    {
        $results = [
            'institutions' => [],
            'machines' => [],
        ];

        if (strlen($query) < 2) {
            return $results;
        }

        if ($type === 'all' || $type === 'institutions') {
            $results['institutions'] = HealthInstitution::query()
                ->published()
                ->search($query)
                ->limit($limit)
                ->get(['id', 'name', 'slug', 'city', 'logo', 'short_name'])
                ->map(function ($institution) {
                    return [
                        'id' => $institution->id,
                        'name' => $institution->name,
                        'short_name' => $institution->short_name,
                        'slug' => $institution->slug,
                        'city' => $institution->city,
                        'logo_url' => $institution->logo_url,
                        'url' => route('institutions.show', $institution->slug),
                        'type' => 'institution',
                    ];
                })
                ->toArray();
        }

        if ($type === 'all' || $type === 'machines') {
            $results['machines'] = DigitalMachine::query()
                ->published()
                ->search($query)
                ->limit($limit)
                ->get(['id', 'name', 'slug', 'brand', 'category', 'primary_image'])
                ->map(function ($machine) {
                    return [
                        'id' => $machine->id,
                        'name' => $machine->name,
                        'brand' => $machine->brand,
                        'category' => $machine->category,
                        'slug' => $machine->slug,
                        'image_url' => $machine->primary_image_url,
                        'url' => route('machines.show', $machine->slug),
                        'type' => 'machine',
                    ];
                })
                ->toArray();
        }

        return $results;
    }

    /**
     * Get published institutions with filtering.
     *
     * @param array $filters
     * @return LengthAwarePaginator
     */
    public function getPublishedInstitutions(array $filters = [], int $perPage = 15): LengthAwarePaginator
    {
        return $this->searchInstitutions('', $filters, $perPage);
    }

    /**
     * Get published machines with filtering.
     *
     * @param array $filters
     * @return LengthAwarePaginator
     */
    public function getPublishedMachines(array $filters = [], int $perPage = 15): LengthAwarePaginator
    {
        return $this->searchMachines('', $filters, $perPage);
    }

    /**
     * Get institutions by city.
     *
     * @param string $city
     * @param int $limit
     * @return Collection
     */
    public function getInstitutionsByCity(string $city, int $limit = 10): Collection
    {
        return HealthInstitution::query()
            ->published()
            ->byCity($city)
            ->limit($limit)
            ->get();
    }

    /**
     * Get institutions by country.
     *
     * @param string $country
     * @param int $limit
     * @return Collection
     */
    public function getInstitutionsByCountry(string $country, int $limit = 10): Collection
    {
        return HealthInstitution::query()
            ->published()
            ->byCountry($country)
            ->limit($limit)
            ->get();
    }

    /**
     * Get machines by category.
     *
     * @param string $category
     * @param int $limit
     * @return Collection
     */
    public function getMachinesByCategory(string $category, int $limit = 10): Collection
    {
        return DigitalMachine::query()
            ->published()
            ->byCategory($category)
            ->latestPublished()
            ->limit($limit)
            ->get();
    }

    /**
     * Get featured institutions (most viewed).
     *
     * @param int $limit
     * @return Collection
     */
    public function getFeaturedInstitutions(int $limit = 6): Collection
    {
        return HealthInstitution::query()
            ->published()
            ->orderBy('view_count', 'desc')
            ->limit($limit)
            ->get();
    }

    /**
     * Get featured machines (most viewed).
     *
     * @param int $limit
     * @return Collection
     */
    public function getFeaturedMachines(int $limit = 6): Collection
    {
        return DigitalMachine::query()
            ->published()
            ->orderBy('view_count', 'desc')
            ->limit($limit)
            ->get();
    }

    /**
     * Get latest institutions.
     *
     * @param int $limit
     * @return Collection
     */
    public function getLatestInstitutions(int $limit = 6): Collection
    {
        return HealthInstitution::query()
            ->published()
            ->latest('published_at')
            ->limit($limit)
            ->get();
    }

    /**
     * Get latest machines.
     *
     * @param int $limit
     * @return Collection
     */
    public function getLatestMachines(int $limit = 6): Collection
    {
        return DigitalMachine::query()
            ->published()
            ->latest('published_at')
            ->limit($limit)
            ->get();
    }

    /**
     * Get all cities with institution count.
     *
     * @return array
     */
    public function getCitiesWithCount(): array
    {
        return HealthInstitution::query()
            ->published()
            ->select('city')
            ->selectRaw('COUNT(*) as count')
            ->groupBy('city')
            ->orderBy('count', 'desc')
            ->pluck('count', 'city')
            ->toArray();
    }

    /**
     * Get all categories with machine count.
     *
     * @return array
     */
    public function getCategoriesWithCount(): array
    {
        return DigitalMachine::query()
            ->published()
            ->select('category')
            ->selectRaw('COUNT(*) as count')
            ->whereNotNull('category')
            ->groupBy('category')
            ->orderBy('count', 'desc')
            ->pluck('count', 'category')
            ->toArray();
    }

    /**
     * Get all services with institution count.
     *
     * @return array
     */
    public function getServicesWithCount(): array
    {
        $institutions = HealthInstitution::query()
            ->published()
            ->whereNotNull('services')
            ->get(['services']);

        $services = [];

        foreach ($institutions as $institution) {
            if (is_array($institution->services)) {
                foreach ($institution->services as $service) {
                    $services[$service] = ($services[$service] ?? 0) + 1;
                }
            }
        }

        arsort($services);

        return $services;
    }

    /**
     * Get all brands with machine count.
     *
     * @return array
     */
    public function getBrandsWithCount(): array
    {
        return DigitalMachine::query()
            ->published()
            ->select('brand')
            ->selectRaw('COUNT(*) as count')
            ->whereNotNull('brand')
            ->groupBy('brand')
            ->orderBy('count', 'desc')
            ->pluck('count', 'brand')
            ->toArray();
    }
}
