from seleniumwire import webdriver as wire_webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from kameleo.local_api_client import KameleoLocalApiClient
from bs4 import BeautifulSoup, NavigableString, Tag
import json
import time
import os
import random
import base64
import mysql.connector
import requests

# --- Конфигурация ---
kameleo_port = os.getenv('KAMELEO_PORT', '5050')

DB_CONFIG = {
    'host': '192.168.8.100',
    'user': 'root',
    'password': 'BXiQLt3G',
    'database': 'led_topics_db',
    'port': 3307,
}

EDITOR_URL = "https://dzen.ru/profile/editor/ledinform/publications"
IMAGE_FOLDER = r"C:\Users\Evgen\Documents\generate_img"  # Папка с изображениями

# === Запуск профиля Kameleo ===
def start_kameleo_profile(profile_name="Dzen_test"):
    client = KameleoLocalApiClient(endpoint=f'http://localhost:{kameleo_port}')
    profiles = client.profile.list_profiles()
    profile_id = None
    for prof in profiles:
        print(f"ID: {prof.id} | Name: {prof.name}")
        if prof.name == profile_name:
            profile_id = prof.id
            break
    if profile_id is None:
        raise Exception(f"Профиль {profile_name} не найден!")

    client.profile.start_profile(profile_id)
    return client, profile_id


# === Подключение Selenium к Kameleo браузеру с selenium-wire ===
def init_kameleo_selenium(profile_id):
    options = Options()
    options.add_experimental_option('kameleo:profileId', profile_id)

    # ✅ Используем selenium-wire для доступа к сетевым запросам
    driver = wire_webdriver.Remote(
        command_executor=f'http://localhost:{kameleo_port}/webdriver',
        options=options
    )
    return driver


# === Открытие редактора ===
def open_editor(driver):
    print("🌐 Открываем редактор...")
    driver.get(EDITOR_URL)

    try:
        WebDriverWait(driver, 15).until(
            EC.presence_of_element_located((By.TAG_NAME, 'body'))
        )
        print("✅ Страница загружена")
        return True
    except:
        print("❌ Страница не загружена за 15 секунд")
        return False


# === Получаем случайную статью из базы ===
def get_article_from_db():
    try:
        conn = mysql.connector.connect(**DB_CONFIG)
        cursor = conn.cursor(dictionary=True)
        query = """
        SELECT topic, content 
        FROM led_topics
        WHERE is_archived = 0 
          AND content IS NOT NULL 
          AND content != ''
        ORDER BY RAND()
        LIMIT 1;
        """
        cursor.execute(query)
        result = cursor.fetchone()
        cursor.close()
        conn.close()
        return result
    except Exception as e:
        print(f"❌ Ошибка при подключении к БД: {e}")
        return None


# === Извлечение заголовка из первого <p> ===
def extract_title_from_first_p(soup):
    p = soup.find('p')
    if not p:
        return "Без заголовка"
    title = p.get_text(strip=True)
    p.decompose()
    return title


# === Создание новой статьи (нажимаем "Написать статью") ===
def create_new_article(driver):
    try:
        add_button = WebDriverWait(driver, 10).until(
            EC.element_to_be_clickable((By.CSS_SELECTOR, "button[data-testid='add-publication-button']"))
        )
        add_button.click()
        print("✅ Клик по кнопке 'Написать статью'")

        write_button = WebDriverWait(driver, 10).until(
            EC.element_to_be_clickable((By.XPATH, '//span[text()="Написать статью"]'))
        )
        write_button.click()
        print("✅ Выбрана публикация 'Написать статью'")
    except Exception as e:
        print(f"❌ Ошибка при создании новой статьи: {e}")
        return False
    return True


# --- Конвертер HTML в Draft.js contentState ---
def random_key(length=7):
    return ''.join(random.choices('abcdefghijklmnopqrstuvwxyz0123456789', k=length))

