import configparser
import random
import keyboard
import json
import os
import sys
import threading
import asyncio
import socket
import emoji
from datetime import datetime, timedelta
import time
import tzlocal
from zoneinfo import ZoneInfo
from http.server import BaseHTTPRequestHandler, HTTPServer
from urllib import parse
from datetime import timezone

# Чтение конфигурации
config = configparser.ConfigParser()
config.read("config.ini")

# Инициализация модулей на основе конфигурации
chat_connectors = {}
chat_comments = {}

# Telegram
if config.getboolean('Telegram', 'enabled', fallback=False):
    import telegram
    bot = telegram.Bot(config['Telegram']['bot_secret'])
    chat_connectors['telegram'] = bot
    chat_comments['tg'] = []

# YouTube
if config.getboolean('YouTube', 'enabled', fallback=False):
    print('Youtube enabled')
    import pytchat
    video_id = config['YouTube']['video_id']
    chat = pytchat.create(video_id=video_id)
    chat_connectors['youtube'] = chat
    chat_comments['yt'] = []

# Twitch
TWITCH_CHANNEL = None
if config.getboolean('Twitch', 'enabled', fallback=False):
    sys.path.append('twitchchatirc')
    import twitch
    twitch_channel = config['Twitch']['channel']
    twitch_socket = twitch.TwitchChatIRC(twitch_channel)
    chat_connectors['twitch'] = twitch_socket
    TWITCH_CHANNEL = config['Twitch']['channel']
    chat_comments['tw'] = []

# Функции для работы с датами
class DateTimeEncoder(json.JSONEncoder):
    def default(self, o):
        if isinstance(o, datetime):
            return o.isoformat()
        if isinstance(o, bytes):
            return list(o)
        return json.JSONEncoder.default(self, o)

LOCAL_TIMEZONE = tzlocal.get_localzone_name()
tz = ZoneInfo('Asia/Yekaterinburg')

all_comments = []
all_old_comments = []
is_changed = False
overallcount = 0
last_tg_update_id = 0

# Получение комментариев из Telegram
async def get_telegram_comments():
    global chat_comments
    global last_tg_update_id
    chat_comments['tg'] = []

    if 'telegram' not in chat_connectors:
        return

    async with bot:
        try:
            updates = await bot.get_updates(
                offset=last_tg_update_id + 1,
                allowed_updates=['message', 'edited_message'], 
                timeout=None
                )
        except telegram.error.TimedOut:
            print('TG connection timeout')
            time.sleep(5)
            return
        except Exception as e:
            print(f'TG connection error: {e}')
            return
        
        if not updates:
            return
        
        last_tg_update_id = updates[-1].update_id

        for upd in updates:
            msg = upd.message
            if upd.edited_message:
                msg = upd.edited_message

            if not hasattr(msg, 'text') or not msg.text:
                continue

            sendr = msg.from_user.first_name
            if msg.from_user.last_name:
                sendr = sendr + ' ' + msg.from_user.last_name

            if sendr == "Group":
                sendr = 'Админ'

            try:
                netdatetime = msg.date.replace(tzinfo=timezone.utc).astimezone(tz)
                
                comm = {
                    'id': msg.message_id,
                    'type': 'tg',
                    'date': netdatetime,
                    'sendr': sendr,
                    'msg': msg.text
                }
                chat_comments['tg'].append(comm)
            except Exception as e:
                print(f"Ошибка преобразования времени: {e}")



# Получение комментариев из YouTube
def get_youtube_comments():
    global chat_comments
    
    if 'youtube' not in chat_connectors:
        return

    chat = chat_connectors['youtube']
    itms = chat.get()
    
    if not hasattr(itms, 'items'):
        print('YT has no items attribute! (Empty?). Reconnecting...')
        time.sleep(5)
        video_id = config['YouTube']['video_id']
        chat_connectors['youtube'] = pytchat.create(video_id=video_id)
        return
        
    for c in itms.items:
        dt = datetime.fromisoformat(c.datetime).replace(tzinfo=tz)
        comm = {
            'id': c.id,
            'type': 'yt',
            'date': dt,
            'sendr': c.author.name,
            'msg': emoji.emojize(c.message)
        }
        chat_comments['yt'].append(comm)

# Получение комментариев из Twitch
def get_twitch_comments():
    global chat_comments
    
    if 'twitch' not in chat_connectors:
        return
        
    chat_comments['tw'] = chat_connectors['twitch'].all_messages

def sort_by_date(e):
    return e['date']

def update_all_comments():
    global all_comments
    global chat_comments
    
    # Временный список для новых комментариев
    new_comments = []
    
    # Собираем новые комментарии из всех источников
    for source in ['tg', 'yt', 'tw']:
        if source in chat_comments and chat_comments[source]:
            # Добавляем все новые комментарии из этого источника
            new_comments.extend(chat_comments[source])
            # Очищаем буфер этого источника
            chat_comments[source] = []
    
    # Добавляем новые комментарии к существующим
    all_comments.extend(new_comments)
    
    # Сортируем по дате
    all_comments.sort(key=sort_by_date)
    
    # Удаляем дубликаты по ID (если они есть)
    seen_ids = set()
    unique_comments = []
    
    for comment in all_comments:
        comment_id = (comment['id'], comment['type'])  # ID уникален в рамках типа
        if comment_id not in seen_ids:
            seen_ids.add(comment_id)
            unique_comments.append(comment)
    
    # Ограничиваем количество и сохраняем
    all_comments = unique_comments[-150:]

