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 = {
"&": "&",
"<": "<",
">": ">",
'"': """,
"'": "'"
}
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)                   (Активность пользователей и анализ взаимодействий между пользователями, ничего нет, графики не отображаются, исправь, и другие ошибки.)