import os
import httpx
import json
import time
from mcp.server.fastmcp import FastMCP
from typing import List, Optional, Dict, Any, Union
from datetime import datetime
from zoneinfo import ZoneInfo

# Инициализация MCP-сервера
mcp = FastMCP(
    "DWH-Server",
    description="Сервер для получения аналитики по маркетплейсам",
    host="0.0.0.0",
    port=8000,
)

# BASE_URL="http://127.0.0.1:43761/api/v1"
BASE_URL = os.getenv("BASE_URL")
if not BASE_URL:
    raise ValueError("BASE_URL env variable is required")


def period_to_timestamp(period: str) -> int:
    year, month = map(int, period.split("-"))
    dt = datetime(year, month, 1, tzinfo=ZoneInfo("Europe/Moscow"))
    return int(dt.timestamp())


@mcp.tool(name="get_product_list", description="""
    Получает список продуктов по различным параметрам.
    Можно использовать чтобы узнать топ товаров по какой-то метрике. Узнать данные о продажа/выручке/отзывах для товаров за период.
    Фильтрация идет по данным на дату последнего наблюдения, кроме продаж, выручки и отзывов - они показываются за период.
    Используй ТОЛЬКО аргументы перечисленные ниже. По умолчанию, всегда пробуй сократить количество запрашиваемых полей с помощью фильтрации fields, перечисляй то что нужно для запроса. В этой функции период можно выбрать ТОЛЬКО через аргумент "period", временные интервалы через другие параметры указывать нельзя!
    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
        id: Список ID продуктов через запятую
        after: Вернуть следующие элементы после заданного
        limit: Вернуть заданное число элементов
        category_id: Список ID категорий через запятую
        brand_id: Список ID брендов через запятую
        merchant_id: Список ID магазинов через запятую
        sort: Параметр сортировки. Возможные значения:
            - created_asc/created_desc: По дате создания товара
            - added_asc/added_desc: По дате добавления товара
            - observed_asc/observed_desc: По дате последнего наблюдения товара
            - deleted_asc/deleted_desc: По дате удаления товара
            - rate_asc/rate_desc: По рейтингу товара
            - discount_asc/discount_desc: По скидке
            - discount_min_asc/discount_min_desc: По минимальной скидке
            - discount_avg_asc/discount_avg_desc: По средней скидке
            - discount_max_asc/discount_max_desc: По максимальной скидке
            - msrp_min_asc/msrp_min_desc: По минимальной рекомендованной цене
            - msrp_avg_asc/msrp_avg_desc: По средней рекомендованной цене
            - msrp_max_asc/msrp_max_desc: По максимальной рекомендованной цене
            - price_min_asc/price_min_desc: По минимальной цене
            - price_avg_asc/price_avg_desc: По средней цене
            - price_max_asc/price_max_desc: По максимальной цене
            - review_asc/review_desc: По количеству отзывов
            - review_first_asc/review_first_desc: По дате первого отзыва
            - review_last_asc/review_last_desc: По дате последнего отзыва
            - mall_reviews_asc/mall_reviews_desc: По количеству отзывов на маркетплейсе
            - sales_grow_asc/sales_grow_desc: По продажам (штуки) за период
            - gmv_grow_asc/gmv_grow_desc: По выручке за период
            - id_asc/id_desc: По ID
            - inventory_asc/inventory_desc: По остаткам
            - inventory_sum_asc/inventory_sum_desc: По сумме остатков
            - inventory_count_asc/inventory_count_desc: По количеству остатков
            - inventory_min_asc/inventory_min_desc: По минимальному остатку
            - inventory_max_asc/inventory_max_desc: По максимальному остатку
            - rating_count_asc/rating_count_desc: По количеству оценок
            - sold_orders_percent_asc/sold_orders_percent_desc: По проценту проданных заказов
        name: Поиск по названию (дословный по вхождению фразы в название товара)
        url: Список URL через запятую
        added_from: Минимальное время добавления (timestamp)
        added_to: Максимальное время добавления (timestamp)
        observed_from: Минимальное время наблюдения (timestamp)
        observed_to: Максимальное время наблюдения (timestamp)
        price_min_from: Минимальная цена от
        price_min_to: Минимальная цена до
        price_avg_from: Средняя цена от
        price_avg_to: Средняя цена до
        price_max_from: Максимальная цена от
        price_max_to: Максимальная цена до
        rate_from: Рейтинг от
        rate_to: Рейтинг до
        sales_from: Продажи от
        sales_to: Продажи до
        gmv_from: GMV от
        gmv_to: GMV до
        review_from: Отзывы от
        review_to: Отзывы до
        inventory_from: Остаток от
        inventory_to: Остаток до
        status: Список статусов через запятую. Возможные значения: available, deleted, archived, outstocked
        inventory_type: Список типов инвентаря через запятую. Возможные значения: 1 (FBS - Fulfillment by Seller), 2 (FBO - Fulfillment by Operator)
        created_from: Время создания карточки товара на площадке от (timestamp)
        created_to: Время создания карточки товара на площадке до (timestamp)
        review_first_from: Время первого отзыва по товару от (timestamp)
        review_first_to: Время первого отзыва по товару до (timestamp)
        review_last_from: Время последнего отзыва от (timestamp)
        review_last_to: Время последнего отзыва до (timestamp)
        count_words_name_from: Количество слов в названии от
        count_words_name_to: Количество слов в названии до
        count_words_desc_from: Количество слов в описании от
        count_words_desc_to: Количество слов в описании до
        count_images_from: Количество изображений от
        count_images_to: Количество изображений до
        count_videos_from: Количество видео от
        count_videos_to: Количество видео до
        count_characteristics_from: Количество характеристик от
        count_characteristics_to: Количество характеристик до
        deleted_from: Время удаления от (timestamp)
        deleted_to: Время удаления до (timestamp)
        after_id: ID для пагинации (используется вместе с sort_values)
        period: Период данных о продажах и отзывах за период, можно передать "last_month", "last_year" или месяц в формате "YYYY-MM" (например "2024-02") - обязательный
        link: Список ссылок через запятую
        sort_values: Значения сортировки для пагинации, полученные от предыдущего запроса. Используется вместе с after_id
        subject_id: Список ID предметов через запятую
        country: Список стран через запятую
        rating_count_from: Количество оценок от
        rating_count_to: Количество оценок до
        tag_id: Список ID тегов через запятую
        sold_orders_percent_from: Процент проданных заказов от
        sold_orders_percent_to: Процент проданных заказов до
        characteristic_country: Страна производства
        characteristic_color: Цвет
        characteristic_volume_min: Минимальный объем
        characteristic_volume_max: Максимальный объем
        characteristic_quantity_min: Минимальное количество
        characteristic_quantity_max: Максимальное количество
        characteristic_weight_min: Минимальный вес
        characteristic_weight_max: Максимальный вес
        ts: Это поле для фильтра "fields". Возвращает массив с временными отметками к товарам, которые позволяют понять когда он был создан, добавлен в парсинг, обновлен, изменен, когда его последний раз пронаблюдали и с какого числа он доступен к заказу (т.е. если сейчас можно заказать то с какого числа он в таком состоянии)
            Пример ответа для ts:{"updated": 1745774586, "created": 1694625915, "added": 1694625915, "changed": 1745774586, "observed": 1745774586, "available": 1726642622}
        fields: перечень полей, которые нужно оставить в ответе. Допустимые поля: id, link, url, name, ts, rate, ratingCount, brandId, brand, code, reviews, review, question, order, gmv, sales, images, videos, inventory, inventoryTypes, price, msrp, discount, merchants, merchantsCount, categories, subjects, countWordsName, countWordsDesc, countImages, countVideos, countCharacteristics, characteristicsNormalized, pts, soldOrdersPercent. При указании вложенных объектов (например, sales или gmv) передавайте имя верхнего объекта. Частичный выбор вложенных полей (например, только sales.total) не поддерживается: будет возвращён весь объект sales. Примеры: fields=["name", "sales"]
            fields=["name", "gmv", "sales"]
    """)
