# /// script
# requires-python = ">=3.12"
# dependencies = [
#     "beautifulsoup4>=4.12.0",
#     "httpx>=0.27.0",
#     "python-slugify>=8.0.4"
# ]
# ///

import asyncio
import re
import shutil
from collections import OrderedDict
from datetime import datetime, timezone
from pathlib import Path
from typing import Any, Dict, List, Optional, Tuple
from urllib.parse import urljoin

import httpx
from bs4 import BeautifulSoup
from slugify import slugify


BASE_URL = "https://mdclinica.ru"
MAIN_URL = f"{BASE_URL}/uslugi"

HTTP_HEADERS = {
    "User-Agent": (
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
        "AppleWebKit/537.36 (KHTML, like Gecko) "
        "Chrome/129.0.0.0 Safari/537.36"
    ),
    "Accept-Language": "ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7",
}

CATEGORY_SECTION_TITLES = [
    "Преимущества",
    "О процедуре",
    "Показания и Противопоказания",
    "Специалисты",
    "Фото до и после",
    "Вопрос-ответ",
    "Цены",
]

TARGET_SECTIONS = set(CATEGORY_SECTION_TITLES)

SERVICE_SECTION_TITLES = [
    "О процедуре",
    "Показания и Противопоказания",
    "Специалисты",
    "Фото до и после",
    "Вопрос-ответ",
    "Цены",
]


def normalize_url(href: Optional[str]) -> Optional[str]:
    if not href:
        return None
    return urljoin(BASE_URL, href)


def make_slug(value: Optional[str], fallback: str) -> str:
    base = value or fallback
    slug = slugify(base, lowercase=True, separator="_")
    if slug:
        return slug
    fallback_slug = slugify(fallback, lowercase=True, separator="_")
    return fallback_slug or "item"


SECTION_NAME_MAPPING = {
    "Услуги": "services",
    "Преимущества": "advantages",
    "О процедуре": "about_procedure",
    "Показания и Противопоказания": "indications",
    "Специалисты": "specialists",
    "Вопрос-ответ": "faq",
    "Цены": "prices",
    "Фото до и после": "before_after_photos",
}


def make_section_slug(value: Optional[str], fallback: str) -> str:
    """Создает slug для секции: маппит русские названия на английские."""
    base = value or fallback
    if not base:
        return fallback or "section"
    
    # Проверяем маппинг
    if base in SECTION_NAME_MAPPING:
        return SECTION_NAME_MAPPING[base]
    
    # Если нет в маппинге, используем транслитерацию
    slug = slugify(base, lowercase=True, separator="_")
    return slug if slug else (fallback or "section")


def ensure_unique_dir(base: Path, slug: str) -> Path:
    candidate = slug
    path = base / candidate
    counter = 2
    while path.exists():
        candidate = f"{slug}_{counter}"
        path = base / candidate
        counter += 1
    return path


def clean_text(value: str) -> str:
    lines = [line.strip() for line in value.splitlines()]
    filtered = [line for line in lines if line]
    return "\n".join(filtered)


def is_code(text: str) -> bool:
    """Проверяет, является ли текст CSS или JavaScript кодом."""
    if not text:
        return False
    
    # Проверяем наличие типичных CSS паттернов
    css_patterns = [
        r'\.\w+\s*\{',  # .class {
        r'#\w+\s*\{',   # #id {
        r'@media',      # @media
        r'@keyframes',  # @keyframes
        r'display\s*:',  # display:
        r'padding\s*:', # padding:
        r'margin\s*:',  # margin:
        r'width\s*:',   # width:
        r'height\s*:',   # height:
    ]
    
    # Проверяем наличие типичных JavaScript паттернов
    js_patterns = [
        r'function\s+\w+\s*\(',  # function name(
        r'\.addEventListener\s*\(',  # .addEventListener(
        r'\.querySelector\w*\s*\(',  # .querySelector(
        r'document\.',  # document.
        r'window\.',  # window.
        r'DOMContentLoaded',  # DOMContentLoaded
        r'Array\.prototype',  # Array.prototype
        r'forEach\s*\(',  # forEach(
        r'classList\.',  # classList.
    ]
    
    text_lower = text.lower()
    css_count = sum(1 for pattern in css_patterns if re.search(pattern, text_lower))
    js_count = sum(1 for pattern in js_patterns if re.search(pattern, text_lower))
    
    # Если найдено много CSS или JS паттернов, это скорее всего код
    if css_count >= 3 or js_count >= 3:
        return True
    
    # Проверяем соотношение фигурных скобок и текста
    open_braces = text.count('{')
    close_braces = text.count('}')
    if open_braces > 0 and close_braces > 0:
        # Если много фигурных скобок относительно длины текста, это может быть код
        if (open_braces + close_braces) / max(len(text), 1) > 0.05:
            return True
    
    return False


