<?php

namespace App\Services;

use App\Models\CategoryServiceOverride;
use App\Models\ProductServiceLink;
use App\Models\Service;
use Illuminate\Support\Collection;

class ServicePriceResolver
{
    /**
     * Resolve the effective price for a single service on a product.
     *
     * Priority:
     *  1. ProductServiceLinks.override_price (not null)
     *  2. CategoryServiceOverrides.override_price (walking category hierarchy)
     *  3. Services.default_price
     *
     * @return decimal|null
     */
    public function calculateServicePrice(int $productId, int $serviceId): ?string
    {
        $link = ProductServiceLink::where('product_id', $productId)
            ->where('service_id', $serviceId)
            ->where('is_enabled', true)
            ->first();

        if ($link) {
            if (! is_null($link->override_price)) {
                return number_format($link->override_price, 2, '.', '');
            }
        }

        $product = \App\Models\Product::find($productId);
        if (! $product) {
            return null;
        }

        $categoryOverride = $this->findCategoryOverride($product->category_id, $serviceId);
        if ($categoryOverride) {
            if (! is_null($categoryOverride->override_price)) {
                return number_format($categoryOverride->override_price, 2, '.', '');
            }
            $service = Service::find($serviceId);
            if ($service) {
                return number_format($service->default_price, 2, '.', '');
            }
            return null;
        }

        $service = Service::find($serviceId);
        if ($service) {
            return number_format($service->default_price, 2, '.', '');
        }

        return null;
    }

    /**
     * Get all applicable services for a product with their resolved prices.
     *
     * Includes:
     *  - Services linked directly to the product (ProductServiceLink)
     *  - Services assigned to the product's category (CategoryServiceOverride)
     *
     * Product-level links take precedence over category-level links.
     *
     * @return Collection<int, array{service: Service, resolved_price: string}>
     */
    public function resolveServicesForProduct(int $productId): Collection
    {
        $product = \App\Models\Product::find($productId);
        if (! $product) {
            return collect();
        }

        $productLinks = ProductServiceLink::where('product_id', $productId)
            ->where('is_enabled', true)
            ->with('service')
            ->get();

        $productServiceIds = $productLinks->pluck('service_id')->filter()->unique();

        $categoryOverrides = CategoryServiceOverride::where('category_id', $product->category_id)
            ->whereHas('service', fn ($q) => $q->where('is_active', true))
            ->with('service')
            ->get();

        $categoryServiceIds = $categoryOverrides
            ->pluck('service_id')
            ->filter()
            ->unique()
            ->diff($productServiceIds);

        $categoryServices = Service::whereIn('id', $categoryServiceIds)
            ->where('is_active', true)
            ->get();

        $all = $productLinks
            ->map(fn ($link) => $link->service)
            ->merge($categoryServices)
            ->unique('id')
            ->values()
            ->map(function ($service) use ($productId) {
                $resolvedPrice = $this->calculateServicePrice($productId, $service->id);

                return [
                    'service' => $service,
                    'resolved_price' => $resolvedPrice,
                ];
            })
            ->filter(fn ($item) => $item['resolved_price'] !== null);

        return $all;
    }

    /**
     * Walk up the category hierarchy to find the nearest override.
     *
     * Note: The current categories table does not have a parent_id column.
     * When hierarchical categories are added, uncomment the recursive walk below.
     */
    private function findCategoryOverride(int $categoryId, int $serviceId): ?CategoryServiceOverride
    {
        $override = CategoryServiceOverride::where('category_id', $categoryId)
            ->where('service_id', $serviceId)
            ->first();

        if ($override) {
            return $override;
        }

        // Uncomment when categories gain a parent_id column:
        // $category = \App\Models\Category::find($categoryId);
        // if ($category && !is_null($category->parent_id ?? null)) {
        //     return $this->findCategoryOverride($category->parent_id, $serviceId);
        // }

        return null;
    }
}