def get_product_list(
        mall: str,
        period: str,
        id: Optional[str] = None,
        after: int = 0,
        limit: int = 10,
        category_id: Optional[str] = None,
        brand_id: Optional[str] = None,
        merchant_id: Optional[str] = None,
        sort: Optional[str] = None,
        name: Optional[str] = None,
        url: Optional[str] = None,
        added_from: Optional[int] = None,
        added_to: Optional[int] = None,
        observed_from: Optional[int] = None,
        observed_to: Optional[int] = None,
        price_min_from: Optional[float] = None,
        price_min_to: Optional[float] = None,
        price_avg_from: Optional[float] = None,
        price_avg_to: Optional[float] = None,
        price_max_from: Optional[float] = None,
        price_max_to: Optional[float] = None,
        rate_from: Optional[float] = None,
        rate_to: Optional[float] = None,
        sales_from: Optional[int] = None,
        sales_to: Optional[int] = None,
        gmv_from: Optional[float] = None,
        gmv_to: Optional[float] = None,
        review_from: Optional[int] = None,
        review_to: Optional[int] = None,
        inventory_from: Optional[int] = None,
        inventory_to: Optional[int] = None,
        status: Optional[str] = None,
        inventory_type: Optional[str] = None,
        created_from: Optional[int] = None,
        created_to: Optional[int] = None,
        review_first_from: Optional[int] = None,
        review_first_to: Optional[int] = None,
        review_last_from: Optional[int] = None,
        review_last_to: Optional[int] = None,
        count_words_name_from: Optional[int] = None,
        count_words_name_to: Optional[int] = None,
        count_words_desc_from: Optional[int] = None,
        count_words_desc_to: Optional[int] = None,
        count_images_from: Optional[int] = None,
        count_images_to: Optional[int] = None,
        count_videos_from: Optional[int] = None,
        count_videos_to: Optional[int] = None,
        count_characteristics_from: Optional[int] = None,
        count_characteristics_to: Optional[int] = None,
        available_from: Optional[int] = None,
        available_to: Optional[int] = None,
        outstocked_from: Optional[int] = None,
        outstocked_to: Optional[int] = None,
        deleted_from: Optional[int] = None,
        deleted_to: Optional[int] = None,
        after_id: Optional[str] = None,
        link: Optional[str] = None,
        sort_values: Optional[str] = None,
        subject_id: Optional[str] = None,
        country: Optional[str] = None,
        rating_count_from: Optional[int] = None,
        rating_count_to: Optional[int] = None,
        tag_id: Optional[str] = None,
        sold_orders_percent_from: Optional[int] = None,
        sold_orders_percent_to: Optional[int] = None,
        characteristic_country: Optional[str] = None,
        characteristic_color: Optional[str] = None,
        characteristic_volume_min: Optional[int] = None,
        characteristic_volume_max: Optional[int] = None,
        characteristic_quantity_min: Optional[int] = None,
        characteristic_quantity_max: Optional[int] = None,
        characteristic_weight_min: Optional[int] = None,
        characteristic_weight_max: Optional[int] = None,
        fields: Optional[List[str]] = None
) -> dict:
    # if kwargs:
    #     return {
    #         "error": f"Unexpected parameters: {', '.join(kwargs.keys())}"
    #     }

    data = {"mall": mall, "after": after, "limit": limit}

    if id is not None:
        data["id"] = [int(x) for x in id.split(",")]
    if category_id is not None:
        data["categoryId"] = [int(x) for x in category_id.split(",")]
    if brand_id is not None:
        data["brandId"] = [int(x) for x in brand_id.split(",")]
    if merchant_id is not None:
        data["merchantId"] = [int(x) for x in merchant_id.split(",")]
    if sort is not None:
        data["sort"] = sort
    if name is not None:
        data["name"] = name
    if url is not None:
        data["url"] = url.split(",")
    if added_from is not None:
        data["addedFrom"] = added_from
    if added_to is not None:
        data["addedTo"] = added_to
    if observed_from is not None:
        data["observedFrom"] = observed_from
    if observed_to is not None:
        data["observedTo"] = observed_to
    if price_min_from is not None:
        data["priceMinFrom"] = price_min_from
    if price_min_to is not None:
        data["priceMinTo"] = price_min_to
    if price_avg_from is not None:
        data["priceAvgFrom"] = price_avg_from
    if price_avg_to is not None:
        data["priceAvgTo"] = price_avg_to
    if price_max_from is not None:
        data["priceMaxFrom"] = price_max_from
    if price_max_to is not None:
        data["priceMaxTo"] = price_max_to
    if rate_from is not None:
        data["rateFrom"] = rate_from
    if rate_to is not None:
        data["rateTo"] = rate_to
    if sales_from is not None:
        data["salesFrom"] = sales_from
    if sales_to is not None:
        data["salesTo"] = sales_to
    if gmv_from is not None:
        data["gmvFrom"] = gmv_from
    if gmv_to is not None:
        data["gmvTo"] = gmv_to
    if review_from is not None:
        data["reviewFrom"] = review_from
    if review_to is not None:
        data["reviewTo"] = review_to
    if inventory_from is not None:
        data["inventoryFrom"] = inventory_from
    if inventory_to is not None:
        data["inventoryTo"] = inventory_to
    if status is not None:
        data["status"] = status.split(",")
    if inventory_type is not None:
        data["inventoryType"] = [int(x) for x in inventory_type.split(",")]
    if created_from is not None:
        data["createdFrom"] = created_from
    if created_to is not None:
        data["createdTo"] = created_to
    if review_first_from is not None:
        data["reviewFirstFrom"] = review_first_from
    if review_first_to is not None:
        data["reviewFirstTo"] = review_first_to
    if review_last_from is not None:
        data["reviewLastFrom"] = review_last_from
    if review_last_to is not None:
        data["reviewLastTo"] = review_last_to
    if count_words_name_from is not None:
        data["countWordsNameFrom"] = count_words_name_from
    if count_words_name_to is not None:
        data["countWordsNameTo"] = count_words_name_to
    if count_words_desc_from is not None:
        data["countWordsDescFrom"] = count_words_desc_from
    if count_words_desc_to is not None:
        data["countWordsDescTo"] = count_words_desc_to
    if count_images_from is not None:
        data["countImagesFrom"] = count_images_from
    if count_images_to is not None:
        data["countImagesTo"] = count_images_to
    if count_videos_from is not None:
        data["countVideosFrom"] = count_videos_from
    if count_videos_to is not None:
        data["countVideosTo"] = count_videos_to
    if count_characteristics_from is not None:
        data["countCharacteristicsFrom"] = count_characteristics_from
    if count_characteristics_to is not None:
        data["countCharacteristicsTo"] = count_characteristics_to
    if available_from is not None:
        data["availableFrom"] = available_from
    if available_to is not None:
        data["availableTo"] = available_to
    if outstocked_from is not None:
        data["outstockedFrom"] = outstocked_from
    if outstocked_to is not None:
        data["outstockedTo"] = outstocked_to
    if deleted_from is not None:
        data["deletedFrom"] = deleted_from
    if deleted_to is not None:
        data["deletedTo"] = deleted_to
    if after_id is not None:
        data["afterId"] = after_id
    if period is not None:
        if period == "last_month":
            data["periodNumber"] = 1
            data["periodMeasure"] = "M"
            data["periodType"] = "grow"
        elif period == "last_year":
            data["periodNumber"] = 1
            data["periodMeasure"] = "Y"
            data["periodType"] = "grow"
        else:
            data["periodNumber"] = period_to_timestamp(period)
            data["periodMeasure"] = "M"
            data["periodType"] = "calendar"
    if link is not None:
        data["link"] = link.split(",")
    if sort_values is not None:
        data["sortValues"] = sort_values
    if subject_id is not None:
        data["subjectId"] = [int(x) for x in subject_id.split(",")]
    if country is not None:
        data["country"] = country.split(",")
    if rating_count_from is not None:
        data["ratingCountFrom"] = rating_count_from
    if rating_count_to is not None:
        data["ratingCountTo"] = rating_count_to
    if tag_id is not None:
        data["tagId"] = [int(x) for x in tag_id.split(",")]
    if sold_orders_percent_from is not None:
        data["soldOrdersPercentFrom"] = sold_orders_percent_from
    if sold_orders_percent_to is not None:
        data["soldOrdersPercentTo"] = sold_orders_percent_to
    if characteristic_country is not None:
        data["characteristicCountry"] = characteristic_country
    if characteristic_color is not None:
        data["characteristicColor"] = characteristic_color
    if characteristic_volume_min is not None:
        data["characteristicVolumeMin"] = characteristic_volume_min
    if characteristic_volume_max is not None:
        data["characteristicVolumeMax"] = characteristic_volume_max
    if characteristic_quantity_min is not None:
        data["characteristicQuantityMin"] = characteristic_quantity_min
    if characteristic_quantity_max is not None:
        data["characteristicQuantityMax"] = characteristic_quantity_max
    if characteristic_weight_min is not None:
        data["characteristicWeightMin"] = characteristic_weight_min
    if characteristic_weight_max is not None:
        data["characteristicWeightMax"] = characteristic_weight_max

    r = httpx.post(f"{BASE_URL}/product/list", data=data)
    response = r.json()
    if fields is not None:
        for product in response.get("products", []):
            product_data = product.get("data", {})
            product["data"] = {k: v for k, v in product_data.items() if k in fields}

    response_str = json.dumps(response, ensure_ascii=False)

    if len(response_str) > 30000:
        return {
            "error": {
                "message": "Слишком много данных, попробуй уточнить фильтры. Length: " + str(len(response_str))
            }
        }

    return response

    # cleaned_products = []
    # for product in response.get("products", []):
    #     pData = product.get("data", {})
    #
    #     pData.pop("images", None)
    #     pData.pop("discount", None)
    #     pData.pop("msrp", None)
    #     pData.pop("order", None)
    #     pData.pop("url", None)
    #
    #     if "gmv" in pData:
    #         pData["gmv"].pop("total", None)
    #     if "price" in pData:
    #         pData["price"].pop("min", None)
    #         pData["price"].pop("max", None)
    #     if "review" in pData:
    #         pData["review"].pop("count", None)
    #     if "sales" in pData:
    #         pData["sales"].pop("total", None)
    #     if "categories" in pData:
    #         for category in pData["categories"]:
    #             category.pop("url", None)
    #             category.pop("link", None)
    #             category.pop("ts", None)
    #             category.pop("active", None)
    #             category.pop("actual", None)
    #     if "merchants" in pData:
    #         for merchant in pData["merchants"]:
    #             merchant.pop("url", None)
    #
    #     cleaned_products.append({
    #         "data": pData
    #     })
    #
    # cleaned_response = {
    #     "total": response.get("total"),
    #     "sortValues": response.get("sortValues"),
    #     "products": cleaned_products
    # }
    # return cleaned_response

    #    @mcp.tool(name="get_product_feeds", description="""
    #        Получает список фидов (лент) товара, в которых товар был замечен в разное время
    #
    #        Args:
    #            mall: Код витрины (обязательный)
    #            id: ID продукта (обязательный)
    #        """)
    #    def get_product_feeds(
    #            mall: str,
    #            id: int
    #    ) -> dict:
    #
    #        data = {"mall": mall, "id": id, "withSuggest": "true"}
    #
    #        r = httpx.post(f"{BASE_URL}/feed/productTransit", data=data)
    #        return r.json()


@mcp.tool(name="get_product_feeds", description="""
    Получает список фидов (лент) товара, в которых товар был замечен в разное время.

    Args:
        mall: Код витрины (обязательный)
        id: ID продукта (обязательный)
        max_records: Максимальное количество записей в ответе (по умолчанию 10)
        feed_type: Тип фида (по умолчанию 3 — поисковые ленты, фразы) 
            Другие типы: 1 - категория - позиции товара в категории 
                         2 - магазин, 3 - фраза, 4 - бренд)
        sort_by: Критерий сортировки — 'volume' (по объёму поиска, по умолчанию) или 'position' (по позиции в поиске)
        debug: False или True, если True - то отладка, по умолчанию False
    """)
def get_product_feeds(
        mall: str,
        id: int,
        max_records: int = 10,
        feed_type: int = 3,
        sort_by: str = "volume",
        debug: bool = False
) -> dict:
    def filter_and_sort_feeds(json_data, max_records, feed_type, sort_by):
        one_week_ago = int(time.time()) - 7 * 24 * 60 * 60

        filtered = []
        for entry in json_data.get("payload", {}).get("data", []):
            if entry.get("feedType") != feed_type:
                continue
            if entry.get("observedFeed", 0) < one_week_ago:
                continue

            filtered.append({
                "feedId": entry.get("feedId"),
                "feedName": entry.get("feedName"),
                "position": entry.get("position"),
                "searchVolume": entry.get("searchVolume", 0)
            })

        if sort_by == "position":
            sorted_filtered = sorted(filtered, key=lambda x: x["position"])
        else:  # sort_by == "volume" or anything else
            sorted_filtered = sorted(filtered, key=lambda x: x["searchVolume"], reverse=True)

        return sorted_filtered[:max_records]

    data = {"mall": mall, "id": id, "withSuggest": "true"}
    r = httpx.post(f"{BASE_URL}/feed/productTransit", data=data)

    # Check if debug mode is enabled
    if debug:
        raw_response = r.text
        return {"debug_response": raw_response[:15000]}
    else:
        # Return filtered and processed data (original behavior)
        filtered = filter_and_sort_feeds(r.json(), max_records, feed_type, sort_by)
        return {"feeds": filtered}


#   filtered = filter_and_sort_feeds(r.json(), max_records, feed_type, sort_by)

#   return {"feeds": filtered}
#   return  r.json()

@mcp.tool(name="get_list_aggregate", description="""
    Получает агрегаты (суму продаж/выручки/среднюю цену/ средний сток) по всем товарам попадающим под фильтры из @get_product_list
    Используй ТОЛЬКО аргументы перечисленные ниже.
    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls, если запрашивают озон или вайлдберриз, то можно не ходить в @get_malls, для wildberries код wb, для Ozon код ozon
        id: Список ID продуктов через запятую
        after: Вернуть следующие элементы после заданного
        limit: Вернуть заданное число элементов
        category_id: Список ID категорий через запятую
        brand_id: Список ID брендов через запятую
        merchant_id: Список ID магазинов через запятую
        sort: Параметр сортировки. Возможные значения:
            - created_asc/created_desc: По дате создания товара
            - added_asc/added_desc: По дате добавления товара
            - observed_asc/observed_desc: По дате последнего наблюдения товара
            - deleted_asc/deleted_desc: По дате удаления товара
            - rate_asc/rate_desc: По рейтингу товара
            - discount_asc/discount_desc: По скидке
            - discount_min_asc/discount_min_desc: По минимальной скидке
            - discount_avg_asc/discount_avg_desc: По средней скидке
            - discount_max_asc/discount_max_desc: По максимальной скидке
            - msrp_min_asc/msrp_min_desc: По минимальной рекомендованной цене
            - msrp_avg_asc/msrp_avg_desc: По средней рекомендованной цене
            - msrp_max_asc/msrp_max_desc: По максимальной рекомендованной цене
            - price_min_asc/price_min_desc: По минимальной цене
            - price_avg_asc/price_avg_desc: По средней цене
            - price_max_asc/price_max_desc: По максимальной цене
            - review_asc/review_desc: По количеству отзывов
            - review_first_asc/review_first_desc: По дате первого отзыва
            - review_last_asc/review_last_desc: По дате последнего отзыва
            - mall_reviews_asc/mall_reviews_desc: По количеству отзывов на маркетплейсе
            - sales_grow_asc/sales_grow_desc: По продажам (штуки) за период
            - gmv_grow_asc/gmv_grow_desc: По выручке за период
            - id_asc/id_desc: По ID
            - inventory_asc/inventory_desc: По остаткам
            - inventory_sum_asc/inventory_sum_desc: По сумме остатков
            - inventory_count_asc/inventory_count_desc: По количеству остатков
            - inventory_min_asc/inventory_min_desc: По минимальному остатку
            - inventory_max_asc/inventory_max_desc: По максимальному остатку
            - rating_count_asc/rating_count_desc: По количеству оценок
            - sold_orders_percent_asc/sold_orders_percent_desc: По проценту проданных заказов
        name: Поиск по названию (дословный по вхождению фразы в название товара)
        url: Список URL через запятую
        added_from: Минимальное время добавления (timestamp)
        added_to: Максимальное время добавления (timestamp)
        observed_from: Минимальное время наблюдения (timestamp)
        observed_to: Максимальное время наблюдения (timestamp)
        price_min_from: Минимальная цена от
        price_min_to: Минимальная цена до
        price_avg_from: Средняя цена от
        price_avg_to: Средняя цена до
        price_max_from: Максимальная цена от
        price_max_to: Максимальная цена до
        rate_from: Рейтинг от
        rate_to: Рейтинг до
        sales_from: Продажи от
        sales_to: Продажи до
        gmv_from: GMV от
        gmv_to: GMV до
        review_from: Отзывы от
        review_to: Отзывы до
        inventory_from: Остаток от
        inventory_to: Остаток до
        status: Список статусов через запятую. Возможные значения: available, deleted, archived, outstocked
        inventory_type: Список типов инвентаря через запятую. Возможные значения: 1 (FBS - Fulfillment by Seller), 2 (FBO - Fulfillment by Operator)
        created_from: Время создания от (timestamp)
        created_to: Время создания до (timestamp)
        review_first_from: Время первого отзыва от (timestamp)
        review_first_to: Время первого отзыва до (timestamp)
        review_last_from: Время последнего отзыва от (timestamp)
        review_last_to: Время последнего отзыва до (timestamp)
        count_words_name_from: Количество слов в названии от
        count_words_name_to: Количество слов в названии до
        count_words_desc_from: Количество слов в описании от
        count_words_desc_to: Количество слов в описании до
        count_images_from: Количество изображений от
        count_images_to: Количество изображений до
        count_videos_from: Количество видео от
        count_videos_to: Количество видео до
        count_characteristics_from: Количество характеристик от
        count_characteristics_to: Количество характеристик до
        deleted_from: Время удаления от (timestamp)
        deleted_to: Время удаления до (timestamp)
        after_id: ID для пагинации (используется вместе с sort_values)
        period: Период данных о продажах и отзывах за период, можно передать "last_month", "last_year" или месяц в формате "YYYY-MM" (например "2024-02") - обязательный
        link: Список ссылок через запятую
        sort_values: Техничское значения для пагинации (для получения следущего батча товаров), полученное в соответствующем поле в предыдущем запросе. Используется вместе с after_id
        subject_id: Список ID предметов через запятую
        country: Список стран через запятую
        rating_count_from: Количество оценок от
        rating_count_to: Количество оценок до
        tag_id: Список ID тегов через запятую
        sold_orders_percent_from: Процент проданных заказов от
        sold_orders_percent_to: Процент проданных заказов до
        characteristic_country: Страна производства
        characteristic_color: Цвет
        characteristic_volume_min: Минимальный объем
        characteristic_volume_max: Максимальный объем
        characteristic_quantity_min: Минимальное количество
        characteristic_quantity_max: Максимальное количество
        characteristic_weight_min: Минимальный вес
        characteristic_weight_max: Максимальный вес
    """)
