<?php

declare(strict_types=1);

namespace App\Services\AiAssistant;

use App\Services\AiAssistant\Tools\CategoryTools;
use App\Services\AiAssistant\Tools\DealTools;
use App\Services\AiAssistant\Tools\ProductTools;
use App\Services\AiAssistant\Tools\RecommendationTools;
use Prism\Prism\Facades\Tool;
use Prism\Prism\Schema\NumberSchema;
use Prism\Prism\Tool as BaseTool;

class ToolManager
{
    protected array $tools = [];

    public function __construct(
        protected ProductTools $productTools,
        protected CategoryTools $categoryTools,
        protected DealTools $dealTools,
        protected RecommendationTools $recommendationTools,
    ) {
        $this->registerTools();
    }

    protected function registerTools(): void
    {
        $this->tools = [
            $this->searchProductsTool(),
            $this->getProductDetailsTool(),
            $this->compareProductsTool(),
            $this->findDealsTool(),
            $this->getRecommendationsTool(),
            $this->getCategoriesTool(),
            $this->getCategoryProductsTool(),
        ];
    }

    /**
     * @return array<BaseTool>
     */
    public function getAvailableTools(): array
    {
        return $this->tools;
    }

    protected function searchProductsTool(): BaseTool
    {
        return Tool::as('search_products')
            ->for('Search for products by name, category, price range, or other criteria')
            ->withStringParameter('query', 'Search query for products (e.g., "laptop", "gaming mouse")', required: true)
            ->withNumberParameter('category_id', 'Filter by category ID', required: false)
            ->withNumberParameter('min_price', 'Minimum price', required: false)
            ->withNumberParameter('max_price', 'Maximum price', required: false)
            ->withNumberParameter('limit', 'Maximum number of results (default: 10)', required: false)
            ->using(fn (string $query, ?int $category_id = null, ?float $min_price = null, ?float $max_price = null, ?int $limit = 10): string => $this->productTools->search(compact('query', 'category_id', 'min_price', 'max_price', 'limit'))
            );
    }

    protected function getProductDetailsTool(): BaseTool
    {
        return Tool::as('get_product_details')
            ->for('Get detailed information about a specific product')
            ->withNumberParameter('product_id', 'The product ID to get details for', required: true)
            ->using(fn (int $product_id): string => $this->productTools->getDetails($product_id)
            );
    }

    protected function compareProductsTool(): BaseTool
    {
        return Tool::as('compare_products')
            ->for('Compare multiple products across features, price, ratings, and value')
            ->withArrayParameter('product_ids', 'Array of product IDs to compare (e.g., [1, 2, 3])', new NumberSchema('product_id', 'A product ID'))
            ->using(fn (array $product_ids): string => $this->productTools->compare($product_ids)
            );
    }

    protected function findDealsTool(): BaseTool
    {
        return Tool::as('find_deals')
            ->for('Find the best deals, discounts, and promotions')
            ->withStringParameter('type', 'Type of deals: "best", "flash", "coupon", or "value"', required: false)
            ->withNumberParameter('category_id', 'Filter deals by category ID', required: false)
            ->withNumberParameter('limit', 'Maximum number of results (default: 10)', required: false)
            ->using(fn (string $type = 'best', ?int $category_id = null, ?int $limit = 10): string => $this->dealTools->find($type, $category_id, $limit)
            );
    }

    protected function getRecommendationsTool(): BaseTool
    {
        return Tool::as('get_recommendations')
            ->for('Get product recommendations based on criteria')
            ->withStringParameter('type', 'Type of recommendations: "trending", "similar" (requires product_id), or "personalized" (requires user_id)', required: true)
            ->withNumberParameter('product_id', 'Product ID for "similar" recommendations', required: false)
            ->withNumberParameter('category_id', 'Category ID for category-based recommendations', required: false)
            ->withNumberParameter('limit', 'Maximum number of results (default: 10)', required: false)
            ->using(fn (string $type, ?int $product_id = null, ?int $category_id = null, ?int $limit = 10): string => $this->recommendationTools->get($type, $product_id, $category_id, $limit)
            );
    }

    protected function getCategoriesTool(): BaseTool
    {
        return Tool::as('get_categories')
            ->for('List all available product categories')
            ->withStringParameter('search', 'Optional search term to filter categories (leave empty for all)', required: false)
            ->using(fn (string $search = ''): string => $this->categoryTools->list($search)
            );
    }

    protected function getCategoryProductsTool(): BaseTool
    {
        return Tool::as('get_category_products')
            ->for('Get products in a specific category')
            ->withNumberParameter('category_id', 'The category ID to get products from', required: true)
            ->withStringParameter('sort', 'Sort order: "best_selling", "top_rated", "price_low", "price_high", "most_viewed"', required: false)
            ->withNumberParameter('limit', 'Maximum number of results (default: 10)', required: false)
            ->using(fn (int $category_id, string $sort = 'best_selling', ?int $limit = 10): string => $this->categoryTools->getProducts($category_id, $sort, $limit)
            );
    }
}
