import tkinter as tk
from tkinter import scrolledtext, messagebox, filedialog
from tkinter import ttk
import xml.etree.ElementTree as ET
import aiohttp
import asyncio
from bs4 import BeautifulSoup
from PIL import Image, ImageTk
from io import BytesIO
import logging
import mimetypes

# Настройка логирования
logging.basicConfig(filename='rss_parser.log', level=logging.INFO, format='%(asctime)s:%(levelname)s:%(message)s')

# Константы
REQUEST_TIMEOUT = 15
IMAGE_MAX_SIZE = (300, 200)

class RSSParserGUI:
    def __init__(self, root):
        self.root = root
        self.root.title("RSS и Веб-Сайты Парсер")
        self.root.geometry("1500x900")
        self.root.resizable(True, True)

        # Кэш изображений
        self.image_cache = {}

        # Настройка интерфейса
        self.setup_gui()

    def setup_gui(self):
        """Настраивает интерфейс."""
        main_frame = ttk.Frame(self.root)
        main_frame.pack(fill=tk.BOTH, expand=True)

        left_frame = ttk.Frame(main_frame, width=400, padding=10)
        left_frame.pack(side=tk.LEFT, fill=tk.Y)

        right_frame = ttk.Frame(main_frame, padding=10)
        right_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True)

        # Настройка области ввода и вывода
        self.setup_menu(left_frame)
        self.setup_output_area(right_frame)

        # История парсинга
        self.parsing_history = []
        self.displayed_images = []

    def setup_menu(self, parent):
        """Создаёт меню для RSS и веб-сайтов."""
        # Пример парсинга RSS
        rss_section = ttk.LabelFrame(parent, text="Парсинг RSS-Лент", padding=10)
        rss_section.pack(fill=tk.X, pady=10)
        self.rss_url_entry = ttk.Entry(rss_section, width=50)
        self.rss_url_entry.pack(anchor=tk.W, pady=5)

        self.rss_start_button = ttk.Button(rss_section, text="Парсинг", command=self.start_parsing_rss)
        self.rss_start_button.pack(anchor=tk.W, pady=5)

    def setup_output_area(self, parent):
        """Создает окно для вывода результатов."""
        self.result_box = scrolledtext.ScrolledText(parent, wrap=tk.WORD, font=("Arial", 12))
        self.result_box.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)

    def start_parsing_rss(self):
        """Запуск асинхронного парсинга RSS."""
        url = self.rss_url_entry.get().strip()
        if not url:
            messagebox.showwarning("Ошибка", "Введите URL")
            return
        asyncio.run_coroutine_threadsafe(self.parse_rss(url), asyncio.get_event_loop())

    async def fetch_rss(self, url):
        """Асинхронный запрос RSS-ленты."""
        try:
            async with aiohttp.ClientSession() as session:
                async with session.get(url, timeout=REQUEST_TIMEOUT) as response:
                    response.raise_for_status()
                    return await response.text()
        except aiohttp.ClientError as e:
            logging.error(f"Ошибка получения RSS: {e}")
            messagebox.showerror("Ошибка", f"Не удалось загрузить RSS: {e}")
            return None

    async def parse_rss(self, url):
        """Асинхронный парсинг RSS."""
        content = await self.fetch_rss(url)
        if not content:
            return

        try:
            root = ET.fromstring(content)
            items = root.findall('.//item')
            for item in items:
                title = item.findtext('title')
                description = item.findtext('description')
                link = item.findtext('link')

                self.result_box.insert(tk.END, f"Заголовок: {title}\n")
                self.result_box.insert(tk.END, f"Описание: {description}\n")
                self.result_box.insert(tk.END, f"Ссылка: {link}\n")
                self.result_box.insert(tk.END, "---\n")

                media_url = self.extract_media_url(item)
                if media_url:
                    await self.display_image_async(media_url)

        except ET.ParseError as e:
            logging.error(f"Ошибка парсинга XML: {e}")
            messagebox.showerror("Ошибка", "Некорректный формат RSS")

    def extract_media_url(self, item):
        """Извлечение медиа-URL из элемента RSS."""
        enclosure = item.find('enclosure')
        if enclosure is not None and 'url' in enclosure.attrib:
            return enclosure.attrib['url']
        return None

    async def display_image_async(self, media_url):
        """Асинхронная загрузка и отображение изображения."""
        try:
            mime_type, _ = mimetypes.guess_type(media_url)
            if mime_type and mime_type.startswith('image'):
                async with aiohttp.ClientSession() as session:
                    async with session.get(media_url) as response:
                        img_data = await response.read()
                        img = Image.open(BytesIO(img_data))
                        img.thumbnail(IMAGE_MAX_SIZE)

                        tk_image = ImageTk.PhotoImage(img)
                        self.image_cache[media_url] = tk_image
                        self.result_box.image_create(tk.END, image=tk_image)
                        self.result_box.insert(tk.END, "\n")
            else:
                logging.info(f"Медиа по URL не является изображением: {media_url}")
        except Exception as e:
            logging.error(f"Ошибка загрузки изображения: {e}")
            messagebox.showerror("Ошибка", f"Не удалось загрузить изображение: {e}")

    def save_results(self):
        """Сохраняет результаты в файл."""
        filename = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files", "*.txt")])
        if filename:
            with open(filename, 'w', encoding='utf-8') as file:
                file.write(self.result_box.get(1.0, tk.END))

    def clear_results(self):
        """Очищает окно вывода."""
        self.result_box.delete(1.0, tk.END)

# Запуск программы
def run_app():
    root = tk.Tk()
    app = RSSParserGUI(root)
    root.mainloop()

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