def get_list_aggregate(
        mall: str,
        period: str,
        id: Optional[str] = None,
        after: int = 0,
        limit: int = 10,
        category_id: Optional[str] = None,
        brand_id: Optional[str] = None,
        merchant_id: Optional[str] = None,
        sort: Optional[str] = None,
        name: Optional[str] = None,
        url: Optional[str] = None,
        added_from: Optional[int] = None,
        added_to: Optional[int] = None,
        observed_from: Optional[int] = None,
        observed_to: Optional[int] = None,
        price_min_from: Optional[float] = None,
        price_min_to: Optional[float] = None,
        price_avg_from: Optional[float] = None,
        price_avg_to: Optional[float] = None,
        price_max_from: Optional[float] = None,
        price_max_to: Optional[float] = None,
        rate_from: Optional[float] = None,
        rate_to: Optional[float] = None,
        sales_from: Optional[int] = None,
        sales_to: Optional[int] = None,
        gmv_from: Optional[float] = None,
        gmv_to: Optional[float] = None,
        review_from: Optional[int] = None,
        review_to: Optional[int] = None,
        inventory_from: Optional[int] = None,
        inventory_to: Optional[int] = None,
        status: Optional[str] = None,
        inventory_type: Optional[str] = None,
        created_from: Optional[int] = None,
        created_to: Optional[int] = None,
        review_first_from: Optional[int] = None,
        review_first_to: Optional[int] = None,
        review_last_from: Optional[int] = None,
        review_last_to: Optional[int] = None,
        count_words_name_from: Optional[int] = None,
        count_words_name_to: Optional[int] = None,
        count_words_desc_from: Optional[int] = None,
        count_words_desc_to: Optional[int] = None,
        count_images_from: Optional[int] = None,
        count_images_to: Optional[int] = None,
        count_videos_from: Optional[int] = None,
        count_videos_to: Optional[int] = None,
        count_characteristics_from: Optional[int] = None,
        count_characteristics_to: Optional[int] = None,
        available_from: Optional[int] = None,
        available_to: Optional[int] = None,
        outstocked_from: Optional[int] = None,
        outstocked_to: Optional[int] = None,
        deleted_from: Optional[int] = None,
        deleted_to: Optional[int] = None,
        after_id: Optional[str] = None,
        link: Optional[str] = None,
        subject_id: Optional[str] = None,
        country: Optional[str] = None,
        rating_count_from: Optional[int] = None,
        rating_count_to: Optional[int] = None,
        tag_id: Optional[str] = None,
        sold_orders_percent_from: Optional[int] = None,
        sold_orders_percent_to: Optional[int] = None,
        characteristic_country: Optional[str] = None,
        characteristic_color: Optional[str] = None,
        characteristic_volume_min: Optional[int] = None,
        characteristic_volume_max: Optional[int] = None,
        characteristic_quantity_min: Optional[int] = None,
        characteristic_quantity_max: Optional[int] = None,
        characteristic_weight_min: Optional[int] = None,
        characteristic_weight_max: Optional[int] = None
) -> dict:
    data = {"mall": mall, "after": after, "limit": limit}

    if id is not None:
        data["id"] = [int(x) for x in id.split(",")]
    if category_id is not None:
        data["categoryId"] = [int(x) for x in category_id.split(",")]
    if brand_id is not None:
        data["brandId"] = [int(x) for x in brand_id.split(",")]
    if merchant_id is not None:
        data["merchantId"] = [int(x) for x in merchant_id.split(",")]
    if sort is not None:
        data["sort"] = sort
    if name is not None:
        data["name"] = name
    if url is not None:
        data["url"] = url.split(",")
    if added_from is not None:
        data["addedFrom"] = added_from
    if added_to is not None:
        data["addedTo"] = added_to
    if observed_from is not None:
        data["observedFrom"] = observed_from
    if observed_to is not None:
        data["observedTo"] = observed_to
    if price_min_from is not None:
        data["priceMinFrom"] = price_min_from
    if price_min_to is not None:
        data["priceMinTo"] = price_min_to
    if price_avg_from is not None:
        data["priceAvgFrom"] = price_avg_from
    if price_avg_to is not None:
        data["priceAvgTo"] = price_avg_to
    if price_max_from is not None:
        data["priceMaxFrom"] = price_max_from
    if price_max_to is not None:
        data["priceMaxTo"] = price_max_to
    if rate_from is not None:
        data["rateFrom"] = rate_from
    if rate_to is not None:
        data["rateTo"] = rate_to
    if sales_from is not None:
        data["salesFrom"] = sales_from
    if sales_to is not None:
        data["salesTo"] = sales_to
    if gmv_from is not None:
        data["gmvFrom"] = gmv_from
    if gmv_to is not None:
        data["gmvTo"] = gmv_to
    if review_from is not None:
        data["reviewFrom"] = review_from
    if review_to is not None:
        data["reviewTo"] = review_to
    if inventory_from is not None:
        data["inventoryFrom"] = inventory_from
    if inventory_to is not None:
        data["inventoryTo"] = inventory_to
    if status is not None:
        data["status"] = status.split(",")
    if inventory_type is not None:
        data["inventoryType"] = [int(x) for x in inventory_type.split(",")]
    if created_from is not None:
        data["createdFrom"] = created_from
    if created_to is not None:
        data["createdTo"] = created_to
    if review_first_from is not None:
        data["reviewFirstFrom"] = review_first_from
    if review_first_to is not None:
        data["reviewFirstTo"] = review_first_to
    if review_last_from is not None:
        data["reviewLastFrom"] = review_last_from
    if review_last_to is not None:
        data["reviewLastTo"] = review_last_to
    if count_words_name_from is not None:
        data["countWordsNameFrom"] = count_words_name_from
    if count_words_name_to is not None:
        data["countWordsNameTo"] = count_words_name_to
    if count_words_desc_from is not None:
        data["countWordsDescFrom"] = count_words_desc_from
    if count_words_desc_to is not None:
        data["countWordsDescTo"] = count_words_desc_to
    if count_images_from is not None:
        data["countImagesFrom"] = count_images_from
    if count_images_to is not None:
        data["countImagesTo"] = count_images_to
    if count_videos_from is not None:
        data["countVideosFrom"] = count_videos_from
    if count_videos_to is not None:
        data["countVideosTo"] = count_videos_to
    if count_characteristics_from is not None:
        data["countCharacteristicsFrom"] = count_characteristics_from
    if count_characteristics_to is not None:
        data["countCharacteristicsTo"] = count_characteristics_to
    if available_from is not None:
        data["availableFrom"] = available_from
    if available_to is not None:
        data["availableTo"] = available_to
    if outstocked_from is not None:
        data["outstockedFrom"] = outstocked_from
    if outstocked_to is not None:
        data["outstockedTo"] = outstocked_to
    if deleted_from is not None:
        data["deletedFrom"] = deleted_from
    if deleted_to is not None:
        data["deletedTo"] = deleted_to
    if after_id is not None:
        data["afterId"] = after_id
    if period is not None:
        if period == "last_month":
            data["periodNumber"] = 1
            data["periodMeasure"] = "M"
            data["periodType"] = "grow"
        elif period == "last_year":
            data["periodNumber"] = 1
            data["periodMeasure"] = "Y"
            data["periodType"] = "grow"
        else:
            data["periodNumber"] = period_to_timestamp(period)
            data["periodMeasure"] = "M"
            data["periodType"] = "calendar"
    if link is not None:
        data["link"] = link.split(",")
    if subject_id is not None:
        data["subjectId"] = [int(x) for x in subject_id.split(",")]
    if country is not None:
        data["country"] = country.split(",")
    if rating_count_from is not None:
        data["ratingCountFrom"] = rating_count_from
    if rating_count_to is not None:
        data["ratingCountTo"] = rating_count_to
    if tag_id is not None:
        data["tagId"] = [int(x) for x in tag_id.split(",")]
    if sold_orders_percent_from is not None:
        data["soldOrdersPercentFrom"] = sold_orders_percent_from
    if sold_orders_percent_to is not None:
        data["soldOrdersPercentTo"] = sold_orders_percent_to
    if characteristic_country is not None:
        data["characteristicCountry"] = characteristic_country
    if characteristic_color is not None:
        data["characteristicColor"] = characteristic_color
    if characteristic_volume_min is not None:
        data["characteristicVolumeMin"] = characteristic_volume_min
    if characteristic_volume_max is not None:
        data["characteristicVolumeMax"] = characteristic_volume_max
    if characteristic_quantity_min is not None:
        data["characteristicQuantityMin"] = characteristic_quantity_min
    if characteristic_quantity_max is not None:
        data["characteristicQuantityMax"] = characteristic_quantity_max
    if characteristic_weight_min is not None:
        data["characteristicWeightMin"] = characteristic_weight_min
    if characteristic_weight_max is not None:
        data["characteristicWeightMax"] = characteristic_weight_max

    r = httpx.post(f"{BASE_URL}/list/aggregate", data=data)
    return r.json()


# @mcp.tool(name="get_products", description= """
#    Получает информацию о товарах по mall и списку ID.
#
#    Args:
#        mall: Код витрины (обязательный), получить из метода @get_malls
#        id_list: Список ID товаров через запятую
#    """)
# def get_products(mall: str, id_list: str) -> dict:
#    ids = [int(x) for x in id_list.split(",")]
#    r = httpx.post(f"{BASE_URL}/products", data={"mall": mall, "id": ids})
#    return r.json()

@mcp.tool(name="get_products", description="""
    Получает информацию о товарах по mall и списку ID с возможностью ограничить набор возвращаемых полей.

    Args:
        mall (str): Код витрины (обязательный), получить из метода @get_malls.
        id_list (str): Список ID товаров через запятую (например: "123,456,789").
        fields (Optional[str]): Список возвращаемых полей через запятую. 
            Примеры:
              - "id,name,rate"
              - "brand,images,characteristics"
              - "merchant.legalInn,ts.updated"

            Поддерживаемые поля:
              - id: ID товара
              - link: Внутренний артикул/ссылка
              - url: Ссылка на карточку на маркетплейсе
              - name: Название товара
              - code: SKU / внешний код товара
              - rate: Средняя оценка товара
              - ratingCount: Кол-во поставленных оценок
              - reviews: Кол-во отзывов
              - review: Объект с данными о первом и последнем отзывах
              - images: Список ссылок на изображения
              - videos: Список ссылок на видео
              - brandId: ID бренда
              - brand: Название бренда
              - merchant: Объект продавца (id, name, url, legalInn, rate)
              - merchants: Список продавцов, связанных с группой товаров
              - groupedIds: Сгруппированные ID одного товара
              - subjects: Категория и подкатегории
              - statuses: Состояния (например, available)
              - ts: Таймстемпы (created, updated, observed)
              - categories: Иерархия категорий
              - variations: Варианты (цвет, склады, цена, наличие)
              - characteristics: Характеристики товара (имя + значение)
              - countWordsName: Кол-во слов в названии
              - countWordsDesc: Кол-во слов в описании
              - countImages: Кол-во изображений
              - countVideos: Кол-во видео
              - countCharacteristics: Кол-во характеристик
              - pts: Внутренняя оценка платформы
              - soldOrdersPercent: Конверсия в покупки
              - colors: Список цветов товара

            Поддерживается вложенность через точку (например: merchant.legalInn или ts.updated).
            Если не задано — возвращаются все поля.
    """)
