import json
import os
import string
import re
from collections import defaultdict, Counter
from datetime import datetime

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 analyze_data(data):
    cleaned_messages = []
    user_message_counts = {}
    user_message_lengths = defaultdict(list)
    activity_by_hour = defaultdict(int)
    activity_by_weekday = defaultdict(int)
    activity_by_month = defaultdict(int)
    activity_by_time_of_day = defaultdict(int)
    word_counter = Counter()
    user_interactions = defaultdict(lambda: defaultdict(int))
    duplicate_messages = defaultdict(int)
    forwarded_messages_count = 0
    media_counts = defaultdict(int)
    user_media_counts = defaultdict(lambda: defaultdict(int))
    mutual_mentions = defaultdict(Counter)

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

    media_type_translations = {
        'voice_message': 'голосовое сообщение',
        'sticker': 'стикер',
        'video_file': 'видео файл',
        'video_message': 'видео сообщение',
        'audio_file': 'аудио файл',
        'photo': 'фотография',
        'animation': 'анимация',
        'document': 'документ',
        'location': 'локация',
        'contact': 'контакт',
        'poll': 'опрос',
        'game': 'игра',
        'invoice': 'счёт',
        'contact_registered': 'контакт зарегистрирован',
    }

    users = set()

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

        users.add(user)
        user_message_counts[user] = user_message_counts.get(user, 0) + 1

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

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

        # Анализ дублирующихся сообщений (только если текст не пустой)
        if cleaned_text.strip():
            duplicate_key = (user, cleaned_text)
            duplicate_messages[duplicate_key] += 1

        # Анализ пересланных сообщений
        if 'forwarded_from' in message:
            forwarded_messages_count += 1

        # Анализ медиа сообщений
        media_type = message.get('media_type')
        if media_type:
            media_type_translated = media_type_translations.get(media_type, media_type)
            media_counts[media_type_translated] += 1
            user_media_counts[user][media_type_translated] += 1

        # Подсчет длины сообщений
        message_length = len(cleaned_text)
        user_message_lengths[user].append(message_length)

        # Анализ времени активности
        message_date_str = message.get('date')
        try:
            message_date = datetime.fromisoformat(message_date_str)
            hour = message_date.hour
            weekday = message_date.weekday()  # Понедельник = 0
            month = message_date.month  # Январь = 1
            time_of_day = get_time_of_day(hour)
            activity_by_hour[hour] += 1
            activity_by_weekday[weekday] += 1
            activity_by_month[month] += 1
            activity_by_time_of_day[time_of_day] += 1
        except (ValueError, TypeError):
            pass  # Пропустить сообщения с некорректными датами

        # Анализ частотности слов
        words = tokenize_text(cleaned_text)
        words = [word for word in words if word.lower() not in russian_stopwords]
        word_counter.update(words)

        # Анализ упоминаний пользователей
        mentions = re.findall(r'@(\w+)', cleaned_text)
        for mention in mentions:
            mutual_mentions[user][mention] += 1

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

    # Обрезка дублирующихся сообщений
    duplicates = {k: v for k, v in duplicate_messages.items() if v > 1}

    return {
        'cleaned_messages': cleaned_messages,
        'user_message_counts': user_message_counts,
        'user_message_lengths': user_message_lengths,
        'activity_by_hour': dict(sorted(activity_by_hour.items())),
        'activity_by_weekday': dict(sorted(activity_by_weekday.items())),
        'activity_by_month': dict(sorted(activity_by_month.items())),
        'activity_by_time_of_day': dict(sorted(activity_by_time_of_day.items())),
        'word_counter': word_counter,
        'user_interactions': user_interactions,
        'duplicate_messages': duplicates,
        'forwarded_messages_count': forwarded_messages_count,
        'media_counts': media_counts,
        'user_media_counts': user_media_counts,
        'mutual_mentions': mutual_mentions,
    }

def escape_html(text):
    replacements = {
        "&": "&amp;",
        "<": "&lt;",
        ">": "&gt;",
        '"': "&quot;",
        "'": "&#39;"
    }
    return ''.join(replacements.get(c, c) for c in text)

