"""Pydantic-модели для входных параметров и выходных результатов инструментов."""

from datetime import date
from typing import Literal

from pydantic import BaseModel, Field


class PaginationParams(BaseModel):
    """Базовая пагинация."""

    limit: int = Field(
        default=20,
        ge=1,
        le=100,
        description=(
            "Количество результатов на странице. "
            "Если total > limit, используй offset+=limit для следующей страницы."
        ),
    )
    offset: int = Field(
        default=0,
        ge=0,
        description="Смещение для пагинации. Следующая страница: offset += limit.",
    )


class MetadataFilters(BaseModel):
    """Фильтры по метаданным, общие для всех инструментов поиска.

    Все фильтры объединяются через AND. Если результатов мало — попробуй убрать
    1–2 фильтра (обычно district или metro_station).
    """

    deal_type: Literal["sale", "rent_long", "rent_short"] | None = Field(
        default=None,
        description=(
            "Тип сделки: sale=продажа, rent_long=долгосрочная аренда, "
            "rent_short=посуточная"
        ),
    )
    city: str | None = Field(
        default=None,
        description=(
            "Город на украинском языке. Поиск по подстроке (ILIKE) — "
            "достаточно части названия, например 'Київ' или 'Львів'. Регистр не важен."
        ),
    )
    district: str | None = Field(
        default=None,
        description=(
            "Район на украинском языке. Поиск по подстроке (ILIKE). "
            "Примеры: 'Печерський', 'Шевченківський', 'Галицький'."
        ),
    )
    rooms_count: int | None = Field(
        default=None,
        ge=0,
        description="Количество комнат. 0 = студия, 1 = 1-комнатная и т.д.",
    )
    min_price: float | None = Field(
        default=None,
        ge=0,
        description=(
            "Минимальная цена. Обязательно указывай currency вместе с min_price/max_price, "
            "иначе фильтр применится ко всем валютам одновременно."
        ),
    )
    max_price: float | None = Field(
        default=None,
        ge=0,
        description="Максимальная цена. Указывай вместе с currency.",
    )
    currency: Literal["USD", "EUR", "UAH"] | None = Field(
        default=None,
        description="Валюта цены. Обязательна при использовании min_price/max_price.",
    )
    min_total_area: float | None = Field(
        default=None,
        ge=0,
        description="Минимальная общая площадь, м².",
    )
    max_total_area: float | None = Field(
        default=None,
        ge=0,
        description="Максимальная общая площадь, м².",
    )
    building_type: Literal["brick", "panel", "monolith", "gas_block", "wood"] | None = Field(
        default=None,
        description=(
            "Тип постройки: brick=кирпичный, panel=панельный, monolith=монолитный, "
            "gas_block=газоблок, wood=деревянный."
        ),
    )
    floor: int | None = Field(
        default=None,
        ge=0,
        description="Этаж квартиры. 0 обычно означает цоколь/подвал (если есть в базе).",
    )
    listing_status: Literal["active", "sold", "rented", "removed", "archived"] | None = Field(
        default=None,
        description="Статус объявления. По умолчанию сервер не фильтрует — включая все статусы.",
    )
    metro_station: str | None = Field(
        default=None,
        description=(
            "Станция метро на украинском. Поиск по подстроке (ILIKE). "
            "Примеры: 'Арсенальна', 'Театральна', 'Площа Ринок'. "
            "Регистр не важен."
        ),
    )


class SearchSimilarInput(BaseModel):
    """Входные параметры для векторного поиска.

    Используй, когда пользователь описывает желания, атмосферу или качества
    («уютная квартира с ремонтом у метро»), а не конкретные ключевые слова.
    """

    query: str = Field(
        ...,
        description=(
            "Текстовый запрос на украинском языке для поиска по смыслу. "
            "Формулируй конкретно, без разговорных стоп-слов. "
            "✓ Хорошо: '2-кімнатна квартира біля метро з ремонтом'. "
            "✗ Плохо: 'дай квартиру недорого' (стоп-слова)."
        ),
    )
    filters: MetadataFilters = Field(default_factory=MetadataFilters)
    pagination: PaginationParams = Field(default_factory=PaginationParams)
    # min_similarity зашит в код всегда 0.7 (широкий поиск)


class SearchMetadataInput(BaseModel):
    """Входные параметры для поиска по метаданным/FTS.

    Используй, когда пользователь называет конкретные ключевые слова:
    район, станция метро, улица, особенности ('Печерський район метро Арсенальна').
    """

    query: str = Field(
        ...,
        description=(
            "Текстовый запрос на украинском языке для полнотекстового поиска. "
            "Подходит для конкретных названий и ключевых слов. "
            "✓ Хорошо: 'Печерський район Арсенальна метро'. "
            "✗ Плохо: 'хочу квартиру' (слишком общее, используй search_similar)."
        ),
    )
    filters: MetadataFilters = Field(default_factory=MetadataFilters)
    pagination: PaginationParams = Field(default_factory=PaginationParams)
    sort_by: Literal[
        "relevance",
        "price_asc",
        "price_desc",
        "date_desc",
        "area_desc",
    ] = Field(
        default="relevance",
        description=(
            "Сортировка результатов: relevance=по релевантности FTS (умолч.), "
            "price_asc=цена по возрастанию, price_desc=цена по убыванию, "
            "date_desc=новые сверху, area_desc=большая площадь сверху."
        ),
    )


class GetListingInput(BaseModel):
    """Входные параметры для получения объявления по ID."""

    listing_id: int = Field(..., ge=1, description="ID объявления (положительное целое число).")


class ListingResult(BaseModel):
    """Результат поиска — одно объявление."""

    id: int
    title: str
    description: str | None = None
    generated_description: str | None = None
    price: float | None = None
    currency: str | None = None
    deal_type: str | None = None
    city: str | None = None
    district: str | None = None
    rooms_count: int | None = None
    total_area: float | None = None
    living_area: float | None = None
    kitchen_area: float | None = None
    floor: int | None = None
    floors_count: int | None = None
    building_type: str | None = None
    building_year: int | None = None
    renovation_status: str | None = None
    balcony_count: int | None = None
    bathroom_type: str | None = None
    parking_type: str | None = None
    heating_type: str | None = None
    layout_type: str | None = None
    window_view: str | None = None
    metro_station: str | None = None
    metro_distance_type: str | None = None
    metro_distance_meters: int | None = None
    url_source: str | None = None
    publish_date: date | None = None
    images_count: int | None = None
    contact_phone: str | None = None
    listing_status: str | None = None
    archived_at: date | None = None
    created_at: date | None = None
    updated_at: date | None = None
    similarity_score: float | None = Field(
        default=None,
        description="Косинусная близость [0..1] для search_similar_listings. "
        "1.0 = максимально похоже, 0.0 = не похоже.",
    )
    rank_score: float | None = Field(
        default=None,
        description="Релевантность FTS (ts_rank_cd) для search_by_metadata. "
        "Чем выше, тем релевантнее.",
    )


class SearchResult(BaseModel):
    """Результат поиска — список объявлений + мета.

    Если total > limit и offset + limit < total — есть ещё результаты.
    Для следующей страницы: offset += limit.
    """

    total: int = Field(description="Общее количество найденных записей (без LIMIT).")
    limit: int
    offset: int
    listings: list[ListingResult]