def get_products(mall: str, id_list: str, fields: Optional[List[str]] = None) -> dict:
    ids = [int(x.strip()) for x in id_list.split(",") if x.strip()]
    r = httpx.post(f"{BASE_URL}/products", data={"mall": mall, "id": ids})
    data = r.json()

    if fields and "products" in data:
        filtered_products = []
        for product in data["products"]:
            filtered = {}
            for field in fields:
                if field in product:
                    filtered[field] = product[field]
                elif "current" in product and field in product["current"]:
                    filtered[field] = product["current"][field]
            filtered_products.append(filtered)
        data["products"] = filtered_products

    return data


@mcp.tool(name="get_feed_positions", description="""
    Получает позиции продуктов в лентах. Используется для получения информаии о лентах нескольких продуктов.

    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
        after: Вернуть следующие элементы после заданного
        limit: Вернуть заданное число элементов
        skip: Пропустить продукты чужих брендов
        from_time: Начало временного интервала (unix timestamp)
        until: Конец временного интервала (unix timestamp)
        brand_id: Список ID брендов через запятую
        category_id: Список ID категорий через запятую
        merchant_id: Список ID магазинов через запятую
        phrase_id: Список ID фраз поиска через запятую
        feed_id: Список ID лент поиска через запятую
        product_name: Название продукта
        url: Список URL через запятую
        position_from: Минимальное значение позиции
        position_to: Максимальное значение позиции
        position_growth_from: Минимальное значение роста позиции
        position_growth_to: Максимальное значение роста позиции
    """)
def get_feed_positions(
        mall: str,
        after: int = 0,
        limit: int = 100,
        skip: bool = False,
        from_time: Optional[int] = None,
        until: Optional[int] = None,
        brand_id: Optional[str] = None,
        category_id: Optional[str] = None,
        merchant_id: Optional[str] = None,
        phrase_id: Optional[str] = None,
        feed_id: Optional[str] = None,
        product_name: Optional[str] = None,
        url: Optional[str] = None,
        position_from: Optional[int] = None,
        position_to: Optional[int] = None,
        position_growth_from: Optional[float] = None,
        position_growth_to: Optional[float] = None
) -> dict:
    data = {"mall": mall, "after": after, "limit": limit, "skip": skip}

    if from_time is not None:
        data["from"] = from_time
    if until is not None:
        data["until"] = until
    if brand_id is not None:
        data["brandId"] = [int(x) for x in brand_id.split(",")]
    if category_id is not None:
        data["categoryId"] = [int(x) for x in category_id.split(",")]
    if merchant_id is not None:
        data["merchantId"] = [int(x) for x in merchant_id.split(",")]
    if phrase_id is not None:
        data["phraseId"] = [int(x) for x in phrase_id.split(",")]
    if feed_id is not None:
        data["feedId"] = [int(x) for x in feed_id.split(",")]
    if product_name is not None:
        data["productName"] = product_name
    if url is not None:
        data["url"] = url.split(",")
    if position_from is not None:
        data["positionFrom"] = position_from
    if position_to is not None:
        data["positionTo"] = position_to
    if position_growth_from is not None:
        data["positionGrowthFrom"] = position_growth_from
    if position_growth_to is not None:
        data["positionGrowthTo"] = position_growth_to

    r = httpx.post(f"{BASE_URL}/feed/positions", data=data)
    return r.json()

@mcp.tool(name="get_review_list", description="""
    Получает список отзывов (без текста) по различным параметрам.
    Можно получить отзывы для товара, бренда, категории или магазина.
    Тексты отзывов получаются отдельным методом @get_review_text
    Используй ТОЛЬКО аргументы перечисленные ниже.
    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
        id: Список ID продуктов через запятую
        after: Вернуть следующие элементы после заданного
        limit: Вернуть заданное число элементов
        category_id: Список ID категорий через запятую
        brand_id: Список ID брендов через запятую
        merchant_id: Список ID магазинов через запятую
        sort: Параметр сортировки. Возможные значения:
            - review_created_asc/review_created_desc: По дате создания отзыва
            - review_rate_asc/review_rate_desc: По оценке в отзыве
        review_created_from: Время создания отзыва от (timestamp)
        review_created_to: Время создания отзыва до (timestamp)
        review_rate_from: Оценка в отзыве от (1-5)
        review_rate_to: Оценка в отзыве до (1-5)
        answer_count_from: Кол-во ответов на отзыв от (если нужны отзывы с ответами - используй 1, если без ответов 0, иначе опускай поле)
        after_id: ID для пагинации (используется вместе с sort_values)
        sort_values: Значения сортировки для пагинации, полученные от предыдущего запроса. Используется вместе с after_id
    """)
def get_review_list(
        mall: str,
        id: Optional[str] = None,
        after: int = 0,
        limit: int = 10,
        category_id: Optional[str] = None,
        brand_id: Optional[str] = None,
        merchant_id: Optional[str] = None,
        sort: Optional[str] = None,
        review_created_from: Optional[int] = None,
        review_created_to: Optional[int] = None,
        review_rate_from: Optional[int] = None,
        review_rate_to: Optional[int] = None,
        answer_count_from: Optional[int] = None,
        after_id: Optional[str] = None,
        sort_values: Optional[str] = None
) -> dict:
    data = {"mall": mall, "after": after, "limit": limit}

    if id is not None:
        data["id"] = [int(x) for x in id.split(",")]
    if category_id is not None:
        data["categoryId"] = [int(x) for x in category_id.split(",")]
    if brand_id is not None:
        data["brandId"] = [int(x) for x in brand_id.split(",")]
    if merchant_id is not None:
        data["merchantId"] = [int(x) for x in merchant_id.split(",")]
    if sort is not None:
        data["sort"] = sort
    if after_id is not None:
        data["afterId"] = after_id

    if review_created_from is not None:
        data["reviewCreatedFrom"] = review_created_from
    if review_created_to is not None:
        data["reviewCreatedTo"] = review_created_to
    if review_rate_from is not None:
        data["reviewRateFrom"] = review_rate_from
    if review_rate_to is not None:
        data["reviewRateTo"] = review_rate_to
    if answer_count_from is not None:
        data["answerCountFrom"] = answer_count_from

    if sort_values is not None:
        data["sortValues"] = sort_values
    
    r = httpx.post(f"{BASE_URL}/review/list", data=data)
    response = r.json()

    return response

@mcp.tool(name="get_review_text", description="""
    Получает текстs отзывов (с текстами ответов) по их айди.
    Сами отзывы (с айди и без текста) можно получить методом @get_review_list
    Используй ТОЛЬКО аргументы перечисленные ниже.
    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
        id: Список ID отзывов через запятую
    """)
def get_review_text(
        mall: str,
        id: Optional[str] = None
) -> dict:
    data = {"mall": mall}

    if id is not None:
        data["id"] = [str(x) for x in id.split(",")]
    
    r = httpx.post(f"{BASE_URL}/review/comment", data=data)
    response = r.json()

    return response

@mcp.tool(name="get_feed_info", description="""
    Получает сводную информацию о лентах.

    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
        category_id: Список ID категорий через запятую
        merchant_id: Список ID магазинов через запятую
        phrase_id: Список ID фраз поиска через запятую
        feed_id: Список ID лент поиска через запятую
    """)
def get_feed_info(
        mall: str,
        category_id: Optional[str] = None,
        merchant_id: Optional[str] = None,
        phrase_id: Optional[str] = None,
        feed_id: Optional[str] = None
) -> dict:
    data = {"mall": mall}

    if category_id is not None:
        data["categoryId"] = [int(x) for x in category_id.split(",")]
    if merchant_id is not None:
        data["merchantId"] = [int(x) for x in merchant_id.split(",")]
    if phrase_id is not None:
        data["phraseId"] = [int(x) for x in phrase_id.split(",")]
    if feed_id is not None:
        data["feedId"] = [int(x) for x in feed_id.split(",")]

    r = httpx.post(f"{BASE_URL}/feed/info", data=data)
    return r.json()


@mcp.tool(name="get_phrase_suggest", description="""
    Отображает текст ключевой фразы в ID или обратно.

    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
        id: Список ID фраз через запятую
        name: Текст ключевой фразы полностью или частично
        link: Список точных текстов для поиска через запятую
        from_item: Начальная позиция
        limit: Ограничить ответ заданным числом элементов
    """)
def get_phrase_suggest(
        mall: str,
        id: Optional[str] = None,
        name: Optional[str] = None,
        link: Optional[str] = None,
        from_item: Optional[int] = None,
        limit: int = 100
) -> dict:
    data = {"mall": mall, "limit": limit}

    if id is not None:
        data["id"] = [int(x) for x in id.split(",")]
    if name is not None:
        data["name"] = name
    if link is not None:
        data["link"] = link.split(",")
    if from_item is not None:
        data["from"] = from_item

    r = httpx.post(f"{BASE_URL}/phrase/suggest", data=data)
    return r.json()


@mcp.tool(name="get_archive_product_season_list", description="""
    Получает список сезонов.

    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
        limit: Ограничить ответ заданным числом элементов
    """)
def get_archive_product_season_list(
        mall: str,
        limit: Optional[int] = None
) -> dict:
    data = {"mall": mall}

    if limit is not None:
        data["limit"] = limit

    r = httpx.post(f"{BASE_URL}/archive/product/season/list", data=data)
    return r.json()


@mcp.tool(name="get_archive_product_position", description="""
    Получает список позиций продукта в ленте.

    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
        id: ID продукта
        feed_type: Тип ленты (1 - категория, 2 - магазин, 3 - фраза, 4 - бренд)
        feed_id: ID ленты
        from_time: Начало временного диапазона (timestamp)
        to_time: Конец временного диапазона (timestamp)
    """)
def get_archive_product_position(
        mall: str,
        id: int,
        feed_type: int,
        feed_id: int,
        from_time: Optional[int] = None,
        to_time: Optional[int] = None
) -> dict:
    data = {"mall": mall, "id": id, "feedType": feed_type, "feedId": feed_id}

    if from_time is not None:
        data["from"] = from_time
    if to_time is not None:
        data["to"] = to_time

    r = httpx.post(f"{BASE_URL}/archive/product/position", data=data)
    return r.json()


@mcp.tool(name="get_archive_product_positions", description="""
    Получает список позиций продукта в лентах.

    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
        id: ID продукта
        feed_type: Тип ленты (1 - категория, 2 - магазин, 3 - фраза, 4 - бренд)
        feed_id: Список ID лент через запятую
        from_time: Начало временного диапазона (timestamp)
        to_time: Конец временного диапазона (timestamp)
    """)
def get_archive_product_positions(
        mall: str,
        id: int,
        feed_type: Optional[int] = None,
        feed_id: Optional[str] = None,
        from_time: Optional[int] = None,
        to_time: Optional[int] = None
) -> dict:
    data = {"mall": mall, "id": id}

    if feed_type is not None:
        data["feedType"] = feed_type
    if feed_id is not None:
        data["feedId"] = [int(x) for x in feed_id.split(",")]
    if from_time is not None:
        data["from"] = from_time
    if to_time is not None:
        data["to"] = to_time

    r = httpx.post(f"{BASE_URL}/archive/product/positions", data=data)
    return r.json()