async def fetch_html(client: httpx.AsyncClient, url: str) -> str:
    response = await client.get(url, timeout=30.0)
    response.raise_for_status()
    return response.text


def extract_anchor_sections(
    html: str,
    allowed_titles: Optional[set[str]] = None,
) -> Dict[str, Dict[str, Any]]:
    soup = BeautifulSoup(html, "html.parser")
    sections: Dict[str, Dict[str, Any]] = {}

    # Ищем секции по data-anchor в div.anchor-container
    for container in soup.select("div.anchor-container"):
        section_title = container.get("data-anchor")
        section_id = container.get("id")

        if not section_title:
            continue
                    
        if allowed_titles is not None and section_title not in allowed_titles:
            continue
                    
        text = clean_text(container.get_text("\n", strip=True))
        
        # Пропускаем, если это CSS или JavaScript код
        if is_code(text):
            continue
        
        links = []

        for link in container.select("a[href]"):
            link_title = link.get_text(strip=True)
            link_href = normalize_url(link.get("href"))
            if link_href and link_title:
                links.append({
                    "title": link_title,
                    "link": link_href,
                })

        sections[section_title] = {
            "id": section_id,
            "title": section_title,
            "text": text,
            "links": links,
        }

    # Дополнительно ищем секции по id, которые соответствуют якорным ссылкам
    # Например, #about-procedure -> id="about-procedure"
    if allowed_titles is not None:
        # Маппинг английских названий якорей на русские
        anchor_mapping = {
            "about-procedure": "О процедуре",
            "about_procedure": "О процедуре",
            "advantages": "Преимущества",
            "preimushchestva": "Преимущества",
            "services": "Услуги",
            "uslugi": "Услуги",
            "indications": "Показания и Противопоказания",
            "pokazaniia": "Показания и Противопоказания",
            "specialists": "Специалисты",
            "spetsialisty": "Специалисты",
            "faq": "Вопрос-ответ",
            "vopros-otvet": "Вопрос-ответ",
            "prices": "Цены",
            "tseny": "Цены",
        }
        
        # Ищем элементы с id, которые могут быть секциями
        for element in soup.select("[id]"):
            element_id = element.get("id", "").lower()
            if not element_id:
                continue
            
            # Пропускаем элементы <style> и <script>
            if element.name in ("style", "script"):
                continue
                
            # Проверяем маппинг
            mapped_title = None
            for anchor_key, russian_title in anchor_mapping.items():
                if anchor_key in element_id or element_id == anchor_key:
                    mapped_title = russian_title
                    break
            
            # Если нашли маппинг и эта секция в списке разрешенных
            if mapped_title and mapped_title in allowed_titles:
                # Проверяем, не добавили ли мы уже эту секцию
                if mapped_title not in sections:
                    # Ищем контент секции - может быть в самом элементе или в следующем sibling
                    content_element = element
                    
                    # Если элемент пустой или содержит только заголовок, ищем следующий элемент
                    text_content = clean_text(element.get_text("\n", strip=True))
                    
                    # Пропускаем, если это CSS или JavaScript код
                    if is_code(text_content):
                        continue
                    
                    if len(text_content) < 50:  # Если текста мало, возможно контент в следующем элементе
                        next_sibling = element.find_next_sibling()
                        if next_sibling and next_sibling.name not in ("style", "script"):
                            # Объединяем текст из обоих элементов
                            next_text = clean_text(next_sibling.get_text("\n", strip=True))
                            # Пропускаем, если следующий элемент содержит код
                            if next_text and not is_code(next_text):
                                text_content = f"{text_content}\n{next_text}" if text_content else next_text
                                content_element = next_sibling
                    
                    text = text_content if text_content else clean_text(content_element.get_text("\n", strip=True))
                    
                    # Пропускаем, если финальный текст является кодом
                    if is_code(text):
                        continue
                    
                    links = []
                    
                    # Ищем ссылки в элементе и его дочерних элементах
                    for link in content_element.select("a[href]"):
                        link_title = link.get_text(strip=True)
                        link_href = normalize_url(link.get("href"))
                        if link_href and link_title:
                            links.append({
                                "title": link_title,
                                "link": link_href,
                            })
                    
                    # Если нашли текст, добавляем секцию
                    if text:
                        sections[mapped_title] = {
                            "id": element_id,
                            "title": mapped_title,
                            "text": text,
                            "links": links,
                        }

    return sections


