import json
import os
import string
import re
from collections import defaultdict, Counter
from datetime import datetime
from urllib.parse import urlparse
import html  # Для безопасного экранирования HTML

import emoji
from wordcloud import WordCloud
from textblob import TextBlob
import gensim
from gensim import corpora
import nltk
from nltk.stem import WordNetLemmatizer
import networkx as nx
import plotly.graph_objs as go

import matplotlib  # Добавлено для устранения сообщения о бекенде
matplotlib.use('Agg')  # Установить неинтерактивный бекенд

# Для загрузки данных NLTK
nltk.download('punkt')
nltk.download('wordnet')


def load_json(file_path):
    if not os.path.exists(file_path):
        print(f"Входной файл '{file_path}' не найден.")
        return None
    try:
        with open(file_path, 'r', encoding='utf-8') as infile:
            return json.load(infile)
    except json.JSONDecodeError as e:
        print(f"Ошибка декодирования JSON: {e}")
        return None


def save_html(content, file_path):
    try:
        with open(file_path, 'w', encoding='utf-8') as html_file:
            html_file.write(content)
            print(f"HTML отчет успешно сохранен в '{file_path}'.")
    except Exception as e:
        print(f"Ошибка при сохранении HTML файла: {e}")


def extract_text(text_content):
    if isinstance(text_content, str):
        return text_content
    elif isinstance(text_content, list):
        text_parts = []
        for item in text_content:
            if isinstance(item, str):
                text_parts.append(item)
            elif isinstance(item, dict) and 'text' in item:
                text_parts.append(item['text'])
        return ''.join(text_parts)
    elif isinstance(text_content, dict) and 'text' in text_content:
        return text_content['text']
    else:
        return ''


def tokenize_text(text):
    text = text.lower()
    text = text.translate(str.maketrans('', '', string.punctuation))
    words = text.split()
    return words


def get_time_of_day(hour):
    if 6 <= hour < 12:
        return 'Утро'
    elif 12 <= hour < 18:
        return 'День'
    elif 18 <= hour < 24:
        return 'Вечер'
    else:
        return 'Ночь'


def identify_hashtags(text):
    return re.findall(r'#\w+', text)


def identify_mentions(text):
    return re.findall(r'@\w+', text)


def identify_links(text):
    # Простое регулярное выражение для поиска ссылок
    return re.findall(r'(https?://[^\s]+)', text)


def get_link_type(url):
    parsed_url = urlparse(url)
    domain = parsed_url.netloc.lower()
    if 'youtube.com' in domain or 'youtu.be' in domain:
        return 'YouTube'
    elif 'twitter.com' in domain:
        return 'Twitter'
    elif 'facebook.com' in domain:
        return 'Facebook'
    elif 'instagram.com' in domain:
        return 'Instagram'
    else:
        return 'Другое'


def extract_emojis(text):
    return [char for char in text if char in emoji.EMOJI_DATA]