#
# @mcp.tool(name="get_review_list", description="Список отзывов продуктов")
# def get_review_list(
#         mall: str,
#         id: Optional[str] = None,
#         after: int = 0,
#         limit: int = 10,
#         category_id: Optional[str] = None,
#         brand_id: Optional[str] = None,
#         merchant_id: Optional[str] = None,
#         review_country: Optional[str] = None,
#         from_time: Optional[int] = None,
#         to_time: Optional[int] = None,
#         review_rate_from: Optional[float] = None,
#         review_rate_to: Optional[float] = None,
#         review_created_from: Optional[int] = None,
#         review_created_to: Optional[int] = None,
#         answer_count_from: Optional[int] = None,
#         answer_count_to: Optional[int] = None,
#         kwargs: str = "{}"
# ) -> dict:
#     """
#     Получает список отзывов продуктов.
#
#     Args:
#         mall: Код витрины (обязательный), получить из метода @get_malls
#         id: Список ID продуктов через запятую
#         after: Вернуть следующие элементы после заданного
#         limit: Вернуть заданное число элементов
#         category_id: Список ID категорий через запятую
#         brand_id: Список ID брендов через запятую
#         merchant_id: Список ID магазинов через запятую
#         review_country: Список стран отзывов через запятую
#         from_time: Начало временного интервала (timestamp)
#         to_time: Конец временного интервала (timestamp)
#         review_rate_from: Рейтинг отзыва от
#         review_rate_to: Рейтинг отзыва до
#         review_created_from: Время создания отзыва от (timestamp)
#         review_created_to: Время создания отзыва до (timestamp)
#         answer_count_from: Количество ответов от
#         answer_count_to: Количество ответов до
#         kwargs: Дополнительные параметры в формате JSON строки
#     """
#     data = {"mall": mall, "after": after, "limit": limit}
#
#     if id is not None:
#         data["id"] = [int(x) for x in id.split(",")]
#     if category_id is not None:
#         data["categoryId"] = [int(x) for x in category_id.split(",")]
#     if brand_id is not None:
#         data["brandId"] = [int(x) for x in brand_id.split(",")]
#     if merchant_id is not None:
#         data["merchantId"] = [int(x) for x in merchant_id.split(",")]
#     if review_country is not None:
#         data["reviewCountry"] = review_country.split(",")
#     if from_time is not None:
#         data["from"] = from_time
#     if to_time is not None:
#         data["to"] = to_time
#     if review_rate_from is not None:
#         data["reviewRateFrom"] = review_rate_from
#     if review_rate_to is not None:
#         data["reviewRateTo"] = review_rate_to
#     if review_created_from is not None:
#         data["reviewCreatedFrom"] = review_created_from
#     if review_created_to is not None:
#         data["reviewCreatedTo"] = review_created_to
#     if answer_count_from is not None:
#         data["answerCountFrom"] = answer_count_from
#     if answer_count_to is not None:
#         data["answerCountTo"] = answer_count_to
#
#     # Добавление дополнительных параметров из kwargs
#     import json
#     extra_params = json.loads(kwargs)
#     for key, value in extra_params.items():
#         if key not in data:
#             data[key] = value
#
#     r = httpx.post(f"{BASE_URL}/review/list", data=data)
#     return r.json()

#
# @mcp.tool(name="get_review_comment", description="Текст отзывов")
# def get_review_comment(mall: str, id: str) -> dict:
#     """
#     Получает текст отзывов.
#
#     Args:
#         mall: Код витрины (обязательный), получить из метода @get_malls
#         id: Список ID отзывов через запятую
#     """
#     data = {"mall": mall, "id": id.split(",")}
#
#     r = httpx.post(f"{BASE_URL}/review/comment", data=data)
#     return r.json()

@mcp.tool(name="get_category_map", description="""
    Получает список категорий.

    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
        id: Список ID категорий через запятую
    """)
def get_category_map(mall: str, id: str) -> dict:
    data = {"mall": mall, "id": id.split(",")}

    r = httpx.post(f"{BASE_URL}/category/map", data=data)
    return r.json()


@mcp.tool(name="get_subjects", description="""
    Получает список предметов.

    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
    """)
def get_subjects(mall: str) -> dict:
    data = {"mall": mall}

    r = httpx.post(f"{BASE_URL}/subjects", data=data)
    return r.json()


@mcp.tool(name="get_tags", description="""
    Получает список тегов.

    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
    """)
def get_tags(mall: str) -> dict:
    data = {"mall": mall}

    r = httpx.post(f"{BASE_URL}/tags", data=data)
    return r.json()


@mcp.tool(name="get_archive_product_sales", description="""
    Получает исторические данные о продажах товара.

    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
        id: ID продукта
        from_time: Начало временного интервала (timestamp)
        to_time: Конец временного интервала (timestamp)
        inventory_type: Список типов инвентаря через запятую. Возможные значения: 1 (FBS - Fulfillment by Seller), 2 (FBO - Fulfillment by Operator)
    """)
def get_archive_product_sales(
        mall: str,
        id: int,
        from_time: Optional[int] = None,
        to_time: Optional[int] = None,
        inventory_type: Optional[str] = None
) -> dict:
    data = {"mall": mall, "id": id}

    if from_time is not None:
        data["from"] = from_time
    if to_time is not None:
        data["to"] = to_time
    if inventory_type is not None:
        data["inventoryType"] = [int(x) for x in inventory_type.split(",")]

    r = httpx.post(f"{BASE_URL}/archive/product/sales", data=data)
    return r.json()


@mcp.tool(name="get_archive_product_price", description="""
    Получает исторические данные о ценах товара.

    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
        id: ID продукта
        from_time: Начало временного интервала (timestamp)
        to_time: Конец временного интервала (timestamp)
    """)
def get_archive_product_price(
        mall: str,
        id: int,
        from_time: Optional[int] = None,
        to_time: Optional[int] = None
) -> dict:
    data = {"mall": mall, "id": id}

    if from_time is not None:
        data["from"] = from_time
    if to_time is not None:
        data["to"] = to_time

    r = httpx.post(f"{BASE_URL}/archive/product/price", data=data)
    return r.json()


@mcp.tool(name="get_archive_product_inventory", description="""
    Получает исторические данные о наличии товара на складе.

    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
        id: ID продукта
        from_time: Начало временного интервала (timestamp)
        to_time: Конец временного интервала (timestamp)
    """)
def get_archive_product_inventory(
        mall: str,
        id: int,
        from_time: Optional[int] = None,
        to_time: Optional[int] = None
) -> dict:
    data = {"mall": mall, "id": id}

    if from_time is not None:
        data["from"] = from_time
    if to_time is not None:
        data["to"] = to_time

    r = httpx.post(f"{BASE_URL}/archive/product/inventory", data=data)
    return r.json()


@mcp.tool(name="get_archive_product_rating", description="""
    Получает исторические данные о рейтинге товара.

    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
        id: ID продукта
        from_time: Начало временного интервала (timestamp)
        to_time: Конец временного интервала (timestamp)
    """)
def get_archive_product_rating(
        mall: str,
        id: int,
        from_time: Optional[int] = None,
        to_time: Optional[int] = None
) -> dict:
    data = {"mall": mall, "id": id}

    if from_time is not None:
        data["from"] = from_time
    if to_time is not None:
        data["to"] = to_time

    r = httpx.post(f"{BASE_URL}/archive/product/rating", data=data)
    return r.json()


@mcp.tool(name="get_archive_product_review", description="""
    Получает исторические данные о количестве отзывов товара.

    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
        id: ID продукта
        from_time: Начало временного интервала (timestamp)
        to_time: Конец временного интервала (timestamp)
    """)
def get_archive_product_review(
        mall: str,
        id: int,
        from_time: Optional[int] = None,
        to_time: Optional[int] = None
) -> dict:
    data = {"mall": mall, "id": id}

    if from_time is not None:
        data["from"] = from_time
    if to_time is not None:
        data["to"] = to_time

    r = httpx.post(f"{BASE_URL}/archive/product/review", data=data)
    return r.json()


@mcp.tool(name="get_brand_suggest", description="""
    Выполняет поиск брендов.

    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
        id: Список ID брендов через запятую
        name: Название бренда (полностью или частично)
        limit: Ограничить результаты указанным количеством
    """)
def get_brand_suggest(
        mall: str,
        id: Optional[str] = None,
        name: Optional[str] = None,
        limit: int = 10
) -> dict:
    data = {"mall": mall, "limit": limit}

    if id is not None:
        data["id"] = [int(x) for x in id.split(",")]
    if name is not None:
        data["name"] = name

    r = httpx.post(f"{BASE_URL}/brand/suggest", data=data)
    return r.json()


@mcp.tool(name="get_merchants", description="""
    Выполняет поиск продавцов (мерчей).

    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
        id: Список ID продавцов через запятую
        name: Название продавца (полностью или частично)
        limit: Ограничить результаты указанным количеством
    """)
def get_merchants(
        mall: str,
        id: Optional[str] = None,
        name: Optional[str] = None,
        limit: int = 10
) -> dict:
    data = {"mall": mall, "limit": limit}

    if id is not None:
        data["id"] = [int(x) for x in id.split(",")]
    if name is not None:
        data["name"] = name

    r = httpx.post(f"{BASE_URL}/merchants", data=data)
    return r.json()


@mcp.tool(name="get_product_events", description="""
    Получает исторические данные о статусах товара.

    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
        id: Список ID продуктов через запятую
    """)
def get_product_events(mall: str, id: str) -> dict:
    data = {"mall": mall, "id": [int(x) for x in id.split(",")]}

    r = httpx.post(f"{BASE_URL}/product/events", data=data)
    return r.json()


@mcp.tool(name="get_categories", description="""
    Получает список категорий на маркетплейсе.

    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
        id: ID категории для получения подкатегорий
        levels: Глубина возвращаемого дерева категорий (до 4 уровня)
    """)
def get_categories(
        mall: str,
        id: Optional[int] = None,
        levels: Optional[int] = None
) -> dict:
    data = {"mall": mall}

    if id is not None:
        data["id"] = id
    if levels is not None:
        data["levels"] = levels

    r = httpx.post(f"{BASE_URL}/categories", data=data)
    return r.json()


@mcp.tool(name="get_country_list", description="""
    Получает список стран.

    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
    """)
def get_country_list(mall: str) -> dict:
    data = {"mall": mall}

    r = httpx.post(f"{BASE_URL}/country/list", data=data)
    return r.json()


#
# @mcp.tool(name="get_question_list", description="Список вопросов продуктов")
# def get_question_list(
#         mall: str,
#         id: Optional[str] = None,
#         after: int = 0,
#         limit: int = 10,
#         category_id: Optional[str] = None,
#         brand_id: Optional[str] = None,
#         merchant_id: Optional[str] = None,
#         question_country: Optional[str] = None,
#         from_time: Optional[int] = None,
#         to_time: Optional[int] = None,
#         question_created_from: Optional[int] = None,
#         question_created_to: Optional[int] = None,
#         answer_count_from: Optional[int] = None,
#         answer_count_to: Optional[int] = None,
#         kwargs: str = "{}"
# ) -> dict:
#     """
#     Получает список вопросов продуктов.
#
#     Args:
#         mall: Код витрины (обязательный), получить из метода @get_malls
#         id: Список ID продуктов через запятую
#         after: Вернуть следующие элементы после заданного
#         limit: Вернуть заданное число элементов
#         category_id: Список ID категорий через запятую
#         brand_id: Список ID брендов через запятую
#         merchant_id: Список ID магазинов через запятую
#         question_country: Список стран вопросов через запятую
#         from_time: Начало временного интервала (timestamp)
#         to_time: Конец временного интервала (timestamp)
#         question_created_from: Время создания вопроса от (timestamp)
#         question_created_to: Время создания вопроса до (timestamp)
#         answer_count_from: Количество ответов от
#         answer_count_to: Количество ответов до
#         kwargs: Дополнительные параметры в формате JSON строки
#     """
#     data = {"mall": mall, "after": after, "limit": limit}
#
#     if id is not None:
#         data["id"] = [int(x) for x in id.split(",")]
#     if category_id is not None:
#         data["categoryId"] = [int(x) for x in category_id.split(",")]
#     if brand_id is not None:
#         data["brandId"] = [int(x) for x in brand_id.split(",")]
#     if merchant_id is not None:
#         data["merchantId"] = [int(x) for x in merchant_id.split(",")]
#     if question_country is not None:
#         data["questionCountry"] = question_country.split(",")
#     if from_time is not None:
#         data["from"] = from_time
#     if to_time is not None:
#         data["to"] = to_time
#     if question_created_from is not None:
#         data["questionCreatedFrom"] = question_created_from
#     if question_created_to is not None:
#         data["questionCreatedTo"] = question_created_to
#     if answer_count_from is not None:
#         data["answerCountFrom"] = answer_count_from
#     if answer_count_to is not None:
#         data["answerCountTo"] = answer_count_to
#
#     # Добавление дополнительных параметров из kwargs
#     import json
#     extra_params = json.loads(kwargs)
#     for key, value in extra_params.items():
#         if key not in data:
#             data[key] = value
#
#     r = httpx.post(f"{BASE_URL}/question/list", data=data)
#     return r.json()
#
#
# @mcp.tool(name="get_question_comment", description="Текст вопросов")
# def get_question_comment(mall: str, id: str) -> dict:
#     """
#     Получает текст вопросов.
#
#     Args:
#         mall: Код витрины (обязательный), получить из метода @get_malls
#         id: Список ID вопросов через запятую
#     """
#     data = {"mall": mall, "id": id.split(",")}
#
#     r = httpx.post(f"{BASE_URL}/question/comment", data=data)
#     return r.json()