def parse_all_services_meta(soup: BeautifulSoup) -> Dict[str, Dict[str, Any]]:
    meta: Dict[str, Dict[str, Any]] = {}
    for link in soup.find_all("a", href=True):
        text = link.get_text(strip=True)
        if not text or "Все услуги" not in text:
            continue

        href = normalize_url(link["href"])
        if not href:
            continue

        count = None
        count_span = link.find("span", class_="jet-engine-query-count")
        if count_span:
            digits = re.sub(r"\D", "", count_span.get_text())
            count = int(digits) if digits else None

        meta[href] = {
            "text": text,
            "count": count,
        }

    return meta


def parse_categories(soup: BeautifulSoup) -> List[Dict[str, Any]]:
    all_services_meta = parse_all_services_meta(soup)
    categories: List[Dict[str, Any]] = []

    for block in soup.select("div.ud-category-list[data-term]"):
        term = block.get("data-term")
        if term == "popular":
                    continue
            
        title_container = block.select_one(".uslugi-section-title")
        title_link = title_container.find("a") if title_container else None

        title = None
        category_link = None

        if title_link:
            title = title_link.get_text(strip=True)
            category_link = normalize_url(title_link.get("href"))
        elif title_container:
            title = title_container.get_text(strip=True)

        items: List[Dict[str, Any]] = []
        seen_links: set[str] = set()

        for item_link in block.select(".ud-scrollable a[href]"):
            item_title = item_link.get_text(strip=True)
            item_href = normalize_url(item_link.get("href"))

            if not item_title or not item_href:
                continue

            if item_href in seen_links:
                continue

            seen_links.add(item_href)
            items.append({
                "title": item_title,
                "link": item_href,
            })

        category_data: Dict[str, Any] = {
            "term": term,
            "title": title,
            "link": category_link,
            "items": items,
        }

        if category_link and category_link in all_services_meta:
            category_data["all_services"] = all_services_meta[category_link]

        categories.append(category_data)

    return categories


def aggregate_unique_services(categories: List[Dict[str, Any]]) -> List[Dict[str, str]]:
    unique: OrderedDict[str, Dict[str, str]] = OrderedDict()

    for category in categories:
        for item in category.get("items", []):
            href = item.get("link")
            title = item.get("title")
            if not href or not title:
                continue
            if href not in unique:
                unique[href] = {"title": title, "link": href}

    return list(unique.values())


async def fetch_anchor_sections_async(
    client: httpx.AsyncClient,
    url: str,
    semaphore: asyncio.Semaphore,
    allowed_titles: Optional[set[str]] = None,
) -> Dict[str, Any]:
    async with semaphore:
        try:
            html = await fetch_html(client, url)
        except httpx.HTTPError as exc:
            return {
                "url": url,
                "error": str(exc),
                "sections": {},
            }

    sections = extract_anchor_sections(html, allowed_titles)

    return {
        "url": url,
        "sections": sections,
    }


async def parse_category_detail(
    client: httpx.AsyncClient,
    url: str,
    semaphore: asyncio.Semaphore,
) -> Dict[str, Any]:
    return await fetch_anchor_sections_async(
        client,
        url,
        semaphore,
        allowed_titles=TARGET_SECTIONS,
    )


async def parse_service_detail(
    client: httpx.AsyncClient,
    url: str,
    semaphore: asyncio.Semaphore,
) -> Dict[str, Any]:
    return await fetch_anchor_sections_async(
        client,
        url,
        semaphore,
        allowed_titles=set(SERVICE_SECTION_TITLES),
    )