def html_to_contentstate(html):
    soup = BeautifulSoup(html, 'html.parser')

    blocks = []
    entity_map = {}
    entity_key = 0

    def process_node(node, current_text, inline_styles, entity_ranges):
        nonlocal entity_key

        if isinstance(node, NavigableString):
            current_text.append(str(node))
            return

        if node.name in ['b', 'strong']:
            start = len(current_text)
            for child in node.children:
                process_node(child, current_text, inline_styles, entity_ranges)
            end = len(current_text)
            inline_styles.append({
                "offset": start,
                "length": end - start,
                "style": "BOLD"
            })
        elif node.name in ['i', 'em']:
            start = len(current_text)
            for child in node.children:
                process_node(child, current_text, inline_styles, entity_ranges)
            end = len(current_text)
            inline_styles.append({
                "offset": start,
                "length": end - start,
                "style": "ITALIC"
            })
        elif node.name == 'u':
            start = len(current_text)
            for child in node.children:
                process_node(child, current_text, inline_styles, entity_ranges)
            end = len(current_text)
            inline_styles.append({
                "offset": start,
                "length": end - start,
                "style": "UNDERLINE"
            })
        elif node.name == 'a':
            href = node.get('href')
            if href:
                start = len(current_text)
                for child in node.children:
                    process_node(child, current_text, inline_styles, entity_ranges)
                end = len(current_text)

                entity_map[str(entity_key)] = {
                    "type": "LINK",
                    "mutability": "MUTABLE",
                    "data": {
                        "href": href,
                        "rel": "noopener noreferrer",
                        "target": "_blank",
                        "url": href
                    }
                }

                entity_ranges.append({
                    "offset": start,
                    "length": end - start,
                    "key": entity_key
                })

                entity_key += 1
        else:
            for child in node.children:
                process_node(child, current_text, inline_styles, entity_ranges)

    for tag in soup.find_all(recursive=False):
        block_type = 'unstyled'

        if tag.name in ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']:
            block_type = f'header-{tag.name[1:]}'
        elif tag.name == 'p':
            block_type = 'unstyled'
        elif tag.name == 'li':
            block_type = 'unordered-list-item'

        current_text = []
        inline_styles = []
        entity_ranges = []

        for child in tag.children:
            process_node(child, current_text, inline_styles, entity_ranges)

        block = {
            "key": random_key(),
            "text": ''.join(current_text),
            "type": block_type,
            "depth": 0,
            "inlineStyleRanges": inline_styles,
            "entityRanges": entity_ranges,
            "data": {}
        }

        blocks.append(block)

    return {
        "blocks": blocks,
        "entityMap": entity_map
    }


# === Проверка токена в localStorage, cookie, заголовках ===
def check_auth_token(driver):
    print("🔍 Проверяем токен авторизации...")

    # 1. Из localStorage
    try:
        auth_token = driver.execute_script("return localStorage.getItem('Zen-authorization');")
        if auth_token:
            print("✅ Токен найден в localStorage")
            return auth_token
    except:
        print("⚠️ Ошибка при получении токена из localStorage")

    # 2. Из кук
    try:
        zen_cookie = driver.get_cookie("Zen-authorization")
        if zen_cookie:
            auth_token = zen_cookie['value']
            print("✅ Токен найден в куках")
            return auth_token
    except:
        print("⚠️ Ошибка при получении токена из кук")

    # 3. Из заголовков запроса (через selenium-wire)
    try:
        for request in driver.requests:
            if "dzen.ru/editor-api" in request.url:
                auth_header = request.headers.get("Authorization")
                if auth_header and "Bearer" in auth_header:
                    auth_token = auth_header.replace("Bearer ", "")
                    print("✅ Токен найден в заголовке Authorization")
                    return auth_token
        print("❌ Токен авторизации не найден")
    except Exception as e:
        print("⚠️ Ошибка при проверке заголовков:", e)

    return None


# === Отправка контента через API ===
def send_content_via_api(driver, html, publication_id="68885d981476e3014bd1eb62", publisher_id="686e295c4763b6759f36a8a1"):
    print("📤 Отправляем контент через API...")

    # 1. Получаем токен
    auth_token = check_auth_token(driver)
    if not auth_token:
        print("❌ Не удалось найти токен авторизации")
        return False

    # 2. Получаем CSRF-токен
    try:
        csrf_token = driver.execute_script("""
            const meta = document.querySelector('meta[name="csrf-token"]');
            return meta ? meta.content : null;
        """)
    except:
        csrf_token = None
        print("⚠️ CSRF-токен не найден")

    # 3. Получаем куки
    selenium_cookies = driver.get_cookies()
    cookie_str = "; ".join([f"{cookie['name']}={cookie['value']}" for cookie in selenium_cookies])

    # 4. URL
    url = f"https://dzen.ru/editor-api/v2/update-publication-content?publisherId={publisher_id}&clientRid=41cabb156ad3c0"

    # 5. Заголовки
    headers = {
        "Authorization": f"Bearer {auth_token}",
        "Content-Type": "application/json",
        "User-Agent": driver.capabilities['browserVersion'],
        "Cookie": cookie_str
    }

    if csrf_token:
        headers["X-Csrf-Token"] = csrf_token

    # 6. Конвертируем HTML в contentState
    content_state = html_to_contentstate(html)

    # 7. Тело запроса
    data = {
        "id": publication_id,
        "articleContent": {
            "contentState": json.dumps(content_state)
        },
        "tagsInput": {"tags": []},
        "commentsFlagState": "on",
        "visibilityType": "all",
        "delayedPublicationFlagState": "off"
    }

    # 8. Отправляем
    try:
        response = requests.post(url, headers=headers, data=json.dumps(data))
        print("📡 Статус код:", response.status_code)
        print("📄 Ответ сервера:", response.text)
        return response.status_code == 200
    except Exception as e:
        print("❌ Ошибка при отправке через API:", e)
        return False


