from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys
from bs4 import BeautifulSoup, NavigableString, Tag
import mysql.connector
import json
import time
import re

# === Конфигурация ===
CHROMEDRIVER_PATH = r"C:\Users\Evgen\Downloads\chromedriver-win64\chromedriver.exe"
COOKIES_FILE = "cookies_dzen.json"

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

EDITOR_URL = "https://dzen.ru/profile/editor/id/669dd289f109381c8b33de06/publications"


# === Подключение к БД ===
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


# === Инициализация браузера ===
def init_browser():
    chrome_options = Options()
    chrome_options.add_argument("--disable-gpu")
    chrome_options.add_argument("--disable-software-rasterizer")
    chrome_options.add_argument("--disable-extensions")
    chrome_options.add_argument("--no-sandbox")
    chrome_options.add_argument("--disable-popup-blocking")
    chrome_options.add_argument("--disable-notifications")
    chrome_options.add_argument("--log-level=3")
    chrome_options.add_experimental_option('excludeSwitches', ['enable-logging'])
    chrome_options.add_experimental_option("useAutomationExtension", False)
    chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"])
    chrome_options.set_capability('goog:loggingPrefs', {'browser': 'SEVERE'})
    service = Service(CHROMEDRIVER_PATH)
    driver = webdriver.Chrome(service=service, options=chrome_options)
    return driver


# === Авторизация через куки ===
def load_cookies(driver):
    try:
        with open(COOKIES_FILE, "r", encoding="utf-8") as f:
            cookies = json.load(f)
        for cookie in cookies:
            cookie.pop("sameSite", None)
            cookie.pop("storeId", None)
            cookie.pop("session", None)
            if not cookie["domain"].startswith("."):
                cookie["domain"] = "." + cookie["domain"]
            try:
                driver.add_cookie(cookie)
            except Exception as e:
                print(f"❌ Ошибка добавления куки {cookie.get('name')}: {e}")
        print("✅ Куки успешно загружены")
    except Exception as e:
        print(f"❌ Ошибка загрузки кук: {e}")


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

    # Закрытие всплывающего окна (если есть)
    try:
        close_btn = WebDriverWait(driver, 5).until(
            EC.element_to_be_clickable((By.CSS_SELECTOR, 'button[data-testid="close-button"]'))
        )
        close_btn.click()
    except:
        pass

    # Проверка авторизации
    try:
        print("⏳ Ожидание загрузки страницы редактора...")
        WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.CSS_SELECTOR, "button[data-testid='add-publication-button']"))
        )
        print("✅ Авторизация успешна")
    except Exception as e:
        print(f"❌ Не удалось авторизоваться. Проверь куки: {e}")
        return False
    return True


# === Создание новой статьи ===
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("✅ Клик по кнопке 'Написать статью'")
    except Exception as e:
        print(f"❌ Ошибка при клике на 'Написать статью': {e}")
        return False
    try:
        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


# === Закрытие подсказок ===
def close_tips(driver):
    try:
        close_button = WebDriverWait(driver, 10).until(
            EC.element_to_be_clickable((By.XPATH, '//div[@role="button" and @aria-label="Закрыть"]'))
        )
        close_button.click()
        print("✅ Подсказка закрыта")
    except:
        print("ℹ️ Подсказка не найдена")


# === Извлечение заголовка из первого <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


# === Вставка заголовка через send_keys ===
def insert_title(driver, title):
    try:
        title_field = WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.CSS_SELECTOR, "div.public-DraftEditor-content[contenteditable='true']"))
        )
        title_field.click()
        time.sleep(0.5)
        actions = ActionChains(driver)
        actions.send_keys(title)
        actions.perform()
        print("✅ Заголовок успешно вставлен")
    except Exception as e:
        print(f"❌ Не удалось вставить заголовок: {e}")