def analyze_data(data, base_dir):
    cleaned_messages = []
    user_message_counts = defaultdict(int)
    user_video_counts = defaultdict(int)
    user_voice_counts = defaultdict(int)
    user_sticker_counts = defaultdict(int)
    user_citation_counts = defaultdict(int)
    user_mentions_received = defaultdict(int)
    user_mentions_made = defaultdict(int)
    hashtag_counter = Counter()
    user_hashtags_made = defaultdict(int)
    user_links_made = defaultdict(int)
    link_type_counter = Counter()
    activity_by_hour = defaultdict(int)
    activity_by_weekday = defaultdict(int)
    activity_by_time_of_day = defaultdict(int)
    word_counter = Counter()
    emoji_counter = Counter()
    user_interactions = defaultdict(lambda: defaultdict(int))
    user_reply_counts = defaultdict(int)
    user_citations_made = defaultdict(int)
    user_citations_received = defaultdict(int)
    user_long_messages = defaultdict(int)
    user_message_lengths = defaultdict(list)
    message_edits = defaultdict(int)
    total_edit_count = 0
    total_messages = 0
    total_characters = 0  # Для общего подсчета символов
    media_files_counter = Counter()
    user_media_counts = defaultdict(int)
    response_times = defaultdict(list)
    user_forwarded_counts = defaultdict(int)
    user_forwarded_from = defaultdict(int)
    forwarded_from_counter = Counter()
    texts_for_topic = []

    russian_stopwords = set([
        'и', 'в', 'во', 'не', 'что', 'он', 'на', 'я', 'с', 'со',
        'как', 'а', 'то', 'все', 'она', 'так', 'его', 'но', 'да',
        'ты', 'к', 'у', 'же', 'вы', 'за', 'бы', 'по', 'только', 'ее',
        'мне', 'было', 'вот', 'от', 'меня', 'еще', 'нет', 'о', 'из',
        'ему', 'теперь', 'когда', 'даже', 'ну', 'вдруг', 'ли', 'если',
        'уже', 'или', 'ни', 'быть', 'был', 'него', 'до', 'вас', 'нибудь',
        'опять', 'уж', 'вам', 'ведь', 'там', 'потом', 'себя', 'ничего',
        'ей', 'может', 'они', 'тут', 'где', 'есть', 'надо', 'ней', 'для',
        'мы', 'тебя', 'их', 'чем', 'была', 'сам', 'чтобы', 'без', 'будто',
        'чего', 'раз', 'тоже', 'себе', 'под', 'будет', 'ж', 'тогда', 'кто',
        'этот', 'того', 'потому', 'этого', 'какой', 'совсем', 'ним', 'здесь',
        'этом', 'один', 'почти', 'мой', 'тем', 'чтобы', 'нее', 'кажется', 'сюда',
        'туда', 'этой'
    ])

    users = set()

    # Предварительная обработка сообщений по id для быстрого поиска
    messages_by_id = {msg['id']: msg for msg in data.get('messages', [])}

    lemmatizer = WordNetLemmatizer()

    for message in data.get('messages', []):
        total_messages += 1
        user = message.get('from', 'Неизвестный пользователь')
        if user != 'Неизвестный пользователь':
            users.add(user)
            user_message_counts[user] += 1

        # Обработка медиафайлов
        media_type = message.get('media_type')
        if media_type:
            # Перевод типов медиафайлов на русский
            media_type_translations = {
                'voice_message': 'Голосовое сообщение',
                'video_message': 'Видеосообщение',
                'sticker': 'Стикер',
                'video_file': 'Видеофайл',
                'audio_file': 'Аудиофайл'
            }
            translated_media_type = media_type_translations.get(media_type, media_type)
            media_files_counter[translated_media_type] += 1
            user_media_counts[user] += 1

            if media_type in ['video_file', 'video_message']:
                user_video_counts[user] += 1
            elif media_type == 'voice_message':
                user_voice_counts[user] += 1
            elif media_type == 'sticker':
                user_sticker_counts[user] += 1

        cleaned_message = {
            'id': message.get('id'),
            'date': message.get('date'),
            'from': user,
            'text': '',
            'edited': message.get('edited', None),
            'reply_to_message_id': message.get('reply_to_message_id', None),
            'forwarded_from': message.get('forwarded_from', None)
        }

        text_content = message.get('text', '')
        cleaned_text = extract_text(text_content)
        cleaned_message['text'] = cleaned_text
        cleaned_messages.append(cleaned_message)

        message_length = len(cleaned_text)
        user_message_lengths[user].append(message_length)
        total_characters += message_length  # Добавляем к общему количеству символов

        if message_length > 140:
            user_long_messages[user] += 1

        # Анализ редактирования сообщений
        if 'edited' in message and message['edited']:
            message_edits[user] += 1
            total_edit_count += 1

        # Обработка цитат
        if 'reply_to_message_id' in message and message['reply_to_message_id']:
            user_citation_counts[user] += 1
            user_citations_made[user] += 1
            reply_message = messages_by_id.get(message['reply_to_message_id'])
            if reply_message:
                reply_user = reply_message.get('from', 'Неизвестный пользователь')
                if reply_user != 'Неизвестный пользователь':
                    user_citations_received[reply_user] += 1

        # Обработка пересланных сообщений
        forwarded_from = message.get('forwarded_from')
        if forwarded_from:
            if isinstance(forwarded_from, dict):
                # Обработка как словаря
                forwarded_user = forwarded_from.get('from', 'Неизвестный пользователь')
            elif isinstance(forwarded_from, str):
                # Обработка как строки
                forwarded_user = forwarded_from
            else:
                # Другие типы данных
                forwarded_user = 'Неизвестный пользователь'

            user_forwarded_counts[user] += 1
            user_forwarded_from[forwarded_user] += 1
            forwarded_from_counter[forwarded_user] += 1

        # Обработка упоминаний
        mentions = identify_mentions(cleaned_text)
        if mentions:
            user_mentions_made[user] += len(mentions)
            for mention in mentions:
                mentioned_user = mention[1:]  # Удаляем '@'
                user_mentions_received[mentioned_user] += 1

        # Обработка хештегов
        hashtags = identify_hashtags(cleaned_text)
        if hashtags:
            user_hashtags_made[user] += len(hashtags)
            hashtag_counter.update([tag.lower() for tag in hashtags])

        # Обработка ссылок
        links = identify_links(cleaned_text)
        if links:
            user_links_made[user] += len(links)
            for link in links:
                link_type = get_link_type(link)
                link_type_counter[link_type] += 1

        # Анализ времени отправки
        message_date = message.get('date')
        if message_date:
            try:
                dt = datetime.fromisoformat(message_date)
                hour = dt.hour
                weekday = dt.weekday()  # Monday = 0
                time_of_day = get_time_of_day(hour)
                activity_by_hour[hour] += 1
                activity_by_weekday[weekday] += 1
                activity_by_time_of_day[time_of_day] += 1
            except ValueError:
                pass

        # Токенизация и подсчет слов
        words = tokenize_text(cleaned_text)
        words = [word for word in words if word not in russian_stopwords]
        lemmatized_words = [lemmatizer.lemmatize(word) for word in words]
        # Исключаем эмодзи из слов
        lemmatized_words = [word for word in lemmatized_words if not any(char in emoji.EMOJI_DATA for char in word)]
        word_counter.update(lemmatized_words)

        # Анализ эмодзи
        emojis = extract_emojis(cleaned_text)
        if emojis:
            emoji_counter.update(emojis)

        # Сбор текста для тематического моделирования
        texts_for_topic.append(lemmatized_words)

    perform_interactions_analysis = len(users) >= 5

    if perform_interactions_analysis:
        # Анализ взаимодействий между пользователями
        for message in data.get('messages', []):
            user = message.get('from', 'Неизвестный пользователь')
            if user == 'Неизвестный пользователь':
                continue
            reply_message_id = message.get('reply_to_message_id')
            if reply_message_id:
                reply_message = messages_by_id.get(reply_message_id)
                if reply_message:
                    reply_user = reply_message.get('from', 'Неизвестный пользователь')
                    if reply_user != 'Неизвестный пользователь':
                        user_interactions[user][reply_user] += 1
                        user_reply_counts[user] += 1

    # Анализ времени отклика
    if perform_interactions_analysis and len(users) >= 2:
        user_last_message_time = defaultdict(lambda: None)
        for message in sorted(data.get('messages', []), key=lambda x: x.get('date', '')):
            user = message.get('from', 'Неизвестный пользователь')
            if user == 'Неизвестный пользователь':
                continue
            current_date = message.get('date')
            if not current_date:
                continue
            try:
                current_dt = datetime.fromisoformat(current_date)
            except ValueError:
                continue

            # Проверяем дату последнего сообщения от других пользователей
            for other_user in users:
                if other_user == user:
                    continue
                last_time = user_last_message_time[other_user]
                if last_time:
                    response_time = (current_dt - last_time).total_seconds()
                    if response_time > 0:
                        response_times[user].append(response_time)

            # Обновляем время последнего сообщения для текущего пользователя
            user_last_message_time[user] = current_dt

    # Тематическое моделирование
    if texts_for_topic:
        dictionary = corpora.Dictionary(texts_for_topic)
        corpus = [dictionary.doc2bow(text) for text in texts_for_topic]
        lda_model = gensim.models.LdaModel(corpus, num_topics=5, id2word=dictionary, passes=15)
        topics = lda_model.print_topics(num_words=5)
    else:
        topics = []

    # Генерация сетевого графа взаимодействий с исправленным методом
    interaction_graph_html = ""
    if perform_interactions_analysis:
        def generate_interaction_graph(user_interactions):
            G = nx.Graph()
            for user, interactions in user_interactions.items():
                for target, count in interactions.items():
                    G.add_edge(user, target, weight=count)

            if len(G.nodes) == 0:
                return "<p>Нет данных для построения сетевого графа.</p>"

            pos = nx.spring_layout(G)

            # Создание списков для координат
            edge_x = []
            edge_y = []
            for edge in G.edges():
                x0, y0 = pos[edge[0]]
                x1, y1 = pos[edge[1]]
                edge_x += [x0, x1, None]
                edge_y += [y0, y1, None]

            edge_trace = go.Scatter(
                x=edge_x,
                y=edge_y,
                line=dict(width=0.5, color='#888'),
                hoverinfo='none',
                mode='lines'
            )

            node_x = []
            node_y = []
            node_text = []
            node_colors = []

            for node in G.nodes():
                x, y = pos[node]
                node_x.append(x)
                node_y.append(y)
                node_text.append(node)
                node_colors.append(len(list(G.neighbors(node))))

            node_trace = go.Scatter(
                x=node_x,
                y=node_y,
                text=node_text,
                mode='markers+text',
                hoverinfo='text',
                textposition="bottom center",
                marker=dict(
                    showscale=True,
                    colorscale='YlGnBu',
                    color=node_colors,
                    size=10,
                    colorbar=dict(
                        thickness=15,
                        title='Количество связей',
                        xanchor='left',
                        titleside='right'
                    ),
                    line_width=2
                )
            )

            fig = go.Figure(data=[edge_trace, node_trace],
                            layout=go.Layout(
                                title='<br>Сетевой Граф Взаимодействий',
                                titlefont=dict(size=16),
                                showlegend=False,
                                hovermode='closest',
                                margin=dict(b=20, l=5, r=5, t=40),
                                annotations=[dict(
                                    text="",
                                    showarrow=False,
                                    xref="paper", yref="paper")],
                                xaxis=dict(showgrid=False, zeroline=False, showticklabels=False),
                                yaxis=dict(showgrid=False, zeroline=False, showticklabels=False))
                            )
            return fig.to_html(full_html=False)

        interaction_graph_html = generate_interaction_graph(user_interactions)

    # Генерация облака слов
    def generate_word_cloud_image(word_freq, output_path, base_dir):
        if not word_freq:
            return ""
        wc = WordCloud(
            width=800,
            height=400,
            background_color='white',
            font_path=None,  # Укажите путь к шрифту, поддерживающему кириллицу, если необходимо
            colormap='viridis'
        ).generate_from_frequencies(word_freq)
        wc.to_file(os.path.join(base_dir, output_path))
        return output_path

    # Генерация облака слов
    word_cloud_path = "word_cloud.png"
    generate_word_cloud_image(word_counter, word_cloud_path, base_dir)

    # Вычисление среднего размера сообщений
    average_message_size = round(total_characters / total_messages, 2) if total_messages > 0 else 0

    # Вычисление среднего размера сообщений по пользователям
    average_message_size_per_user = {}
    for user, lengths in user_message_lengths.items():
        average = round(sum(lengths) / len(lengths), 2) if lengths else 0
        average_message_size_per_user[user] = average

    # Подготовка результатов
    analysis_results = {
        'cleaned_messages': cleaned_messages,
        'user_message_counts': dict(user_message_counts),
        'user_video_counts': dict(user_video_counts),
        'user_voice_counts': dict(user_voice_counts),
        'user_sticker_counts': dict(user_sticker_counts),
        'user_citation_counts': dict(user_citation_counts),
        'user_mentions_received': dict(user_mentions_received),
        'user_mentions_made': dict(user_mentions_made),
        'hashtag_counts': dict(hashtag_counter),
        'user_hashtags_made': dict(user_hashtags_made),
        'user_links_made': dict(user_links_made),
        'link_type_counts': dict(link_type_counter),
        'activity_by_hour': dict(sorted(activity_by_hour.items())),
        'activity_by_weekday': dict(sorted(activity_by_weekday.items())),
        'activity_by_time_of_day': dict(sorted(activity_by_time_of_day.items())),
        'word_counter': dict(word_counter),
        'emoji_counter': dict(emoji_counter),
        'user_interactions': {user: dict(targets) for user, targets in user_interactions.items()} if perform_interactions_analysis else {},
        'user_reply_counts': dict(user_reply_counts),
        'user_citations_made': dict(user_citations_made),
        'user_citations_received': dict(user_citations_received),
        'user_hashtags_made': dict(user_hashtags_made),
        'user_links_made': dict(user_links_made),
        'user_long_messages': dict(user_long_messages),
        'user_message_lengths': {user: lengths for user, lengths in user_message_lengths.items()},
        'message_edits': dict(message_edits),
        'total_edit_count': total_edit_count,
        'total_messages': total_messages,
        'media_files_counter': dict(media_files_counter),
        'user_media_counts': dict(user_media_counts),
        'response_times': {user: times for user, times in response_times.items()},
        'forwarded_from_counter': dict(forwarded_from_counter),
        'topics': topics,
        'word_cloud_path': word_cloud_path,
        'interaction_graph_html': interaction_graph_html,
        'user_forwarded_counts': dict(user_forwarded_counts),
        'average_message_size': average_message_size,
        'average_message_size_per_user': average_message_size_per_user
    }

    return analysis_results