def generate_html(data):
    total_messages = len(data['cleaned_messages'])
    total_media_messages = sum(data['media_counts'].values())
    user_average_lengths = {user: round(sum(lengths) / len(lengths), 2) if lengths else 0 for user, lengths in data['user_message_lengths'].items()}
    most_common_words = data['word_counter'].most_common(50)
    duplicate_count = sum(data['duplicate_messages'].values()) - len(data['duplicate_messages'])
    forwarded_messages = data['forwarded_messages_count']
    media_counts = data['media_counts']
    user_media_counts = data['user_media_counts']
    mutual_mentions = data['mutual_mentions']

    # Для построения графиков
    hours = list(data['activity_by_hour'].keys())
    messages_per_hour = list(data['activity_by_hour'].values())

    # Для дней недели
    weekdays = list(data['activity_by_weekday'].keys())
    messages_per_weekday = list(data['activity_by_weekday'].values())
    weekdays, messages_per_weekday = zip(*sorted(zip(weekdays, messages_per_weekday)))
    weekday_labels = ['Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота', 'Воскресенье']
    weekdays = [weekday_labels[wd] for wd in weekdays]

    # Для месяцев
    months = list(data['activity_by_month'].keys())
    messages_per_month = list(data['activity_by_month'].values())
    months, messages_per_month = zip(*sorted(zip(months, messages_per_month)))
    month_labels = ['Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь',
                    'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь']
    months = [month_labels[month - 1] for month in months]

    time_of_day = list(data['activity_by_time_of_day'].keys())
    messages_per_time_of_day = list(data['activity_by_time_of_day'].values())

    # Собираем все возможные типы медиа
    all_media_types = set()
    for user_media in user_media_counts.values():
        all_media_types.update(user_media.keys())
    all_media_types = sorted(all_media_types)

    html = 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;
            }}
            .bold {{
                font-weight: bold;
            }}
        </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_media_messages}</p>
            <p><strong>Количество дублирующихся сообщений:</strong> {duplicate_count}</p>
            <p><strong>Количество пересланных сообщений:</strong> {forwarded_messages}</p>
        </div>

        <h2>Количество Сообщений на Пользователя</h2>
        <table id="userMessagesTable" 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 += f"""
                <tr>
                    <td>{escape_html(user)}</td>
                    <td>{count}</td>
                </tr>
        """
    html += """
            </tbody>
        </table>

        <h2>Анализ Медиа Сообщений</h2>
        <table id="mediaMessagesTable" class="display">
            <thead>
                <tr>
                    <th>Пользователь</th>
    """

    for media_type in all_media_types:
        html += f"<th>{media_type}</th>"

    html += """
                </tr>
            </thead>
            <tbody>
    """

    for user in data['user_message_counts'].keys():
        html += f"<tr><td>{escape_html(user)}</td>"
        user_media = user_media_counts.get(user, {})
        for media_type in all_media_types:
            count = user_media.get(media_type, 0)
            html += f"<td>{count}</td>"
        html += "</tr>"

    html += """
            </tbody>
        </table>

        <h2>Средняя Длина Сообщений на Пользователя</h2>
        <table id="userAverageLengthsTable" class="display">
            <thead>
                <tr>
                    <th>Пользователь</th>
                    <th>Средняя Длина Сообщения</th>
                </tr>
            </thead>
            <tbody>
    """

    for user, avg_len in sorted(user_average_lengths.items(), key=lambda x: x[1], reverse=True):
        html += f"""
                <tr>
                    <td>{escape_html(user)}</td>
                    <td>{avg_len}</td>
                </tr>
        """
    html += """
            </tbody>
        </table>

        <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="activityByMonthChart"></canvas>
        </div>
        <div class="chart-container">
            <canvas id="activityByTimeOfDayChart"></canvas>
        </div>

        <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 += f"""
                <tr>
                    <td>{escape_html(word)}</td>
                    <td>{freq}</td>
                </tr>
        """
    html += """
            </tbody>
        </table>

        <h2>Анализ Взаимодействий между Пользователями</h2>
        <div class="chart-container">
            <canvas id="userInteractionsChart"></canvas>
        </div>

        <h2>Дублирующиеся Сообщения</h2>
        <table id="duplicateMessagesTable" class="display">
            <thead>
                <tr>
                    <th>Пользователь</th>
                    <th>Текст Сообщения</th>
                    <th>Количество Повторений</th>
                </tr>
            </thead>
            <tbody>
    """

    for (user, text), count in data['duplicate_messages'].items():
        html += f"""
                <tr>
                    <td>{escape_html(user)}</td>
                    <td>{escape_html(text)}</td>
                    <td>{count}</td>
                </tr>
        """
    html += """
            </tbody>
        </table>

        <h2>Взаимные Упоминания Пользователей</h2>
        <table id="mutualMentionsTable" class="display">
            <thead>
                <tr>
                    <th>Пользователь</th>
                    <th>Упомянутый Пользователь</th>
                    <th>Количество Упоминаний</th>
                </tr>
            </thead>
            <tbody>
    """

    for user, mentions in data['mutual_mentions'].items():
        for mentioned_user, count in mentions.items():
            html += f"""
                <tr>
                    <td>{escape_html(user)}</td>
                    <td>{escape_html(mentioned_user)}</td>
                    <td>{count}</td>
                </tr>
            """
    html += """
            </tbody>
        </table>

        <script>
            // Данные для графиков активности
            const hours = """ + json.dumps(hours) + """;
            const messagesPerHour = """ + json.dumps(messages_per_hour) + """;

            const weekdays = """ + json.dumps(weekdays) + """;
            const messagesPerWeekday = """ + json.dumps(messages_per_weekday) + """;

            const months = """ + json.dumps(months) + """;
            const messagesPerMonth = """ + json.dumps(messages_per_month) + """;

            const timeOfDay = """ + json.dumps(time_of_day) + """;
            const messagesPerTimeOfDay = """ + json.dumps(messages_per_time_of_day) + """;

            // График активности по часам
            const ctxHour = document.getElementById('activityByHourChart').getContext('2d');
            new Chart(ctxHour, {{
                type: 'bar',
                data: {{
                    labels: hours,
                    datasets: [{{
                        label: 'Количество Сообщений',
                        data: messagesPerHour,
                        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 ctxWeekday = document.getElementById('activityByWeekdayChart').getContext('2d');
            new Chart(ctxWeekday, {{
                type: 'bar',
                data: {{
                    labels: weekdays,
                    datasets: [{{
                        label: 'Количество Сообщений',
                        data: messagesPerWeekday,
                        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 ctxMonth = document.getElementById('activityByMonthChart').getContext('2d');
            new Chart(ctxMonth, {{
                type: 'bar',
                data: {{
                    labels: months,
                    datasets: [{{
                        label: 'Количество Сообщений',
                        data: messagesPerMonth,
                        backgroundColor: 'rgba(75, 192, 192, 0.6)',
                        borderColor: 'rgba(75, 192, 192, 1)',
                        borderWidth: 1
                    }}]
                }},
                options: {{
                    scales: {{
                        x: {{
                            title: {{
                                display: true,
                                text: 'Месяцы'
                            }}
                        }},
                        y: {{
                            beginAtZero: true,
                            title: {{
                                display: true,
                                text: 'Количество Сообщений'
                            }}
                        }}
                    }}
                }}
            }});

            // График активности по времени суток
            const ctxTimeOfDay = document.getElementById('activityByTimeOfDayChart').getContext('2d');
            new Chart(ctxTimeOfDay, {{
                type: 'bar',
                data: {{
                    labels: timeOfDay,
                    datasets: [{{
                        label: 'Количество Сообщений',
                        data: messagesPerTimeOfDay,
                        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 interactionLabels = """ + json.dumps(list(data['user_interactions'].keys())) + """;
            const interactionData = """ + json.dumps([sum(interactions.values()) for interactions in data['user_interactions'].values()]) + """;

            const ctxInteractions = document.getElementById('userInteractionsChart').getContext('2d');
            new Chart(ctxInteractions, {{
                type: 'bar',
                data: {{
                    labels: interactionLabels,
                    datasets: [{{
                        label: 'Количество Взаимодействий',
                        data: interactionData,
                        backgroundColor: 'rgba(255, 159, 64, 0.6)',
                        borderColor: 'rgba(255, 159, 64, 1)',
                        borderWidth: 1
                    }}]
                }},
                options: {{
                    scales: {{
                        x: {{
                            title: {{
                                display: true,
                                text: 'Пользователи'
                            }}
                        }},
                        y: {{
                            beginAtZero: true,
                            title: {{
                                display: true,
                                text: 'Количество Взаимодействий'
                            }}
                        }}
                    }}
                }}
            }});

            // Инициализация DataTables
            $(document).ready(function() {
                $('#userMessagesTable').DataTable({
                    "paging": false,
                    "searching": true,
                    "info": false
                });
                $('#userAverageLengthsTable').DataTable({
                    "paging": false,
                    "searching": true,
                    "info": false
                });
                $('#wordFrequencyTable').DataTable({
                    "paging": false,
                    "searching": true,
                    "info": false
                });
                $('#duplicateMessagesTable').DataTable({
                    "paging": false,
                    "searching": true,
                    "info": false
                });
                $('#mediaMessagesTable').DataTable({
                    "paging": false,
                    "searching": true,
                    "info": false
                });
                $('#mutualMentionsTable').DataTable({
                    "paging": false,
                    "searching": true,
                    "info": false
                });
            });
        </script>

    </body>
    </html>
    """

    return html

if __name__ == "__main__":
    # Пути к файлам
    input_file = r"C:\Users\Admin\Downloads\AyuGram Desktop\ChatExport_2024-09-23 (1)\result.json"
    output_json = r"C:\Users\Admin\Downloads\AyuGram Desktop\ChatExport_2024-09-23 (1)\cleaned_result.json"
    output_html = r"C:\Users\Admin\Downloads\AyuGram Desktop\ChatExport_2024-09-23 (1)\chat_statistics.html"

    data = load_json(input_file)
    if data:
        analyzed_data = analyze_data(data)
        save_json(analyzed_data['cleaned_messages'], output_json)
        html_content = generate_html(analyzed_data)
        save_html(html_content, output_html)                   (Активность пользователей и анализ взаимодействий между пользователями, ничего нет, графики не отображаются, исправь, и другие ошибки.)