# === Вставка форматированного контента (УЛУЧШЕННАЯ ВЕРСИЯ) ===
def send_formatted_content(driver, html):
    editor_xpath = "//div[@aria-describedby='placeholder-ZenDraftEditor' and contains(@class, 'public-DraftEditor-content')]"
    editor = WebDriverWait(driver, 10).until(
        EC.element_to_be_clickable((By.XPATH, editor_xpath))
    )
    editor.click()
    time.sleep(0.5)
    soup = BeautifulSoup(html, 'html.parser')
    actions = ActionChains(driver)

    def add_space_if_needed(prev_char, next_text_start=""):
        """Проверяет, нужно ли добавить пробел перед следующим элементом."""
        # Не добавляем пробел, если предыдущий символ - знак препинания или пробел
        if prev_char and prev_char in '.,;:!? ':
            return
        # Не добавляем пробел перед началом предложения или если следующий элемент пустой
        if not next_text_start or next_text_start.startswith((' ', '.', ',', ';', ':', '!', '?')):
            return
        actions.send_keys(' ')

    last_char_in_paragraph = "" # Для отслеживания необходимости пробела

    for tag in soup.find_all(recursive=False):
        last_char_in_paragraph = "" # Сброс для каждого нового блока (p, h1 и т.д.)
        if tag.name in ['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6']:
            content_parts = []
            # Собираем все части контента абзаца
            for child in tag.children:
                if isinstance(child, NavigableString):
                    text = child.strip()
                    if text:
                        content_parts.append({'type': 'text', 'value': text})
                elif child.name in ['b', 'strong', 'i', 'em', 'u']:
                    inner_text = child.get_text(strip=True)
                    if inner_text:
                        content_parts.append({
                            'type': child.name,
                            'value': inner_text
                        })
                elif child.name == 'a':
                    link_text = child.get_text(strip=True)
                    link_url = child.get('href')
                    if link_text and link_url:
                        content_parts.append({
                            'type': 'link',
                            'value': link_text,
                            'url': link_url
                        })

            # Вставляем собранный контент с правильными пробелами
            for i, part in enumerate(content_parts):
                # Добавляем пробел перед элементом, если это необходимо
                if i > 0 or (i == 0 and last_char_in_paragraph): # Если это не первый элемент в документе или был текст в предыдущем блоке
                     # Получаем начало текста текущей части
                    part_start = part['value'][0] if part['value'] else ''
                    add_space_if_needed(last_char_in_paragraph, part_start)

                if part['type'] == 'text':
                    actions.send_keys(part['value'])
                    if part['value']:
                        last_char_in_paragraph = part['value'][-1]
                elif part['type'] in ['b', 'strong']:
                    actions.key_down(Keys.CONTROL).send_keys('b').key_up(Keys.CONTROL)
                    actions.send_keys(part['value'])
                    actions.key_down(Keys.CONTROL).send_keys('b').key_up(Keys.CONTROL)
                    if part['value']:
                        last_char_in_paragraph = part['value'][-1]
                elif part['type'] in ['i', 'em']:
                    actions.key_down(Keys.CONTROL).send_keys('i').key_up(Keys.CONTROL)
                    actions.send_keys(part['value'])
                    actions.key_down(Keys.CONTROL).send_keys('i').key_up(Keys.CONTROL)
                    if part['value']:
                        last_char_in_paragraph = part['value'][-1]
                elif part['type'] == 'u':
                    actions.key_down(Keys.CONTROL).key_down(Keys.SHIFT).send_keys('u').key_up(Keys.SHIFT).key_up(Keys.CONTROL)
                    actions.send_keys(part['value'])
                    # Убедиться, что модификаторы отпущены
                    actions.key_up(Keys.CONTROL)
                    if part['value']:
                        last_char_in_paragraph = part['value'][-1]
                elif part['type'] == 'link':
                    # Вставляем текст ссылки
                    actions.send_keys(part['value'])
                    actions.perform() # Выполняем вставку текста
                    if part['value']:
                        last_char_in_paragraph = part['value'][-1]

                    # --- Процесс создания ссылки ---
                    # 1. Выделение текста ссылки (движение влево с Shift)
                    temp_actions = ActionChains(driver)
                    for _ in range(len(part['value'])):
                        temp_actions.key_down(Keys.SHIFT).send_keys(Keys.LEFT).key_up(Keys.SHIFT)
                    temp_actions.perform()
                    time.sleep(0.2) # Небольшая пауза для стабильности

                    # 2. Клик по кнопке "Ссылка"
                    link_button_clicked = False
                    link_button_selectors = [
                        By.XPATH, "//div[contains(@class, 'editor-toolbar') and contains(., 'Ссылка')]//div[@role='button']",
                        By.XPATH, "//button[@aria-label='Ссылка']",
                        By.XPATH, "//div[@data-testid='link-button']",
                        By.CSS_SELECTOR, "button[aria-label*='Ссылка'], button[title*='Ссылка']" # Более гибкий CSS-селектор
                    ]
                    for by, selector in link_button_selectors:
                        try:
                            link_button = WebDriverWait(driver, 3).until(
                                EC.element_to_be_clickable((by, selector))
                            )
                            link_button.click()
                            print(f"✅ Кнопка ссылки найдена и нажата (селектор: {selector})")
                            link_button_clicked = True
                            break
                        except:
                            continue # Пробуем следующий селектор

                    if not link_button_clicked:
                         print(f"❌ Не удалось найти кнопку 'Ссылка' для текста '{part['value']}'. Пропускаем создание ссылки.")
                         # Снимаем выделение, нажав стрелку вправо
                         ActionChains(driver).send_keys(Keys.RIGHT).perform()
                         continue # Переходим к следующей части контента

                    # 3. Ожидание и заполнение поля ввода URL
                    try:
                        link_input = WebDriverWait(driver, 5).until(
                            EC.element_to_be_clickable((By.XPATH, "//input[contains(@placeholder, 'Введите ссылку') or @placeholder='Ссылка' or @type='url']"))
                        )
                        link_input.clear()
                        link_input.send_keys(part['url'])
                        link_input.send_keys(Keys.ENTER)
                        print(f"✅ Вставлена ссылка: {part['value']} -> {part['url']}")
                    except Exception as e:
                        print(f"❌ Не удалось заполнить URL для ссылки '{part['value']}': {e}. Пропускаем.")
                        # Пытаемся закрыть диалог или снять выделение
                        ActionChains(driver).send_keys(Keys.ESCAPE).perform()

                    # 4. Переинициализируем ActionChains после потенциальных действий с UI
                    actions = ActionChains(driver)
                    time.sleep(0.3) # Пауза после создания ссылки


            actions.send_keys(Keys.ENTER) # Завершаем абзац

        elif tag.name == 'ul':
            for li in tag.find_all('li', recursive=False):
                # Добавляем пробел перед списком, если предыдущий блок не закончился на пробел
                add_space_if_needed(last_char_in_paragraph, '•')
                actions.send_keys('• ')
                # Обрабатываем содержимое li как простой текст
                text_content = li.get_text(strip=True)
                actions.send_keys(text_content)
                if text_content:
                     last_char_in_paragraph = text_content[-1]
                actions.send_keys(Keys.ENTER)
        elif tag.name == 'ol':
            for idx, li in enumerate(tag.find_all('li', recursive=False), 1):
                # Добавляем пробел перед списком, если предыдущий блок не закончился на пробел
                 add_space_if_needed(last_char_in_paragraph, str(idx)[0])
                actions.send_keys(f"{idx}. ")
                # Обрабатываем содержимое li как простой текст
                text_content = li.get_text(strip=True)
                actions.send_keys(text_content)
                if text_content:
                     last_char_in_paragraph = text_content[-1]
                actions.send_keys(Keys.ENTER)
        
        # Выполняем накопленные действия для каждого блока
        try:
             actions.perform()
        except Exception as e:
             print(f"⚠️ Ошибка при выполнении действий для блока {tag.name}: {e}")
        actions = ActionChains(driver) # Переинициализируем для следующего блока

    print("✅ Форматированный контент вставлен через горячие клавиши")





# === Основная функция ===
def main():
    driver = init_browser()
    article = get_article_from_db()
    if not article:
        print("❌ Не удалось загрузить статью из базы данных.")
        driver.quit()
        return

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

    if soup.body:
        cleaned_article = ''.join(str(tag) for tag in soup.body.contents if tag.name not in ['script', 'style'])
    else:
        cleaned_article = ''.join(str(tag) for tag in soup.contents if tag.name not in ['script', 'style'])

    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

    close_tips(driver)
    insert_title(driver, title)
    send_formatted_content(driver, cleaned_article)

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


if __name__ == "__main__":
    main()   File "C:\Users\Evgen\python_scripts\dzen.py", line 343
    actions.send_keys(f"{idx}. ")
                                 ^
IndentationError: unindent does not match any outer indentation level напечатай исправленный скрипт