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

# Для загрузки данных 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_json(data, file_path):
    try:
        with open(file_path, 'w', encoding='utf-8') as outfile:
            json.dump(data, outfile, ensure_ascii=False, indent=2)
            print(f"Данные успешно сохранены в '{file_path}'.")
    except Exception as e:
        print(f"Ошибка при сохранении файла: {e}")


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):
    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
    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)

        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:
            forwarded_user = forwarded_from.get('from', 'Неизвестный пользователь')
            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:]  # Удаляем '@'sz
                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]
        word_counter.update(lemmatized_words)

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

        # Анализ взаимодействий между пользователями
        if 'reply_to_message_id' in message and message['reply_to_message_id']:
            reply_message_id = message['reply_to_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

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

    # Анализ времени отклика
    if len(users) >= 2:
        user_last_message_time = defaultdict(lambda: None)
        for message in data.get('messages', []):
            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

    # Анализ настроений
    sentiments = []
    for message in cleaned_messages:
        cleaned_text = message['text']
        blob = TextBlob(cleaned_text)
        sentiment_polarity = blob.sentiment.polarity
        sentiments.append(sentiment_polarity)

    average_sentiment = sum(sentiments) / len(sentiments) if sentiments else 0

    # Тематическое моделирование
    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 = []

    # Генерация сетевого графа взаимодействий
    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_trace = go.Scatter(
            x=[],
            y=[],
            line=dict(width=0.5, color='#888'),
            hoverinfo='none',
            mode='lines')

        for edge in G.edges():
            x0, y0 = pos[edge[0]]
            x1, y1 = pos[edge[1]]
            edge_trace['x'] += [x0, x1, None]
            edge_trace['y'] += [y0, y1, None]

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

        for node in G.nodes():
            x, y = pos[node]
            node_trace['x'] += [x]
            node_trace['y'] += [y]
            node_trace['marker']['color'] += [len(list(G.neighbors(node)))]
            node_trace['text'] += [node]

        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):
        if not word_freq:
            return ""
        wc = WordCloud(width=800, height=400, background_color='white').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)

    # Генерация облака эмодзи
    def generate_emoji_cloud_image(emoji_freq, output_path):
        if not emoji_freq:
            return ""
        wc = WordCloud(width=800, height=400, background_color='white', font_path=None)
        wc.generate_from_frequencies(emoji_freq)
        wc.to_file(os.path.join(base_dir, output_path))
        return output_path

    emoji_cloud_path = "emoji_cloud.png"
    generate_emoji_cloud_image(emoji_counter, emoji_cloud_path)

    # Подготовка результатов
    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()},
        '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),
        'sentiment_average': average_sentiment,
        'topics': topics,
        'word_cloud_path': word_cloud_path,
        'emoji_cloud_path': emoji_cloud_path,
        'interaction_graph_html': interaction_graph_html
    }

    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_sentiment = data.get('sentiment_average', 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 = any(len(v) > 0 for v in data['user_interactions'].values())
    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

    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, .emoji-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>
            <p><strong>Средний показатель настроений:</strong> {average_sentiment:.2f}</p>
        </div>

        <h2>Анализ Медиафайлов</h2>
        <table id="mediaFilesTable" class="display">
            <thead>
                <tr>
                    <th>Тип Медиафайла</th>
                    <th>Количество</th>
                </tr>
            </thead>
            <tbody>
    """

    # Таблица медиафайлов
    for media_type, count in sorted(data['media_files_counter'].items(), key=lambda x: x[1], reverse=True):
        html_content += f"""
                <tr>
                    <td>{html.escape(media_type)}</td>
                    <td>{count}</td>
                </tr>
        """
    html_content += """
            </tbody>
        </table>
    """

    # Таблица пересланных сообщений
    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['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>
        """

        # Облако эмодзи
        emoji_cloud_full_path = os.path.join(base_dir, data['emoji_cloud_path'])
        if os.path.exists(emoji_cloud_full_path):
            html_content += f"""
            <h2>Облако Эмодзи</h2>
            <img src="{data['emoji_cloud_path']}" alt="Облако Эмодзи" class="emoji-cloud">
            """

    # Анализ взаимодействий между пользователями
    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 += f"""
    <h2>Средний Показатель Настроений</h2>
    <p>{average_sentiment:.2f}</p>
    """

    # График распределения настроений
    html_content += """
    <h2>Распределение Настроений</h2>
    <div class="chart-container">
        <canvas id="sentimentChart"></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]

    # График активности по дням недели
    messages_per_weekday = [data['activity_by_weekday'].get(wd, 0) for wd in weekdays_num]
    labels_weekdays = weekdays_labels

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

    # Подготовка данных для графика настроений (позитивные, нейтральные, негативные)
    sentiment_counts = {
        'Позитивные': len([s for s in data['sentiment_average'] if s > 0]),
        'Нейтральные': len([s for s in data['sentiment_average'] if s == 0]),
        'Негативные': len([s for s in data['sentiment_average'] if s < 0])
    }

    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: 'Количество Сообщений'
                        }}
                    }}
                }}
            }}
        }});

        // График распределения настроений
        const sentimentCtx = document.getElementById('sentimentChart').getContext('2d');
        const sentimentChart = new Chart(sentimentCtx, {{
            type: 'bar',
            data: {{
                labels: {json.dumps(list(sentiment_counts.keys()))},
                datasets: [{{
                    label: 'Распределение Настроений',
                    data: {json.dumps(list(sentiment_counts.values()))},
                    backgroundColor: [
                        'rgba(75, 192, 192, 0.6)',
                        'rgba(201, 203, 207, 0.6)',
                        'rgba(255, 99, 132, 0.6)'
                    ],
                    borderColor: [
                        'rgba(75, 192, 192, 1)',
                        'rgba(201, 203, 207, 1)',
                        'rgba(255, 99, 132, 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
            }});
    """
    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__":
    # Рекомендуется использовать os.path.join для построения путей
    base_dir = r"C:\Users\Admin\Downloads\AyuGram Desktop\ChatExport_2024-09-23 (4)"
    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)
        save_json(analyzed_data, output_json)
        html_content = generate_html(analyzed_data, base_dir)
        save_html(html_content, output_html)

(выдает ошибку в строке- { forwarded_user = forwarded_from.get('from', 'Неизвестный пользователь')} ошибка- {'str' object has no attribute 'get'}    и  [nltk_data] Downloading package punkt to
[nltk_data]     C:\Users\Admin\AppData\Roaming\nltk_data...
[nltk_data]   Package punkt is already up-to-date!
[nltk_data] Downloading package wordnet to
[nltk_data]     C:\Users\Admin\AppData\Roaming\nltk_data...
[nltk_data]   Package wordnet is already up-to-date!
Backend tkagg is interactive backend. Turning interactive mode on. )