async def parse_mdclinica_services() -> Dict[str, Any]:
    async with httpx.AsyncClient(headers=HTTP_HEADERS, follow_redirects=True) as client:
        print(f"Загружаю главную страницу: {MAIN_URL}")
        main_html = await fetch_html(client, MAIN_URL)
        soup = BeautifulSoup(main_html, "html.parser")

        categories = parse_categories(soup)
        print(f"Найдено блоков с услугами: {len(categories)}")

        services = aggregate_unique_services(categories)
        print(f"Уникальных ссылок на услуги: {len(services)}")

        semaphore = asyncio.Semaphore(4)
        detail_tasks: Dict[str, asyncio.Task] = {}
        service_tasks: Dict[str, asyncio.Task] = {}

        for category in categories:
            link = category.get("link")
            if not link:
                continue
            if link in detail_tasks:
                continue
            detail_tasks[link] = asyncio.create_task(
                parse_category_detail(client, link, semaphore)
            )

        detail_results: Dict[str, Dict[str, Any]] = {}

        if detail_tasks:
            print(f"Загружаю страницы разделов: {len(detail_tasks)}")
            completed = await asyncio.gather(*detail_tasks.values())
            for result in completed:
                detail_results[result["url"]] = result

        for service in services:
            link = service.get("link")
            if not link or link in service_tasks:
                continue
            service_tasks[link] = asyncio.create_task(
                parse_service_detail(client, link, semaphore)
            )

        service_results: Dict[str, Dict[str, Any]] = {}

        if service_tasks:
            print(f"Загружаю страницы услуг: {len(service_tasks)}")
            completed_services = await asyncio.gather(*service_tasks.values())
            for result in completed_services:
                service_results[result["url"]] = result

        for category in categories:
            link = category.get("link")
            if link and link in detail_results:
                category["details"] = detail_results[link]

        return {
            "parsed_at": datetime.now(timezone.utc).isoformat(),
            "source": MAIN_URL,
            "categories": categories,
            "services": services,
            "category_details": detail_results,
            "service_details": service_results,
        }


def write_text(path: Path, content: str) -> None:
    path.parent.mkdir(parents=True, exist_ok=True)
    with path.open("w", encoding="utf-8") as fp:
        normalized = content.strip()
        fp.write(normalized + ("\n" if normalized else ""))


INDICATION_KEYWORDS = ("показания", "противопоказания")
ADVANTAGE_KEYWORDS = ("преимущество", "преимущества")
FAQ_KEYWORDS = ("вопрос", "ответ")
SPECIALIST_KEYWORDS = ("специалист", "врач")


def format_indications_text(text: str) -> str:
    lines: List[str] = []
    current: Optional[str] = None

    for raw_line in text.splitlines():
        line = raw_line.strip()
        if not line:
            continue

        lowered = line.lower()
        if lowered.startswith("показания"):
            current = "Показания"
            if lines and lines[-1]:
                lines.append("")
            lines.append("Показания:")
            remainder = line[len("Показания"):].strip(" :")
            if remainder:
                lines.append(f"- {remainder}")
            continue

        if lowered.startswith("противопоказания"):
            current = "Противопоказания"
            if lines and lines[-1]:
                lines.append("")
            lines.append("Противопоказания:")
            remainder = line[len("Противопоказания"):].strip(" :")
            if remainder:
                lines.append(f"- {remainder}")
            continue

        if current:
            cleaned = re.sub(r"^\d+[\).\s]+", "", line)
            lines.append(f"- {cleaned}")
        else:
            lines.append(line)

    return "\n".join(lines).strip()


def format_advantages_text(text: str) -> str:
    bullet_lines: List[str] = []
    for raw_line in text.splitlines():
        line = raw_line.strip()
        if not line:
            continue
        cleaned = re.sub(r"^\d+[\).\s]+", "", line)
        bullet_lines.append(f"- {cleaned}")
    return "\n".join(bullet_lines).strip()


def format_prices_text(text: str) -> str:
    headings: List[str] = []
    entries: List[tuple[str, Optional[str], Optional[str]]] = []

    current_code: Optional[str] = None
    current_name_parts: List[str] = []

    price_pattern = re.compile(r"[0-9][0-9\s]*₽")
    code_pattern = re.compile(r"^[A-ZА-Я]{1,2}\d")

    def commit(price: Optional[str]) -> None:
        nonlocal current_code, current_name_parts
        name = " ".join(current_name_parts).strip()
        if not name and price:
            name = price_pattern.sub("", price).strip("—: ")
        if name or price:
            entries.append((name, current_code, price))
        current_code = None
        current_name_parts = []

    for raw_line in text.splitlines():
        line = raw_line.strip()
        if not line:
            continue

        if line.lower().startswith("цены") and not current_name_parts and not current_code:
            headings.append(line)
            continue

        if code_pattern.match(line):
            if current_name_parts:
                commit(None)
            current_code = line
            continue

        price_match = price_pattern.search(line)
        if price_match:
            price = price_match.group(0)
            before_price = line[: price_match.start()].strip("—: ")
            if before_price:
                current_name_parts.append(before_price)
            commit(price)
            continue

        current_name_parts.append(line)

    commit(None)

    lines: List[str] = []
    if headings:
        lines.extend(headings)
        if entries:
            lines.append("")

    for name, code, price in entries:
        if not name and not price:
            continue
        line = f"• {name or 'Услуга'}"
        if code:
            line += f" ({code})"
        if price:
            line += f" — {price}"
        lines.append(line)

    return "\n".join(lines).strip() if lines else text.strip()