@mcp.tool(name="get_product_offers", description="""
    Получает офферы товара (на офферных витринах - beru, goods, lavka, samokat).

    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
        id: Список ID продуктов через запятую
    """)
def get_product_offers(mall: str, id: str) -> dict:
    data = {"mall": mall, "id": [int(x) for x in id.split(",")]}

    r = httpx.post(f"{BASE_URL}/product/offers", data=data)
    return r.json()


@mcp.tool(name="get_keyword_list", description="""
    Получает список кейвордов (поисковых фраз) со статистикой.

    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
        suggest: Поисковая фраза (частичное совпадение)
        suggest_exact: Точное совпадение поисковой фразы
        category_id: Список ID категорий через запятую
        brand_id: Список ID брендов через запятую
        merchant_id: Список ID магазинов через запятую
        total_products_from: Всего продуктов от
        total_products_to: Всего продуктов до
        sales_from: Продажи от
        sales_to: Продажи до
        gmv_from: GMV от
        gmv_to: GMV до
        competition_from: Конкуренция от
        competition_to: Конкуренция до
        search_volume_from: Объем поиска от
        search_volume_to: Объем поиска до
        phrase_id: Список ID фраз через запятую
        sort: Параметр сортировки
        after: Вернуть следующие элементы после заданного
        limit: Вернуть заданное число элементов
    """)
def get_keyword_list(
        mall: str,
        suggest: Optional[str] = None,
        suggest_exact: Optional[str] = None,
        category_id: Optional[str] = None,
        brand_id: Optional[str] = None,
        merchant_id: Optional[str] = None,
        total_products_from: Optional[int] = None,
        total_products_to: Optional[int] = None,
        sales_from: Optional[int] = None,
        sales_to: Optional[int] = None,
        gmv_from: Optional[float] = None,
        gmv_to: Optional[float] = None,
        competition_from: Optional[float] = None,
        competition_to: Optional[float] = None,
        search_volume_from: Optional[int] = None,
        search_volume_to: Optional[int] = None,
        phrase_id: Optional[str] = None,
        sort: Optional[str] = None,
        after: int = 0,
        limit: int = 10
) -> dict:
    data = {"mall": mall, "after": after, "limit": limit}

    if suggest is not None:
        data["suggest"] = suggest
    if suggest_exact is not None:
        data["suggestExact"] = suggest_exact
    if category_id is not None:
        data["categoryId"] = [int(x) for x in category_id.split(",")]
    if brand_id is not None:
        data["brandId"] = [int(x) for x in brand_id.split(",")]
    if merchant_id is not None:
        data["merchantId"] = [int(x) for x in merchant_id.split(",")]
    if total_products_from is not None:
        data["totalProductsFrom"] = total_products_from
    if total_products_to is not None:
        data["totalProductsTo"] = total_products_to
    if sales_from is not None:
        data["salesFrom"] = sales_from
    if sales_to is not None:
        data["salesTo"] = sales_to
    if gmv_from is not None:
        data["gmvFrom"] = gmv_from
    if gmv_to is not None:
        data["gmvTo"] = gmv_to
    if competition_from is not None:
        data["competitionFrom"] = competition_from
    if competition_to is not None:
        data["competitionTo"] = competition_to
    if search_volume_from is not None:
        data["searchVolumeFrom"] = search_volume_from
    if search_volume_to is not None:
        data["searchVolumeTo"] = search_volume_to
    if phrase_id is not None:
        data["phraseId"] = [int(x) for x in phrase_id.split(",")]
    if sort is not None:
        data["sort"] = sort

    r = httpx.post(f"{BASE_URL}/keyword/list", data=data)
    return r.json()


@mcp.tool(name="get_keyword_quantiles", description="""
    Получает квантили кейвордов.

    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
        metric: Список метрик через запятую
        quantile: Список значений квантилей через запятую (значения от 0 до 1)
    """)
def get_keyword_quantiles(
        mall: str,
        metric: Optional[str] = None,
        quantile: Optional[str] = None
) -> dict:
    data = {"mall": mall}

    if metric is not None:
        data["metric"] = metric.split(",")
    if quantile is not None:
        data["quantile"] = [float(x) for x in quantile.split(",")]

    r = httpx.post(f"{BASE_URL}/keyword/quantiles", data=data)
    return r.json()


@mcp.tool(name="get_keyword_graph", description="""
    Получает графики кейворда.

    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
        id: ID кейворда
    """)
def get_keyword_graph(mall: str, id: int) -> dict:
    data = {"mall": mall, "id": id}

    r = httpx.post(f"{BASE_URL}/keyword/graph", data=data)
    return r.json()


@mcp.tool(name="get_keyword_brands", description="""
    Получает список брендов для кейворда.

    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
        phrase_id: ID фразы (кейворда)
    """)
def get_keyword_brands(mall: str, phrase_id: int) -> dict:
    data = {"mall": mall, "phraseId": phrase_id}

    r = httpx.post(f"{BASE_URL}/keyword/brands", data=data)
    return r.json()


@mcp.tool(name="get_keyword_merchants", description="""
    Получает список мерчей (продавцов) для кейворда.

    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
        phrase_id: ID фразы (кейворда)
    """)
def get_keyword_merchants(mall: str, phrase_id: int) -> dict:
    data = {"mall": mall, "phraseId": phrase_id}

    r = httpx.post(f"{BASE_URL}/keyword/merchants", data=data)
    return r.json()


@mcp.tool(name="get_malls", description="Список маркетплейсов для анализа")
def get_malls() -> dict:
    """
    Получает список маркетплейсов для анализа.
    """
    r = httpx.get(f"{BASE_URL}/malls")
    return r.json()


@mcp.tool(name="get_stat_summary", description="Данные о кол-ве сущностей для аналитики на марктеплейсах")
def get_stat_summary() -> dict:
    """
    Получает данные о количестве сущностей для аналитики на маркетплейсах.
    """
    r = httpx.get(f"{BASE_URL}/stat/summary")
    return r.json()


@mcp.tool(name="get_category_stat", description="""
    Получает агрегатные данные категорий. Это именно данные в целом по категориям, без товаров.
    Можно фильтровать по брендам и/или продавцам, чтобы узнать сумму их продаж в целом за период или в конкретных категориях.
    

    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
        from_time: Начало временного интервала (timestamp)
        to_time: Конец временного интервала (timestamp)
        with_prev: Нужен ли предыдущий период в ответе (bool)
        brand_id: Список ID брендов через запятую
        category_id: ID категории
        merchant_id: Список ID магазинов через запятую
        product_id: Список ID товаров через запятую
        group_categories: Группировать по категориям - отображать дерево категорий с продажами (использование исключает группировку (одновременное использование) по брендам и мерчантам(магазинам))
        group_brands: Группировать по брендам (bool) - отображать список брендов с продажами в выбранной категории (category_id) или в целом на площадке (использование исключает группировку по категориям и магазинам(мерчантам))
        group_merchants: Группировать по мерчам (bool) - отображать список магазинов с продажами в выбранной категрии (category_id) или в целом на площадке (использование исключает группировку по категориям и брендам)
        after: Вернуть следующие элементы после заданного
        limit: Вернуть заданное число элементов
        stats_fields: Список ключей из блока "current", которые нужно оставить в ответе.
            Например: ["sales", "gmv", "productsSales"]. Если не указано — возвращаются все поля.
        inventory_type: Тип модели по которой реализовывались товары 
            для Ozon
                FBO = 2 если выбрана площадка озон и запрос показать продажи со склада озона
                FBS = 1 если выбрана площадка озон и запрос показать продажи со склада селлера
            для Wb
                FBW = 1 если выбрана площадка ВБ и запрос показать продажи со склада ВБ
                FBS = 2 если выбрана площадка ВБ и запрос показать продажи со склада селлера
                FBW+FBW = marketplace если выбран ВБ, но надо посмотреть продажи по всем моделям продаж
        include_ids: Возвращать ли brandId / merchantId и categoryId в ответе.
                По умолчанию False — возвращаются только имена брендов или магазинов.

    """)
def get_category_stat(
        mall: str,
        from_time: int,
        to_time: int,
        with_prev: Optional[bool] = None,
        brand_id: Optional[str] = None,
        category_id: Optional[int] = None,
        merchant_id: Optional[str] = None,
        product_id: Optional[str] = None,
        group_categories: Optional[bool] = None,
        group_brands: Optional[bool] = None,
        group_merchants: Optional[bool] = None,
        after: int = 0,
        limit: int = 10,
        inventory_type: Optional[int] = None,
        stats_fields: Optional[List[str]] = None,  # <-- ВСТАВИТЬ ЗДЕСЬ
        include_ids: bool = False,  # <-- ВСТАВИТЬ ЗДЕСЬ
) -> dict:
    data = {
        "mall": mall,
        "from": from_time,
        "to": to_time,
        "after": after,
        "limit": limit
    }

    def filter_current(data: dict, allowed_fields: Optional[List[str]]) -> dict:
        if not allowed_fields:
            return data
        return {k: v for k, v in data.items() if k in allowed_fields}

    if with_prev is not None:
        data["withPrev"] = with_prev
    if brand_id is not None:
        data["brandId"] = [int(x) for x in brand_id.split(",")]
    if category_id is not None:
        data["categoryId"] = category_id
    if merchant_id is not None:
        data["merchantId"] = [int(x) for x in merchant_id.split(",")]
    if product_id is not None:
        data["productId"] = [int(x) for x in product_id.split(",")]
    if group_categories is not None:
        data["groupCategories"] = group_categories
    if group_brands is not None:
        data["groupBrands"] = group_brands
    if group_merchants is not None:
        data["groupMerchants"] = group_merchants
    if inventory_type is not None:
        data["inventoryType"] = inventory_type

    r = httpx.post(f"{BASE_URL}/category/stat", data=data)
    response = r.json()  # сначала распарсим JSON
    return response
    # if group_categories:
    #     payload = response.get("payload", {})
    #     filtered = {"categories": [], "dict": {"categories": {}}}

    #     for cat in payload.get("data", {}).get("categories", []):
    #         filtered_cat = {
    #             "categoryId": cat.get("categoryId"),
    #             "current": {
    #                 "sales": cat.get("current", {}).get("sales"),
    #                 "gmv": cat.get("current", {}).get("gmv"),
    #                 "productsSales": cat.get("current", {}).get("productsSales"),
    #             }
    #         }
    #         filtered["categories"].append(filtered_cat)

    #     for cat_id, cat_info in payload.get("dict", {}).get("categories", {}).items():
    #         filtered["dict"]["categories"][cat_id] = {
    #             "id": cat_info.get("id"),
    #             "name": cat_info.get("name")
    #         }
    #     return filtered

    # elif group_brands:
    #     payload = response.get("payload", {})
    #     brand_dict = payload.get("dict", {}).get("brands", {})
    #     result = []

    #     for brand in payload.get("data", {}).get("brands", []):
    #         brand_id = brand.get("brandId")
    #         item = {
    #             "brand": brand_dict.get(str(brand_id), {}).get("name", ""),
    #             "current": filter_current(brand.get("current", {}), stats_fields)
    #         }
    #         if include_ids:
    #             item["brandId"] = brand_id
    #             item["categoryId"] = brand.get("categoryId")
    #         result.append(item)

    #     return {"brands": result}

    # elif group_merchants:
    #     payload = response.get("payload", {})
    #     merch_dict = payload.get("dict", {}).get("merchants", {})
    #     result = []

    #     for merch in payload.get("data", {}).get("merchants", []):
    #         merch_id = merch.get("merchantId")
    #         item = {
    #             "merchant": merch_dict.get(str(merch_id), {}).get("name", ""),
    #             "current": filter_current(merch.get("current", {}), stats_fields)
    #         }
    #         if include_ids:
    #             item["merchantId"] = merch_id
    #             item["categoryId"] = merch.get("categoryId")
    #         result.append(item)

    #     return {"merchants": result}

    # else:
    #    return response


#   response=r.json().get("payload")
#   data.pop("previous")
# ba   data.pop("categories")

#   return {
#   "data": data,
#   "categories_dict": response.get("dict"),
#  }

#   return response


@mcp.tool(name="get_product_metrics", description="""
    Получает метрики товара.

    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
        from_time: Начало временного интервала (timestamp)
        to_time: Конец временного интервала (timestamp)
        id: Список ID товаров через запятую
        inventory_type: Список типов инвентаря через запятую. Возможные значения: 1 (FBS - Fulfillment by Seller), 2 (FBO - Fulfillment by Operator)
    """)