# === Основная функция ===
def main():
    client, profile_id = start_kameleo_profile(profile_name="Dzen_test")
    driver = init_kameleo_selenium(profile_id)

    article = get_article_from_db()
    if not article:
        print("❌ Не удалось получить статью из базы")
        driver.quit()
        client.profile.stop_profile(profile_id)
        return

    soup = BeautifulSoup(article['content'], "html.parser")
    title = extract_title_from_first_p(soup)

    # Извлекаем основной контент
    if soup.body:
        content_tags = [tag for tag in soup.body.contents if isinstance(tag, Tag) and tag.name not in ['script', 'style']]
    else:
        content_tags = [tag for tag in soup.contents if isinstance(tag, Tag) and tag.name not in ['script', 'style']]

    cleaned_article = ''.join(str(tag) for tag in content_tags)

    with open("formatted_article.html", "w", encoding="utf-8") as f:
        f.write(cleaned_article)

    if not open_editor(driver):
        driver.quit()
        return

    if not create_new_article(driver):
        driver.quit()
        return

    # Проверяем токен и отправляем через API или innerHTML
    auth_token = check_auth_token(driver)
    if not auth_token:
        print("❌ Токен не найден, вставляем через innerHTML")
        editor = WebDriverWait(driver, 10).until(
            EC.element_to_be_clickable((By.XPATH, "//div[@contenteditable='true']"))
        )
        editor.click()
        driver.execute_script("""
            const editor = arguments[0];
            editor.focus();
            editor.innerHTML = arguments[1];

            ['input', 'change', 'blur', 'compositionend'].forEach(eventType => {
                const event = new Event(eventType, { bubbles: true, cancelable: true });
                editor.dispatchEvent(event);
            });
        """, editor, cleaned_article)
        print("✅ Контент вставлен через innerHTML (без API)")
    else:
        # Отправляем через API
        success = send_content_via_api(driver, cleaned_article)
        if success:
            print("✅ Контент успешно отправлен через API")
        else:
            print("❌ Ошибка при отправке контента через API")

    input("✅ Нажмите Enter, чтобы закрыть браузер...")
    driver.quit()
    client.profile.stop_profile(profile_id)


if __name__ == "__main__":
    main() py kamelio.py
C:\Users\Evgen\AppData\Local\Programs\Python\Python313\Lib\site-packages\seleniumwire\thirdparty\mitmproxy\contrib\kaitaistruct\tls_client_hello.py:10: UserWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html. The pkg_resources package is slated for removal as early as 2025-11-30. Refrain from using this package or pin to Setuptools<81.
  from pkg_resources import parse_version
ID: 3fa38013-b74a-4b38-9ce9-9903b7eafeff | Name: Dzen_test
Traceback (most recent call last):
  File "C:\Users\Evgen\python_scripts\kamelio.py", line 413, in <module>
    main()
    ~~~~^^
  File "C:\Users\Evgen\python_scripts\kamelio.py", line 349, in main
    driver = init_kameleo_selenium(profile_id)
  File "C:\Users\Evgen\python_scripts\kamelio.py", line 53, in init_kameleo_selenium
    driver = wire_webdriver.Remote(
        command_executor=f'http://localhost:{kameleo_port}/webdriver',
        options=options
    )
  File "C:\Users\Evgen\AppData\Local\Programs\Python\Python313\Lib\site-packages\seleniumwire\webdriver.py", line 308, in __init__
    super().__init__(*args, **kwargs)
    ~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
TypeError: WebDriver.__init__() got an unexpected keyword argument 'desired_capabilities'