def format_faq_text(text: str) -> str:
    entries: List[str] = []
    question: Optional[str] = None
    answer_parts: List[str] = []

    def flush() -> None:
        nonlocal question, answer_parts
        if question:
            answer = " ".join(answer_parts).strip()
            entries.append(f"• Вопрос: {question}")
            if answer:
                entries.append(f"  Ответ: {answer}")
            entries.append("")
        question = None
        answer_parts = []

    for raw_line in text.splitlines():
        line = raw_line.strip()
        if not line:
            continue

        if line.lower().startswith("вопрос") and line.endswith(":"):
            flush()
            continue

        if line.endswith("?"):
            flush()
            question = line
            continue

        if line.lower().startswith("ответ") and line.endswith(":"):
            continue

        answer_parts.append(line)

    flush()

    while entries and not entries[-1].strip():
        entries.pop()

    return "\n".join(entries).strip()


def format_specialists_text(text: str) -> str:
    lines = [line.strip() for line in text.splitlines()]
    general: List[str] = []
    entries: List[str] = []
    current_name: Optional[str] = None
    description_parts: List[str] = []

    skip_phrases = {
        "специалисты",
        "все специалисты",
        "наша команда профессионалов",
    }

    def is_name(candidate: str) -> bool:
        if not candidate:
            return False
        parts = candidate.split()
        if len(parts) < 2 or len(parts) > 6:
            return False
        return all(part[0].isupper() for part in parts if part)

    def flush() -> None:
        nonlocal current_name, description_parts
        if current_name:
            description = " ".join(description_parts).strip()
            if description:
                entries.append(f"• {current_name} — {description}")
            else:
                entries.append(f"• {current_name}")
        current_name = None
        description_parts = []

    for line in lines:
        cleaned = line.strip()
        if not cleaned:
            continue
        if cleaned.lower() in skip_phrases:
            continue

        if is_name(cleaned):
            flush()
            current_name = cleaned
            continue

        if current_name:
            description_parts.append(cleaned)
        else:
            general.append(cleaned)

    flush()

    result: List[str] = []
    if general:
        result.extend(general)
        result.append("")

    result.extend(entries)

    return "\n".join(result).strip()


def format_section_content(
    title: str,
    text: str,
    links: List[Dict[str, str]],
    include_links: bool = True,
    category_or_service_name: Optional[str] = None,
) -> str:
    lines: List[str] = []
    
    if category_or_service_name:
        lines.append(category_or_service_name)
        lines.append("")
    
    lines.append(title)
    lines.append("")

    formatted_text = text.strip()

    if formatted_text:
        lower_title = title.lower()

        if any(keyword in lower_title for keyword in INDICATION_KEYWORDS) or any(
            formatted_text.lower().startswith(keyword) for keyword in INDICATION_KEYWORDS
        ):
            formatted_text = format_indications_text(formatted_text)

        elif any(keyword in lower_title for keyword in ADVANTAGE_KEYWORDS) or formatted_text.lower().startswith("преимущества"):
            formatted_text = format_advantages_text(formatted_text)

        elif lower_title.startswith("цены") or formatted_text.lower().startswith("цены"):
            formatted_text = format_prices_text(formatted_text)

        elif any(keyword in lower_title for keyword in FAQ_KEYWORDS) or "?" in formatted_text:
            formatted_text = format_faq_text(formatted_text)

        elif any(keyword in lower_title for keyword in SPECIALIST_KEYWORDS):
            formatted_text = format_specialists_text(formatted_text)

        lines.append(formatted_text)
    else:
        lines.append("Нет данных.")

    lower_title = title.lower()
    should_include_links = include_links
    if any(keyword in lower_title for keyword in SPECIALIST_KEYWORDS):
        should_include_links = False
    if "услуги" in lower_title:
        should_include_links = False

    filtered_links = [link for link in links if link.get("link")] if should_include_links else []
    if filtered_links:
        lines.append("")
        lines.append("Ссылки:")
        for link in filtered_links:
            link_title = link.get("title") or link.get("link")
            lines.append(f"- {link_title}: {link.get('link')}")

    return "\n".join(lines).strip()