def get_product_metrics(
        mall: str,
        from_time: int,
        to_time: int,
        id: str,
        inventory_type: Optional[str] = None
) -> dict:
    data = {"mall": mall, "from": from_time, "to": to_time, "id": [int(x) for x in id.split(",")]}

    if inventory_type is not None:
        data["inventoryType"] = [int(x) for x in inventory_type.split(",")]

    r = httpx.post(f"{BASE_URL}/product/metrics", data=data)
    return r.json()


# @mcp.tool(name="get_category_graph", description= """
#     Получает данные по агрегатам категорий для графика.

#     Args:
#         mall: Код витрины (обязательный), получить из метода @get_malls
#         from_time: Начало временного интервала (timestamp)
#         to_time: Конец временного интервала (timestamp)
#         category_id: ID категории
#         brand_id: Список ID брендов через запятую
#         merchant_id: Список ID магазинов через запятую
#         metric: Список метрик через запятую
#         inventory_type: Тип инвентаря Возможные значения: 1 (FBS - Fulfillment by Seller), 2 (FBO - Fulfillment by Operator), inventoryType=marketplace (FBO+FBS)
#         aggregate_by: Агрегация по времени. Возможные значения: 'week' — по неделям, 'month' — по месяцам, None — без агрегации (по дням)
#     """)
# def get_category_graph(
#         mall: str,
#         from_time: int,
#         to_time: int,
#         category_id: Optional[int] = None,
#         brand_id: Optional[str] = None,
#         merchant_id: Optional[str] = None,
#         metric: Optional[str] = None,
#         inventory_type: Optional[int] = None,
#         aggregate_by: Optional[str] = None
# ) -> dict:

#     data = {"mall": mall, "from": from_time, "to": to_time}

#     if category_id is not None:
#         data["categoryId"] = category_id
#     if brand_id is not None:
#         data["brandId"] = [int(x) for x in brand_id.split(",")]
#     if merchant_id is not None:
#         data["merchantId"] = [int(x) for x in merchant_id.split(",")]
#     if metric is not None:
#         data["metric"] = metric.split(",")
#     if inventory_type is not None:
#         data["inventoryType"] = inventory_type

#     r = httpx.post(f"{BASE_URL}/category/graph", data=data)
#     response = r.json()
#     if aggregate_by not in {"week", "month", None}:
#         return {"error": "Неверное значение aggregate_by, используйте 'week', 'month' или None"}

#     if aggregate_by:
#         import pandas as pd
#         from datetime import datetime

#         ts_data = response.get("payload", {}).get("ts", [])
#         df = pd.DataFrame([
#             {
#                 "ts": datetime.fromtimestamp(item["tsFrom"]),
#                 "gmv": item["current"]["gmv"],
#                 "brandsTotal": item["current"]["brandsTotal"],
#                 "merchantsTotal": item["current"]["merchantsTotal"]
#             }
#             for item in ts_data
#         ])

#         if aggregate_by == "week":
#             df["period"] = df["ts"].dt.to_period("W").apply(lambda x: x.start_time)
#         elif aggregate_by == "month":
#             df["period"] = df["ts"].dt.to_period("M").apply(lambda x: x.start_time)

#         agg_df = df.groupby("period").sum(numeric_only=True).reset_index()
#         response["aggregated"] = agg_df.to_dict(orient="records")
# #        response = agg_df.to_dict(orient="records")
#     return response
#  #   return r.json()

@mcp.tool(name="get_category_graph", description="""
    Получает данные по агрегатам категорий для графика.
    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
        from_time: Начало временного интервала (timestamp)
        to_time: Конец временного интервала (timestamp)
        category_id: ID категории
        brand_id: Список ID брендов через запятую
        merchant_id: Список ID магазинов через запятую
        metric: Список метрик через запятую. Доступные метрики:
            - gmv: Выручка
            - sales: Количество проданных единиц товара
            - brandsTotal: Общее количество брендов
            - merchantsTotal: Общее количество продавцов
            - productsAvail: Количество доступных товаров
            - productsSales: Количество проданных товаров (артикулов)
            - inventoryAvg: Средний остаток товаров
            - priceAvg: Средняя цена
            - reviewCount: Количество отзывов
            - ratingAvg: Средний рейтинг
            - ratingDistr: Распределение оценок по звездам
        inventory_type: Тип инвентаря Возможные значения: 1 (FBS - Fulfillment by Seller), 2 (FBO - Fulfillment by Operator), inventoryType=marketplace (FBO+FBS)
        aggregate_by: Агрегация по времени. Возможные значения: 'week' — по неделям, 'month' — по месяцам, 'day' — по дням
    """)
def get_category_graph(
        mall: str,
        from_time: int,
        to_time: int,
        category_id: Optional[int] = None,
        brand_id: Optional[str] = None,
        merchant_id: Optional[str] = None,
        metric: Optional[str] = None,
        inventory_type: Optional[int] = None,
        aggregate_by: Optional[str] = None
) -> dict:
    # Проверка корректности параметра aggregate_by
    if aggregate_by is not None and aggregate_by not in {"day", "week", "month"}:
        return {"error": "Неверное значение aggregate_by, используйте 'day', 'week', 'month' или None"}

    # Подготовка данных для запроса
    data = {"mall": mall, "from": from_time, "to": to_time}

    if category_id is not None:
        data["categoryId"] = category_id

    if brand_id is not None:
        try:
            data["brandId"] = [int(x.strip()) for x in brand_id.split(",")]
        except ValueError:
            return {"error": "Неверный формат brand_id, используйте числа через запятую"}

    if merchant_id is not None:
        try:
            data["merchantId"] = [int(x.strip()) for x in merchant_id.split(",")]
        except ValueError:
            return {"error": "Неверный формат merchant_id, используйте числа через запятую"}

    if metric is not None:
        data["metric"] = [x.strip() for x in metric.split(",")]

    if inventory_type is not None:
        data["inventoryType"] = inventory_type

    # Выполнение запроса
    r = httpx.post(f"{BASE_URL}/category/graph", data=data)
    response = r.json()

    # Если требуется агрегация и есть данные
    if aggregate_by and "payload" in response and "ts" in response["payload"]:
        ts_data = response["payload"]["ts"]
        aggregated_data = {}

        # Импортируем datetime только если нужна агрегация
        from datetime import datetime, timedelta

        # Определим, какие метрики нужно суммировать, а какие усреднять
        sum_metrics = {
            "gmv", "sales", "reviewCount", "productsSales",
        }

        max_metrics = {
            "brandsTotal", "merchantsTotal", "productsAvail",
        }

        avg_metrics = {
            "inventoryAvg", "priceAvg", "ratingAvg",
        }

        # Для вычисления средних значений нам нужно хранить суммы и количество точек
        metric_counts = {}
        metric_sums = {}

        for item in ts_data:
            # Преобразуем timestamp в datetime
            dt = datetime.fromtimestamp(item["tsFrom"])

            # Определяем ключ периода в зависимости от типа агрегации
            if aggregate_by == "day":
                # Начало дня
                period_key = dt.strftime("%Y-%m-%d")
            elif aggregate_by == "week":
                # Начало недели (понедельник)
                start_of_week = dt - timedelta(days=dt.weekday())
                period_key = start_of_week.strftime("%Y-%m-%d")
            elif aggregate_by == "month":
                # Начало месяца
                period_key = dt.strftime("%Y-%m-01")

            # Если период ещё не существует в словаре, создаём его
            if period_key not in aggregated_data:
                aggregated_data[period_key] = {
                    "period": period_key
                }
                metric_counts[period_key] = {}
                metric_sums[period_key] = {}

                # Инициализируем метрики в зависимости от типа агрегации
                current = item.get("current", {})
                for metric_key in current.keys():
                    if metric_key == "ratingDistr":
                        aggregated_data[period_key][metric_key] = [0, 0, 0, 0, 0]
                    elif metric_key in sum_metrics or metric_key in max_metrics:
                        aggregated_data[period_key][metric_key] = 0
                    elif metric_key in avg_metrics:
                        metric_counts[period_key][metric_key] = 0
                        metric_sums[period_key][metric_key] = 0

            # Обрабатываем метрики
            current = item.get("current", {})
            for metric_key, metric_value in current.items():
                # Пропускаем метрики, которые не являются числами или массивами
                if not isinstance(metric_value, (int, float, list)):
                    continue

                # Инициализируем метрику, если она еще не существует
                if metric_key not in aggregated_data[period_key]:
                    if metric_key == "ratingDistr":
                        aggregated_data[period_key][metric_key] = [0, 0, 0, 0, 0]
                    elif metric_key in sum_metrics or metric_key in max_metrics:
                        aggregated_data[period_key][metric_key] = 0
                    elif metric_key in avg_metrics:
                        metric_counts[period_key][metric_key] = 0
                        metric_sums[period_key][metric_key] = 0

                # Обрабатываем метрику в зависимости от типа
                if metric_key == "ratingDistr" and isinstance(metric_value, list):
                    # Суммируем распределения оценок поэлементно
                    for i in range(min(len(metric_value), len(aggregated_data[period_key][metric_key]))):
                        aggregated_data[period_key][metric_key][i] += metric_value[i]

                elif metric_key in sum_metrics:
                    # Суммируем значения для метрик типа "сумма"
                    aggregated_data[period_key][metric_key] += metric_value

                elif metric_key in max_metrics:
                    # Берем максимальное значение для метрик типа "максимум"
                    aggregated_data[period_key][metric_key] = max(
                        aggregated_data[period_key][metric_key], metric_value
                    )

                elif metric_key in avg_metrics:
                    # Для средних значений накапливаем сумму и количество
                    metric_sums[period_key][metric_key] += metric_value
                    metric_counts[period_key][metric_key] += 1

        # Вычисляем средние значения
        for period_key in aggregated_data:
            for metric_key in avg_metrics:
                if metric_key in metric_sums[period_key] and metric_counts[period_key][metric_key] > 0:
                    aggregated_data[period_key][metric_key] = round(
                        metric_sums[period_key][metric_key] / metric_counts[period_key][metric_key], 2
                    )

        # Преобразуем словарь в список для более удобного формата
        response["aggregated"] = list(aggregated_data.values())
        return response["aggregated"]

    return response


@mcp.tool(name="get_archive_product_warehouse_inventory",
          description="""
    Получает временные отметки с количеством товара на складе.

    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
        product_id: ID продукта
        variation_id: ID варианта
        warehouse_id: ID склада
        from_time: Начало временного интервала (timestamp)
        to_time: Конец временного интервала (timestamp)
    """)
def get_archive_product_warehouse_inventory(
        mall: str,
        product_id: int,
        variation_id: Optional[int] = None,
        warehouse_id: Optional[str] = None,
        from_time: Optional[int] = None,
        to_time: Optional[int] = None
) -> dict:
    data = {"mall": mall, "productId": product_id}

    if variation_id is not None:
        data["variationId"] = variation_id
    if warehouse_id is not None:
        data["warehouseId"] = warehouse_id
    if from_time is not None:
        data["from"] = from_time
    if to_time is not None:
        data["to"] = to_time

    r = httpx.post(f"{BASE_URL}/archive/product/warehouse/inventory", data=data)
    return r.json()


@mcp.tool(name="get_archive_product_warehouse_sales", description="""
    Получает временные отметки с продажами на складе.

    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
        product_id: ID продукта
        variation_id: ID варианта
        warehouse_id: ID склада
        from_time: Начало временного интервала (timestamp)
        to_time: Конец временного интервала (timestamp)
    """)
def get_archive_product_warehouse_sales(
        mall: str,
        product_id: int,
        variation_id: Optional[int] = None,
        warehouse_id: Optional[int] = None,
        from_time: Optional[int] = None,
        to_time: Optional[int] = None
) -> dict:
    data = {"mall": mall, "productId": product_id}

    if variation_id is not None:
        data["variationId"] = variation_id
    if warehouse_id is not None:
        data["warehouseId"] = warehouse_id
    if from_time is not None:
        data["from"] = from_time
    if to_time is not None:
        data["to"] = to_time

    r = httpx.post(f"{BASE_URL}/archive/product/warehouse/sales", data=data)
    return r.json()


@mcp.tool(name="get_archive_product_warehouse_balance", description="""
    Получает остатки товаров по складам.

    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
        product_id: Список ID продуктов через запятую
    """)
def get_archive_product_warehouse_balance(
        mall: str,
        product_id: Optional[str] = None
) -> dict:
    data = {"mall": mall}

    if product_id is not None:
        data["productId"] = product_id

    r = httpx.post(f"{BASE_URL}/archive/product/warehouse/balance", data=data)
    return r.json()