def generate_html(data, base_dir):
    total_messages = data['total_messages']
    total_edit_count = data['total_edit_count']
    total_links = sum(data['user_links_made'].values())
    total_mentions = sum(data['user_mentions_made'].values())
    total_quotes = sum(data['user_citation_counts'].values())
    average_message_size = data.get('average_message_size', 0)

    edit_percentage = (total_edit_count / total_messages) * 100 if total_messages > 0 else 0

    # Топ-50 слов
    most_common_words = sorted(data['word_counter'].items(), key=lambda x: x[1], reverse=True)[:50]

    # Для дней недели
    weekdays_num = sorted(map(int, data['activity_by_weekday'].keys()), key=int)
    messages_per_weekday = [data['activity_by_weekday'].get(wd, 0) for wd in weekdays_num]
    weekday_labels = ['Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота', 'Воскресенье']
    weekdays_labels = [weekday_labels[wd] for wd in weekdays_num if 0 <= wd < 7]

    # Для времени суток
    time_of_day_labels = list(data['activity_by_time_of_day'].keys())
    messages_time_of_day = list(data['activity_by_time_of_day'].values())

    # Проверка наличия данных для различных анализов
    has_media_files = any(data['media_files_counter'].values())
    word_freq_present = len(most_common_words) > 0
    user_interactions_present = len(data['user_interactions']) > 0
    response_times_present = any(len(v) > 0 for v in data['response_times'].values())
    forwarded_messages_present = any(count > 0 for count in data['forwarded_from_counter'].values())
    topics_present = len(data['topics']) > 0
    average_size_present = average_message_size > 0
    average_size_per_user_present = len(data.get('average_message_size_per_user', {})) > 0

    html_content = f"""
    <!DOCTYPE html>
    <html lang="ru">
    <head>
        <meta charset="UTF-8">
        <title>Статистика Чата</title>
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
        <link rel="stylesheet" href="https://cdn.datatables.net/1.10.21/css/jquery.dataTables.min.css">
        <style>
            body {{
                font-family: Arial, sans-serif;
                margin: 20px;
            }}
            table {{
                width: 100%;
                border-collapse: collapse;
                margin-bottom: 40px;
            }}
            th, td {{
                border: 1px solid #ddd;
                padding: 8px;
                text-align: left;
            }}
            th {{
                background-color: #f2f2f2;
            }}
            h2 {{
                color: #333;
            }}
            .chart-container {{
                width: 100%;
                height: 400px;
                margin-bottom: 40px;
            }}
            .summary {{
                margin-bottom: 40px;
            }}
            .word-cloud {{
                max-width: 100%;
                height: auto;
                margin-bottom: 40px;
            }}
        </style>
        <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
        <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
        <script src="https://cdn.datatables.net/1.10.21/js/jquery.dataTables.min.js"></script>
    </head>
    <body>
        <h1>Статистика Чата</h1>

        <div class="summary">
            <p><strong>Общее количество сообщений:</strong> {total_messages}</p>
            <p><strong>Общее количество редактирований:</strong> {total_edit_count}</p>
            <p><strong>Процент редактированных сообщений:</strong> {edit_percentage:.2f}%</p>
            <p><strong>Общее количество ссылок:</strong> {total_links}</p>
            <p><strong>Общее количество упоминаний:</strong> {total_mentions}</p>
            <p><strong>Общее количество цитирований:</strong> {total_quotes}</p>
    """

    if average_size_present:
        html_content += f"""
            <p><strong>Средний размер сообщений:</strong> {average_message_size} символов</p>
        """

    # Добавление количества сообщений по пользователям
    if average_size_per_user_present:
        html_content += """
            <h2>Количество сообщений по пользователям</h2>
            <table id="userMessageCountsTable" class="display">
                <thead>
                    <tr>
                        <th>Пользователь</th>
                        <th>Количество сообщений</th>
                    </tr>
                </thead>
                <tbody>
        """
        for user, count in sorted(data['user_message_counts'].items(), key=lambda x: x[1], reverse=True):
            html_content += f"""
                    <tr>
                        <td>{html.escape(user)}</td>
                        <td>{count}</td>
                    </tr>
            """
        html_content += """
                </tbody>
            </table>
        """

    # Добавление среднего размера сообщений по пользователям
    if average_size_per_user_present:
        html_content += """
            <h2>Средний размер сообщений по пользователям</h2>
            <table id="averageMessageSizeTable" class="display">
                <thead>
                    <tr>
                        <th>Пользователь</th>
                        <th>Средний размер сообщения (символы)</th>
                    </tr>
                </thead>
                <tbody>
        """
        for user, avg_size in sorted(data['average_message_size_per_user'].items(), key=lambda x: x[1], reverse=True):
            html_content += f"""
                    <tr>
                        <td>{html.escape(user)}</td>
                        <td>{avg_size}</td>
                    </tr>
            """
        html_content += """
                </tbody>
            </table>
        """

    # Анализ Медиафайлов
    html_content += f"""
            <h2>Анализ Медиафайлов</h2>
            <p><strong>Голосовые сообщения:</strong> {data['media_files_counter'].get('Голосовое сообщение', 0)}</p>
            <p><strong>Видеосообщения:</strong> {data['media_files_counter'].get('Видеосообщение', 0)}</p>
            <p><strong>Аудиофайлы:</strong> {data['media_files_counter'].get('Аудиофайл', 0)}</p>
            <p><strong>Видеофайлы:</strong> {data['media_files_counter'].get('Видеофайл', 0)}</p>
            <p><strong>Стикеры:</strong> {data['media_files_counter'].get('Стикер', 0)}</p>
        """

    # Таблица пересланных сообщений
    if forwarded_messages_present:
        html_content += f"""
        <h2>Анализ Пересланных Сообщений</h2>
        <table id="forwardedMessagesTable" class="display">
            <thead>
                <tr>
                    <th>Пользователь</th>
                    <th>Количество Пересланных Сообщений</th>
                </tr>
            </thead>
            <tbody>
        """
        for user, count in sorted(data.get('user_forwarded_counts', {}).items(), key=lambda x: x[1], reverse=True):
            html_content += f"""
                <tr>
                    <td>{html.escape(user)}</td>
                    <td>{count}</td>
                </tr>
            """
        html_content += """
            </tbody>
        </table>

        <h3>Источник Пересылок</h3>
        <table id="forwardedFromTable" class="display">
            <thead>
                <tr>
                    <th>От кого пересылают</th>
                    <th>Количество Пересланных Сообщений</th>
                </tr>
            </thead>
            <tbody>
        """
        for user, count in sorted(data['forwarded_from_counter'].items(), key=lambda x: x[1], reverse=True):
            html_content += f"""
                <tr>
                    <td>{html.escape(user)}</td>
                    <td>{count}</td>
                </tr>
            """
        html_content += """
            </tbody>
        </table>
        """

    # Таблица медиастатистики по пользователям
    html_content += f"""
        <h2>Медиастатистика на Пользователя и Другие Анализы</h2>
        <table id="combinedMediaAndLinksTable" class="display">
            <thead>
                <tr>
                    <th>Пользователь</th>
                    <th>Количество Медиафайлов</th>
                    <th>Видеосообщения</th>
                    <th>Голосовые Сообщения</th>
                    <th>Стикеры</th>
                    <th>Цитирования</th>
                    <th>Отправляет Ссылки</th>
                </tr>
            </thead>
            <tbody>
    """
    users_sorted = sorted(data['user_message_counts'].keys())

    for user in users_sorted:
        media_count = data['user_media_counts'].get(user, 0)
        video_count = data['user_video_counts'].get(user, 0)
        voice_count = data['user_voice_counts'].get(user, 0)
        sticker_count = data['user_sticker_counts'].get(user, 0)
        citation_count = data['user_citation_counts'].get(user, 0)
        links_sent = data['user_links_made'].get(user, 0)

        html_content += f"""
                <tr>
                    <td>{html.escape(user)}</td>
                    <td>{media_count}</td>
                    <td>{video_count}</td>
                    <td>{voice_count}</td>
                    <td>{sticker_count}</td>
                    <td>{citation_count}</td>
                    <td>{links_sent}</td>
                </tr>
        """
    html_content += """
            </tbody>
        </table>
    """

    # Анализ редактирования сообщений
    if total_edit_count > 0:
        html_content += f"""
        <h2>Анализ Редактирования Сообщений</h2>
        <table id="messageEditsTable" class="display">
            <thead>
                <tr>
                    <th>Пользователь</th>
                    <th>Количество Редактирований</th>
                </tr>
            </thead>
            <tbody>
        """
        for user, count in sorted(data['message_edits'].items(), key=lambda x: x[1], reverse=True):
            html_content += f"""
                <tr>
                    <td>{html.escape(user)}</td>
                    <td>{count}</td>
                </tr>
            """
        html_content += """
            </tbody>
        </table>
        """

    # Анализ временной активности
    html_content += """
    <h2>Активность Пользователей</h2>
    <div class="chart-container">
        <canvas id="activityByHourChart"></canvas>
    </div>
    <div class="chart-container">
        <canvas id="activityByWeekdayChart"></canvas>
    </div>
    <div class="chart-container">
        <canvas id="activityByTimeOfDayChart"></canvas>
    </div>
    """

    # Частотный анализ слов
    if word_freq_present:
        html_content += """
        <h2>Частотный Анализ Слов (Топ-50)</h2>
        <table id="wordFrequencyTable" class="display">
            <thead>
                <tr>
                    <th>Слово</th>
                    <th>Частота</th>
                </tr>
            </thead>
            <tbody>
        """
        for word, freq in most_common_words:
            html_content += f"""
                <tr>
                    <td>{html.escape(word)}</td>
                    <td>{freq}</td>
                </tr>
            """
        html_content += """
            </tbody>
        </table>
        """

    # Облако слов
    word_cloud_full_path = os.path.join(base_dir, data['word_cloud_path'])
    if word_freq_present and os.path.exists(word_cloud_full_path):
        html_content += f"""
        <h2>Облако Слов</h2>
        <img src="{data['word_cloud_path']}" alt="Облако Слов" class="word-cloud">
        """

    # Частотный анализ эмодзи
    if len(data['emoji_counter']) > 0:
        most_common_emojis = sorted(data['emoji_counter'].items(), key=lambda x: x[1], reverse=True)[:50]
        html_content += """
        <h2>Частотный Анализ Эмодзи (Топ-50)</h2>
        <table id="emojiFrequencyTable" class="display">
            <thead>
                <tr>
                    <th>Эмодзи</th>
                    <th>Частота</th>
                </tr>
            </thead>
            <tbody>
        """
        for emj, freq in most_common_emojis:
            html_content += f"""
                <tr>
                    <td>{emj}</td>
                    <td>{freq}</td>
                </tr>
            """
        html_content += """
            </tbody>
        </table>
        """

    # Анализ взаимодействий между пользователями
    if user_interactions_present:
        interactions_data = []
        for user, interactions in data['user_interactions'].items():
            for target, count in interactions.items():
                interactions_data.append((user, target, count))

        if interactions_data:
            html_content += """
            <h2>Анализ Взаимодействий между Пользователями</h2>
            <div>
                """ + data['interaction_graph_html'] + """
            </div>
            <table id="userInteractionsTable" class="display">
                <thead>
                    <tr>
                        <th>Отправитель</th>
                        <th>Получатель</th>
                        <th>Количество</th>
                    </tr>
                </thead>
                <tbody>
            """
            for sender, receiver, count in interactions_data:
                html_content += f"""
                    <tr>
                        <td>{html.escape(sender)}</td>
                        <td>{html.escape(receiver)}</td>
                        <td>{count}</td>
                    </tr>
                """
            html_content += """
                </tbody>
            </table>
            """

    # Анализ времени отклика
    if response_times_present:
        html_content += """
        <h2>Анализ Времени Отклика</h2>
        <table id="responseTimesTable" class="display">
            <thead>
                <tr>
                    <th>Пользователь</th>
                    <th>Среднее Время Отклика (секунды)</th>
                    <th>Медиана Времени Отклика (секунды)</th>
                    <th>Стандартное Отлонение (секунды)</th>
                </tr>
            </thead>
            <tbody>
        """
        for user, times in data['response_times'].items():
            if times:
                average = round(sum(times) / len(times), 2)
                sorted_times = sorted(times)
                median = round(sorted_times[len(sorted_times) // 2], 2) if len(sorted_times) > 0 else 0
                variance = sum((x - average) ** 2 for x in times) / len(times) if len(times) > 0 else 0
                std_dev = round(variance ** 0.5, 2)
                html_content += f"""
                    <tr>
                        <td>{html.escape(user)}</td>
                        <td>{average}</td>
                        <td>{median}</td>
                        <td>{std_dev}</td>
                    </tr>
                """
            else:
                html_content += f"""
                    <tr>
                        <td>{html.escape(user)}</td>
                        <td>0</td>
                        <td>0</td>
                        <td>0</td>
                    </tr>
                """
        html_content += """
            </tbody>
        </table>
        """

    # Тематическое моделирование
    if topics_present:
        html_content += f"""
        <h2>Тематическое Моделирование</h2>
        <table id="topicsTable" class="display">
            <thead>
                <tr>
                    <th>Тема</th>
                    <th>Ключевые Слова</th>
                </tr>
            </thead>
            <tbody>
        """
        for idx, topic in data['topics']:
            html_content += f"""
                <tr>
                    <td>{idx}</td>
                    <td>{html.escape(topic)}</td>
                </tr>
            """
        html_content += """
            </tbody>
        </table>
        """

    html_content += """
    <h2>Распределение Активности</h2>
    <div class="chart-container">
        <canvas id="activityByHourChart"></canvas>
    </div>
    <div class="chart-container">
        <canvas id="activityByWeekdayChart"></canvas>
    </div>
    <div class="chart-container">
        <canvas id="activityByTimeOfDayChart"></canvas>
    </div>
    """

    # Добавление графиков
    # График активности по часам
    hours = sorted(map(int, data['activity_by_hour'].keys()))
    messages_per_hour = [data['activity_by_hour'].get(hour, 0) for hour in hours]
    labels_hours = [str(hour) for hour in hours]

    # График активности по дням недели
    labels_weekdays = weekdays_labels

    # График активности по времени суток
    labels_time_of_day = time_of_day_labels
    messages_time_of_day = messages_time_of_day

    html_content += f"""
    <script>
        // Данные для графика активности по часам
        const activityByHourCtx = document.getElementById('activityByHourChart').getContext('2d');
        const activityByHourChart = new Chart(activityByHourCtx, {{
            type: 'bar',
            data: {{
                labels: {json.dumps(labels_hours)},
                datasets: [{{
                    label: 'Количество Сообщений',
                    data: {json.dumps(messages_per_hour)},
                    backgroundColor: 'rgba(54, 162, 235, 0.6)',
                    borderColor: 'rgba(54, 162, 235, 1)',
                    borderWidth: 1
                }}]
            }},
            options: {{
                scales: {{
                    x: {{
                        title: {{
                            display: true,
                            text: 'Часы'
                        }}
                    }},
                    y: {{
                        beginAtZero: true,
                        title: {{
                            display: true,
                            text: 'Количество Сообщений'
                        }}
                    }}
                }}
            }}
        }});

        // Данные для графика активности по дням недели
        const activityByWeekdayCtx = document.getElementById('activityByWeekdayChart').getContext('2d');
        const activityByWeekdayChart = new Chart(activityByWeekdayCtx, {{
            type: 'bar',
            data: {{
                labels: {json.dumps(labels_weekdays)},
                datasets: [{{
                    label: 'Количество Сообщений',
                    data: {json.dumps(messages_per_weekday)},
                    backgroundColor: 'rgba(255, 99, 132, 0.6)',
                    borderColor: 'rgba(255, 99, 132, 1)',
                    borderWidth: 1
                }}]
            }},
            options: {{
                scales: {{
                    x: {{
                        title: {{
                            display: true,
                            text: 'Дни Недели'
                        }}
                    }},
                    y: {{
                        beginAtZero: true,
                        title: {{
                            display: true,
                            text: 'Количество Сообщений'
                        }}
                    }}
                }}
            }}
        }});

        // Данные для графика активности по времени суток
        const activityByTimeOfDayCtx = document.getElementById('activityByTimeOfDayChart').getContext('2d');
        const activityByTimeOfDayChart = new Chart(activityByTimeOfDayCtx, {{
            type: 'bar',
            data: {{
                labels: {json.dumps(labels_time_of_day)},
                datasets: [{{
                    label: 'Количество Сообщений',
                    data: {json.dumps(messages_time_of_day)},
                    backgroundColor: 'rgba(153, 102, 255, 0.6)',
                    borderColor: 'rgba(153, 102, 255, 1)',
                    borderWidth: 1
                }}]
            }},
            options: {{
                scales: {{
                    x: {{
                        title: {{
                            display: true,
                            text: 'Время Суток'
                        }}
                    }},
                    y: {{
                        beginAtZero: true,
                        title: {{
                            display: true,
                            text: 'Количество Сообщений'
                        }}
                    }}
                }}
            }}
        }});

        // Инициализация DataTables
        $(document).ready(function() {{
            $('#mediaFilesTable').DataTable({{
                "paging": false,
                "searching": false,
                "info": false
            }});
            $('#combinedMediaAndLinksTable').DataTable({{
                "paging": false,
                "searching": false,
                "info": false
            }});
            $('#userMessageCountsTable').DataTable({{
                "paging": false,
                "searching": false,
                "info": false
            }});
            $('#averageMessageSizeTable').DataTable({{
                "paging": false,
                "searching": false,
                "info": false
            }});
    """

    if forwarded_messages_present:
        html_content += """
            $('#forwardedMessagesTable').DataTable({
                "paging": false,
                "searching": false,
                "info": false
            });
            $('#forwardedFromTable').DataTable({
                "paging": false,
                "searching": false,
                "info": false
            });
        """

    if total_edit_count > 0:
        html_content += """
            $('#messageEditsTable').DataTable({
                "paging": false,
                "searching": false,
                "info": false
            });
        """

    if word_freq_present:
        html_content += """
            $('#wordFrequencyTable').DataTable({
                "paging": false,
                "searching": false,
                "info": false
            });
        """

    if len(data['emoji_counter']) > 0:
        html_content += """
            $('#emojiFrequencyTable').DataTable({
                "paging": false,
                "searching": false,
                "info": false
            });
        """

    if user_interactions_present:
        html_content += """
            $('#userInteractionsTable').DataTable({
                "paging": false,
                "searching": false,
                "info": false
            });
        """

    if response_times_present:
        html_content += """
            $('#responseTimesTable').DataTable({
                "paging": false,
                "searching": false,
                "info": false
            });
        """

    if topics_present:
        html_content += """
            $('#topicsTable').DataTable({
                "paging": false,
                "searching": false,
                "info": false
            });
        """

    html_content += """
        });
    </script>

    </body>
    </html>
    """

    return html_content


if __name__ == "__main__":
    # Замените путь ниже на путь к вашей директории
    base_dir = r"C:\Users\Admin\Downloads\AyuGram Desktop\ChatExport_2024-09-23 (7)"
    input_file = os.path.join(base_dir, "result.json")
    # output_json = os.path.join(base_dir, "cleaned_result.json")  # Удалено
    output_html = os.path.join(base_dir, "chat_statistics.html")

    data = load_json(input_file)
    if data:
        analyzed_data = analyze_data(data, base_dir)
        # save_json(analyzed_data, output_json)  # Удалено
        html_content = generate_html(analyzed_data, base_dir)
        save_html(html_content, output_html)
(Предложи, как можно улучшить HTML: 1. внешний вид чтобы файл был один-html. 2. функциональность и улучшить скорость работы создания html.)