def make_json_object():
    global all_comments
    global chat_comments
    global overallcount
    
    # Получаем комментарии из всех включенных источников
    if 'youtube' in chat_connectors:
        get_youtube_comments()
    
    if 'twitch' in chat_connectors:
        get_twitch_comments()
    
    if 'telegram' in chat_connectors:
        try:
            asyncio.run(get_telegram_comments())
        except Exception as e:
            print(f'TG error: {e}')
            time.sleep(2)
    
    # Ограничиваем буферы для каждого источника
    for source in ['yt', 'tg', 'tw']:
        if source in chat_comments and len(chat_comments[source]) > 15:
            # Сортируем ВСЕ источники по дате (старые -> новые)
            chat_comments[source].sort(key=lambda x: x['date'])
            # Берём последние 15 (самые новые)
            chat_comments[source] = chat_comments[source][-15:]
    
    # Добавляем приветственное сообщение каждые 10 минут
    current_second = int(time.time())
    if current_second % 600 <= 5:
        # Проверяем, есть ли приветственное сообщение от Eikichi-bot в последних 20 сообщениях
        has_recent_hello = any(
            comment.get('sendr') == 'Eikichi-bot' and comment.get('type') == 'hello'
            for comment in all_comments[-20:]  # Последние 20 сообщений
        )
        
        if not has_recent_hello:
            dt = datetime.now(ZoneInfo('UTC')).astimezone(tz)
            hello_msg = {
                'id': random.randint(100000, 999999),
                'type': 'hello',
                'date': dt,
                'sendr': 'Eikichi-bot',
                'msg': '🔥 Спасибо всем на стриме за интерес к переводу и поддержку! 🔥'
            }
            all_comments.append(hello_msg)
            print(f"{datetime.now().strftime('%H:%M:%S')} Добавлено приветственное сообщение")
    
    # Обновляем общий список комментариев
    update_all_comments()
    
    overallcount += 1
    print(f"{datetime.now().strftime('%H:%M:%S')} Проверка чатов... {len(all_comments)} элементов ({overallcount})")

def print_all_comments():
    global all_comments
    global chat_comments
    print('-' * 40)
    print(all_comments)
    print('-' * 40)
    print(chat_comments)

# HTTP сервер
class ChatServer(BaseHTTPRequestHandler):
    def _set_headers(self):
        self.send_response(200)
        self.send_header('Content-type', 'application/json')
        self.send_header("Access-Control-Allow-Origin", "*")
        self.end_headers()
        
    def do_HEAD(self):
        self._set_headers()
    
    def log_message(self, format, *args):
        # Отключаем логи сервера
        return

    def do_GET(self):
        if self.path == '/':
            self._set_headers()
            self.wfile.write(json.dumps(all_comments, cls=DateTimeEncoder).encode('utf-8'))
        else:
            self.send_error(404, "Not Found")

def run_server(port=8008):
    server_address = ('', port)
    httpd = HTTPServer(server_address, ChatServer)
    print(f'Starting HTTP сервер на http://127.0.0.1:{port} ...')
    print()
    try:
        httpd.serve_forever()
    except KeyboardInterrupt:
        pass
    httpd.server_close()
    sys.exit(1)

# Основная часть программы
print()
print('--- Парсер чатов Telegram/YouTube/Twitch --- Sergey Shemet (C) 2025 ---')
print()

# Запускаем Twitch в отдельном потоке если включен
if 'twitch' in chat_connectors:
    twitch_thread = threading.Thread(target=twitch_socket.listen, name='twitchirc')
    twitch_thread.daemon = True
    twitch_thread.start()

# Запускаем HTTP сервер в отдельном потоке
server_thread = threading.Thread(target=run_server, name='HTTPServer')
server_thread.daemon = True
server_thread.start()

print('Запуск подсистем чатов...')
print('...Удерживайте Ctrl+Alt+Shift+C для выхода и C для очистки консоли...')
# print('Загрузка 7TV эмодзи...')
# emotes_cache = get_7tv_emotes() if TWITCH_CHANNEL else {}


poll_time = 2  # Интервал проверки в секундах

while True:
    # Обработка горячих клавиш
    if keyboard.is_pressed('Ctrl+Shift+Alt+c'):
        sys.exit(1)
    if keyboard.is_pressed('Ctrl+Shift+Alt+z'):
        print_all_comments()
    if keyboard.is_pressed('c'):
        os.system("cls")
    
    # Периодическая проверка чатов
    this_second = int(time.time())
    if this_second % poll_time == 0:
        make_json_object()
        time.sleep(1)