@mcp.tool(name="get_archive_product_similar", description="""
    Получает список похожих товаров.

    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
        id: Список ID продуктов через запятую
    """)
def get_archive_product_similar(
        mall: str,
        id: str
) -> dict:
    data = {"mall": mall, "id": [int(x) for x in id.split(",")]}

    r = httpx.post(f"{BASE_URL}/archive/product/similar", data=data)
    return r.json()


@mcp.tool(name="get_archive_variation_data", description="""
    Получает исторические данные о вариантах товара.

    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
        product_id: ID продукта
        variation_id: ID варианта
        from_time: Начало временного интервала (timestamp)
        to_time: Конец временного интервала (timestamp)
    """)
def get_archive_variation_data(
        mall: str,
        product_id: int,
        variation_id: int,
        from_time: Optional[int] = None,
        to_time: Optional[int] = None
) -> dict:
    data = {"mall": mall, "productId": product_id, "variationId": variation_id}

    if from_time is not None:
        data["from"] = from_time
    if to_time is not None:
        data["to"] = to_time

    r = httpx.post(f"{BASE_URL}/archive/variation/data", data=data)
    return r.json()


@mcp.tool(name="get_archive_variation_sales", description="""
    Получает исторические данные о продажах варианта товара.

    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
        variation_id: ID варианта
        from_time: Начало временного интервала (timestamp)
        to_time: Конец временного интервала (timestamp)
    """)
def get_archive_variation_sales(
        mall: str,
        variation_id: int,
        from_time: Optional[int] = None,
        to_time: Optional[int] = None
) -> dict:
    data = {"mall": mall, "variationId": variation_id}

    if from_time is not None:
        data["from"] = from_time
    if to_time is not None:
        data["to"] = to_time

    r = httpx.post(f"{BASE_URL}/archive/variation/sales", data=data)
    return r.json()


@mcp.tool(name="get_archive_product_content", description="""
    Получает исторические данные об изменениях контента товара.

    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
        id: ID продукта
        from_time: Начало временного интервала (timestamp)
        to_time: Конец временного интервала (timestamp)
    """)
def get_archive_product_content(
        mall: str,
        id: int,
        from_time: Optional[int] = None,
        to_time: Optional[int] = None
) -> dict:
    data = {"mall": mall, "id": id}

    if from_time is not None:
        data["from"] = from_time
    if to_time is not None:
        data["to"] = to_time

    r = httpx.post(f"{BASE_URL}/archive/product/content", data=data)
    return r.json()


@mcp.tool(name="get_archive_product_names", description="""
    Получает исторические данные об изменениях названия товара.

    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
        id: ID продукта
    """)
def get_archive_product_names(
        mall: str,
        id: int
) -> dict:
    data = {"mall": mall, "id": id}

    r = httpx.post(f"{BASE_URL}/archive/product/names", data=data)
    return r.json()


@mcp.tool(name="get_archive_product_suggestion", description="""
    Получает саджесты (предложения) для товаров. Ищет похожие товары на заданный товар. Результат надо выборочно перероверять.

    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
        id: Список ID продуктов через запятую
    """)
def get_archive_product_suggestion(
        mall: str,
        id: str
) -> dict:
    data = {"mall": mall, "id": [int(x) for x in id.split(",")]}

    r = httpx.post(f"{BASE_URL}/archive/product/suggestion", data=data)
    return r.json()


@mcp.tool(name="get_archive_product_reviews",
          description="""
    Получает исторические данные о количестве отзывов товара (витринная метрика).

    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
        id: ID продукта
        from_time: Начало временного интервала (timestamp)
        to_time: Конец временного интервала (timestamp)
    """)
def get_archive_product_reviews(
        mall: str,
        id: int,
        from_time: Optional[int] = None,
        to_time: Optional[int] = None
) -> dict:
    data = {"mall": mall, "id": id}

    if from_time is not None:
        data["from"] = from_time
    if to_time is not None:
        data["to"] = to_time

    r = httpx.post(f"{BASE_URL}/archive/product/reviews", data=data)
    return r.json()


@mcp.tool(name="get_category_last_date", description="""
    Получает дату последнего обсчета агрегатов категорий.

    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
    """)
def get_category_last_date(mall: str) -> dict:
    data = {"mall": mall}

    r = httpx.post(f"{BASE_URL}/category/lastDate", data=data)
    return r.json()


@mcp.tool(name="get_archive_product_msrp", description="""
    Получает исторические данные о цене без скидки товара (MSRP).

    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
        id: ID продукта
        from_time: Начало временного интервала (timestamp)
        to_time: Конец временного интервала (timestamp)
    """)
def get_archive_product_msrp(
        mall: str,
        id: int,
        from_time: Optional[int] = None,
        to_time: Optional[int] = None
) -> dict:
    data = {"mall": mall, "id": id}

    if from_time is not None:
        data["from"] = from_time
    if to_time is not None:
        data["to"] = to_time

    r = httpx.post(f"{BASE_URL}/archive/product/msrp", data=data)
    return r.json()


@mcp.tool(name="get_archive_product_discount", description="""
    Получает исторические данные о ценах со скидкой маркетплейса товара.

    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
        id: ID продукта
        from_time: Начало временного интервала (timestamp)
        to_time: Конец временного интервала (timestamp)
    """)
def get_archive_product_discount(
        mall: str,
        id: int,
        from_time: Optional[int] = None,
        to_time: Optional[int] = None
) -> dict:
    data = {"mall": mall, "id": id}

    if from_time is not None:
        data["from"] = from_time
    if to_time is not None:
        data["to"] = to_time

    r = httpx.post(f"{BASE_URL}/archive/product/discount", data=data)
    return r.json()


@mcp.tool(name="get_products_description", description="""
    Получает актуальные тексты описаний для группы товаров.
    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
        id: Список ID товаров через запятую
    """)
def get_products_description(mall: str, id: str) -> dict:
    products_ids = [int(x) for x in id.split(",") if x.strip()]
    result = {}

    for product_id in products_ids:
        versions_resp = get_archive_product_description_version(
            mall=mall, id=product_id
        ) or {}

        timestamps = []
        payload = versions_resp.get("payload")
        if isinstance(payload, list):
            timestamps = payload

        if not timestamps:
            result[product_id] = None
            continue

        latest_ts = max(timestamps)

        text_resp = get_archive_product_description_text(
            mall=mall, id=product_id, ts=str(latest_ts)
        ) or {}

        description = None
        payload = text_resp.get("payload")

        if isinstance(payload, dict):
            value = payload.get(str(latest_ts))
            if isinstance(value, str):
                description = value

        result[product_id] = description
    return result

def get_archive_product_description_version(
        mall: str,
        id: int
) -> dict:
    data = {"mall": mall, "id": id}

    r = httpx.post(f"{BASE_URL}/archive/product/description/version", data=data)
    return r.json()

def get_archive_product_description_text(
        mall: str,
        id: int,
        ts: Optional[str] = None
) -> dict:
    data = {"mall": mall, "id": id}

    if ts is not None:
        data["ts"] = [int(x) for x in ts.split(",")]

    r = httpx.post(f"{BASE_URL}/archive/product/description/text", data=data)
    return r.json()


@mcp.tool(name="get_category_price", description="""
    Получает разбивку цен товаров в категории.

    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
        category_id: Список ID категорий через запятую
        brand_id: Список ID брендов через запятую
        merchant_id: Список ID магазинов через запятую
        from_time: Начало временного интервала (timestamp)
        to_time: Конец временного интервала (timestamp)
        inventory_type: Тип инвентаря Возможные значения: 1 (FBS - Fulfillment by Seller), 2 (FBO - Fulfillment by Operator)
    """)
def get_category_price(
        mall: str,
        category_id: str,
        brand_id: Optional[str] = None,
        merchant_id: Optional[str] = None,
        from_time: Optional[int] = None,
        to_time: Optional[int] = None,
        inventory_type: Optional[int] = None
) -> dict:
    data = {"mall": mall, "categoryId": [int(x) for x in category_id.split(",")]}

    if brand_id is not None:
        data["brandId"] = [int(x) for x in brand_id.split(",")]
    if merchant_id is not None:
        data["merchantId"] = [int(x) for x in merchant_id.split(",")]
    if from_time is not None:
        data["from"] = from_time
    if to_time is not None:
        data["to"] = to_time
    if inventory_type is not None:
        data["inventoryType"] = inventory_type

    r = httpx.post(f"{BASE_URL}/category/price", data=data)
    return r.json()


@mcp.tool(name="get_characteristic_suggest_available", description="""
    Получает доступные характеристики для товаров.

    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
        id: Список ID продуктов через запятую
        category_id: Список ID категорий через запятую
        brand_id: Список ID брендов через запятую
        merchant_id: Список ID магазинов через запятую
        price_min_from: Минимальная цена от
        price_min_to: Минимальная цена до
        kwargs: Дополнительные параметры в формате JSON строки, здесь можно использовать все фильтры из get_product_list
    """)
def get_characteristic_suggest_available(
        mall: str,
        id: Optional[str] = None,
        category_id: Optional[str] = None,
        brand_id: Optional[str] = None,
        merchant_id: Optional[str] = None,
        price_min_from: Optional[float] = None,
        price_min_to: Optional[float] = None,
        kwargs: str = "{}"
) -> dict:
    data = {"mall": mall}

    if id is not None:
        data["id"] = [int(x) for x in id.split(",")]
    if category_id is not None:
        data["categoryId"] = [int(x) for x in category_id.split(",")]
    if brand_id is not None:
        data["brandId"] = [int(x) for x in brand_id.split(",")]
    if merchant_id is not None:
        data["merchantId"] = [int(x) for x in merchant_id.split(",")]
    if price_min_from is not None:
        data["priceMinFrom"] = price_min_from
    if price_min_to is not None:
        data["priceMinTo"] = price_min_to

    # Добавление дополнительных параметров из kwargs
    import json
    extra_params = json.loads(kwargs)
    for key, value in extra_params.items():
        if key not in data:
            data[key] = value

    r = httpx.post(f"{BASE_URL}/characteristic/suggest/available", data=data)
    return r.json()


@mcp.tool(name="get_characteristic_suggest_value", description="""
    Получает значения характеристик товаров.

    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
        characteristic_code: Код характеристики
        id: Список ID продуктов через запятую
        category_id: Список ID категорий через запятую
        brand_id: Список ID брендов через запятую
        merchant_id: Список ID магазинов через запятую
        kwargs: Дополнительные параметры в формате JSON строки, здесь можно использовать все фильтры из get_product_list
    """)
def get_characteristic_suggest_value(
        mall: str,
        characteristic_code: str,
        id: Optional[str] = None,
        category_id: Optional[str] = None,
        brand_id: Optional[str] = None,
        merchant_id: Optional[str] = None,
        kwargs: str = "{}"
) -> dict:
    data = {"mall": mall, "characteristicCode": characteristic_code}

    if id is not None:
        data["id"] = [int(x) for x in id.split(",")]
    if category_id is not None:
        data["categoryId"] = [int(x) for x in category_id.split(",")]
    if brand_id is not None:
        data["brandId"] = [int(x) for x in brand_id.split(",")]
    if merchant_id is not None:
        data["merchantId"] = [int(x) for x in merchant_id.split(",")]

    # Добавление дополнительных параметров из kwargs
    import json
    extra_params = json.loads(kwargs)
    for key, value in extra_params.items():
        if key not in data:
            data[key] = value

    r = httpx.post(f"{BASE_URL}/characteristic/suggest/value", data=data)
    return r.json()


@mcp.tool(name="get_feed_overall", description="""
    Получает общие ленты для товаров. Использовать только в том случае если сравниваем два и более продукта одного или несколькиз брендов.

    Args:
        mall: Код витрины (обязательный), получить из метода @get_malls
        product_id: Список ID продуктов через запятую
        feed_type: Тип ленты (1 - категория, 2 - магазин, 3 - фраза, 4 - бренд)
        match_count: Количество совпадений
    """)
def get_feed_overall(
        mall: str,
        product_id: str,
        feed_type: Optional[int] = None,
        match_count: Optional[int] = None
) -> dict:
    data = {"mall": mall, "productId": [int(x) for x in product_id.split(",")]}

    if feed_type is not None:
        data["feedType"] = feed_type
    if match_count is not None:
        data["matchCount"] = match_count

    r = httpx.post(f"{BASE_URL}/feed/overall", data=data)
    return r.json()


# Запуск сервера
if __name__ == "__main__":
    mcp.run(transport="sse")

# Альтернативный запуск сервера
#if __name__ == "__main__":
#    import uvicorn
#
#    uvicorn.run("main:mcp.app", host="0.0.0.0", port=8080)