def write_sections_files(
    base_dir: Path,
    sections: Dict[str, Dict[str, Any]],
    expected_titles: List[str],
    *,
    include_links: bool = True,
    category_or_service_name: Optional[str] = None,
) -> None:
    sections_dir = base_dir / "sections"
    sections_dir.mkdir(parents=True, exist_ok=True)

    for title in expected_titles:
        data = sections.get(title) or {}
        text = data.get("text", "")
        links = data.get("links", []) or []
        
        # Пропускаем создание файла, если нет данных (нет текста)
        if not text.strip():
            continue
        
        filename = f"{make_section_slug(title, 'section')}.txt"
        content = format_section_content(
            title, text, links, include_links=include_links, 
            category_or_service_name=category_or_service_name
        )
        write_text(sections_dir / filename, content)


def write_output(results: Dict[str, Any], base_dir: Path) -> None:
    if base_dir.exists():
        shutil.rmtree(base_dir)
    base_dir.mkdir(parents=True, exist_ok=True)

    summary_lines = [
        f"Источник: {results.get('source')}",
        f"Дата парсинга (UTC): {results.get('parsed_at')}",
        f"Количество разделов: {len(results.get('categories', []))}",
        f"Количество услуг: {len(results.get('services', []))}",
    ]
    write_text(base_dir / "summary.txt", "\n".join(summary_lines))

    service_details = results.get("service_details", {})

    for category in results.get("categories", []):
        title = category.get("title") or category.get("term") or "category"
        slug = make_slug(title, fallback=category.get("term") or "category")
        category_dir = ensure_unique_dir(base_dir, slug)
        category_dir.mkdir(parents=True, exist_ok=True)
        category["slug"] = category_dir.name
        write_text(category_dir / "name.txt", title or category.get("term") or "category")

        overview_dir = category_dir / "overview"
        overview_dir.mkdir(parents=True, exist_ok=True)

        details = category.get("details", {})
        overview_data = {
            "title": category.get("title"),
            "term": category.get("term"),
            "link": category.get("link"),
            "all_services": category.get("all_services"),
            "items": category.get("items", []),
            "sections": details.get("sections", {}),
            "error": details.get("error"),
        }
        write_sections_files(
            overview_dir,
            overview_data["sections"],
            [
                title
                for title in CATEGORY_SECTION_TITLES
                if title not in {"Цены", "Фото до и после"}
            ],
            category_or_service_name=title,
        )

        services_root = category_dir / "services"
        services_root.mkdir(parents=True, exist_ok=True)

        used_service_slugs: set[str] = set()
        for item in category.get("items", []):
            service_title = item.get("title") or item.get("link") or "service"
            base_slug = make_slug(service_title, fallback="service")
            slug_candidate = base_slug
            counter = 2
            while slug_candidate in used_service_slugs:
                slug_candidate = f"{base_slug}_{counter}"
                counter += 1
            used_service_slugs.add(slug_candidate)

            service_dir = services_root / slug_candidate
            service_dir.mkdir(parents=True, exist_ok=True)
            write_text(service_dir / "name.txt", service_title)

            detail = service_details.get(item.get("link"), {})

            write_sections_files(
                service_dir,
                detail.get("sections", {}),
                [
                    title
                    for title in SERVICE_SECTION_TITLES
                    if title != "Фото до и после"
                ],
                include_links=False,
                category_or_service_name=service_title,
            )


async def main() -> None:
    print("=" * 60)
    print("Парсинг сайта mdclinica.ru/uslugi")
    print("=" * 60)
    
    results = await parse_mdclinica_services()
    
    output_dir = Path("mdclinica")
    write_output(results, output_dir)
    
    print("\n" + "=" * 60)
    print("РЕЗУЛЬТАТЫ:")
    print(f"  Блоков категорий: {len(results['categories'])}")
    print(f"  Уникальных услуг: {len(results['services'])}")
    print(f"  Папка с данными: {output_dir.resolve()}")
    print("=" * 60)


if __name__ == "__main__":
    asyncio.run(main())