import os
import logging
import json
import time
import threading
from zlapi.models import Message, ThreadType
from config import ADMIN

# Cấu hình logging
logging.basicConfig(
    filename='rai.log',
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

des = {
    'version': "2.11",
    'credits': "Hồ Văn Hoà",
    'description': "Rải link với text và card toàn cục, auto gửi tuần tự qua thread_id, lưu data vào JSON, bỏ ttl cho tin nhắn auto và thủ công trong send_rai_message",
    'power': "admin"
}

# Đường dẫn file JSON
THREADS_FILE = 'modules/cache/rai_threads.json'
SETUP_FILE = 'modules/cache/rai_setup.json'
ALLOWED_FILE = 'modules/cache/rai_allowed.json'
DISBOX_FILE = 'modules/cache/rai_disbox.json'

# Trạng thái và luồng tự động
rai_states = {}
auto_thread = None
last_sent = {}  

def thread_type_to_string(thread_type):
    if thread_type == ThreadType.GROUP:
        return "GROUP"
    elif thread_type == ThreadType.USER:
        return "USER"
    return None

def string_to_thread_type(thread_type_str):
    if thread_type_str == "GROUP":
        return ThreadType.GROUP
    elif thread_type_str == "USER":
        return ThreadType.USER
    return None

def load_threads():
    if not os.path.exists(THREADS_FILE):
        with open(THREADS_FILE, 'w') as f:
            json.dump([], f)
        return []
    try:
        with open(THREADS_FILE, 'r') as f:
            threads = json.load(f)
            if isinstance(threads, list) and all(isinstance(t, str) for t in threads):
                logger.warning("Old rai_threads.json format detected, converting to new format")
                new_threads = [
                    {'thread_id': t, 'thread_type': ThreadType.GROUP if t.startswith('g') else ThreadType.USER}
                    for t in threads
                ]
                save_threads(new_threads)
                return new_threads
            if not all(isinstance(t, dict) and 'thread_id' in t and 'thread_type' in t for t in threads):
                logger.error("Invalid rai_threads.json format, resetting to empty list")
                return []
            for thread in threads:
                thread['thread_type'] = string_to_thread_type(thread['thread_type'])
                if thread['thread_type'] is None:
                    logger.error(f"Invalid thread_type in thread {thread['thread_id']}, resetting to empty list")
                    return []
            return threads
    except json.JSONDecodeError:
        logger.error("Invalid rai_threads.json, resetting to empty list")
        return []

def save_threads(threads):
    threads_to_save = [
        {'thread_id': t['thread_id'], 'thread_type': thread_type_to_string(t['thread_type'])}
        for t in threads
    ]
    with open(THREADS_FILE, 'w') as f:
        json.dump(threads_to_save, f)

def load_setup():
    if not os.path.exists(SETUP_FILE):
        default_setup = {'content': 'Mặc định nội dung rải', 'card': {}}
        with open(SETUP_FILE, 'w') as f:
            json.dump(default_setup, f)
        return default_setup
    try:
        with open(SETUP_FILE, 'r') as f:
            data = json.load(f)
            if not isinstance(data, dict) or 'content' not in data or 'card' not in data:
                logger.warning("Invalid setup file, resetting to default")
                default_setup = {'content': 'Mặc định nội dung rải', 'card': {}}
                save_setup(default_setup)
                return default_setup
            return data
    except json.JSONDecodeError as e:
        logger.error(f"Failed to load setup file: {str(e)}")
        default_setup = {'content': 'Mặc định nội dung rải', 'card': {}}
        save_setup(default_setup)
        return default_setup

def save_setup(setup):
    with open(SETUP_FILE, 'w') as f:
        json.dump(setup, f)

def load_allowed():
    if not os.path.exists(ALLOWED_FILE):
        with open(ALLOWED_FILE, 'w') as f:
            json.dump({}, f)
    try:
        with open(ALLOWED_FILE, 'r') as f:
            return json.load(f)
    except json.JSONDecodeError:
        logger.error("Invalid rai_allowed.json, resetting to empty dict")
        return {}

def save_allowed(allowed):
    with open(ALLOWED_FILE, 'w') as f:
        json.dump(allowed, f)

def load_disbox():
    if not os.path.exists(DISBOX_FILE):
        with open(DISBOX_FILE, 'w') as f:
            json.dump([], f)
    try:
        with open(DISBOX_FILE, 'r') as f:
            return json.load(f)
    except json.JSONDecodeError:
        logger.error("Invalid rai_disbox.json, resetting to empty list")
        return []

def save_disbox(disbox):
    with open(DISBOX_FILE, 'w') as f:
        json.dump(disbox, f)

def has_permission(author_id, thread_id):
    allowed = load_allowed()
    return (author_id in ADMIN or 
            (thread_id in allowed and str(author_id) in allowed[thread_id]))

def is_valid_thread(client, thread_id, thread_type):
    try:
        msg = client.sendMessage(
            Message(text="Kiểm tra thread"),
            thread_id=thread_id,
            thread_type=thread_type,
            ttl=600000
        )
        logger.info(f"Thread {thread_id} (type: {thread_type}) is valid, message_id: {msg.message_id if msg else 'None'}")
        return True
    except Exception as e:
        logger.error(f"Thread {thread_id} (type: {thread_type}) is invalid: {str(e)}")
        return False

def send_rai_message(client, thread_id, thread_type, content, card_data=None):
    try:
        logger.info(f"Preparing to send to {thread_id} (type: {thread_type}) - Content: {content}, Card: {card_data}")
        if not is_valid_thread(client, thread_id, thread_type):
            logger.error(f"Skipping send to {thread_id}: Invalid thread")
            return False

        msg = client.sendMessage(
            Message(text=content),
            thread_id=thread_id,
            thread_type=thread_type
        )
        logger.info(f"Sent text to {thread_id} (type: {thread_type}), ID: {msg.message_id if msg else 'None'}")
        if not msg or not msg.message_id:
            logger.warning(f"Text message sent to {thread_id} but no message_id returned")

        if card_data and isinstance(card_data, dict) and card_data.get('uid') and card_data.get('content'):
            try:
                user_info = client.fetchUserInfo(card_data['uid']).changed_profiles.get(card_data['uid'])
                avatar_url = user_info.avatar if user_info and hasattr(user_info, 'avatar') else None
                logger.info(f"Fetched user info for UID {card_data['uid']}: Avatar {avatar_url}")
                card_msg = client.sendBusinessCard(
                    userId=card_data['uid'],
                    qrCodeUrl=avatar_url or "",
                    phone=card_data['content'],
                    thread_id=thread_id,
                    thread_type=thread_type
                )
                logger.info(f"Sent card to {thread_id} (type: {thread_type}), ID: {card_msg.message_id if card_msg else 'None'}")
                if not card_msg or not card_msg.message_id:
                    logger.warning(f"Card sent to {thread_id} but no message_id returned")
            except Exception as e:
                logger.error(f"Failed to send card to {thread_id} (type: {thread_type}): {str(e)}")
                client.sendMessage(
                    Message(text=f"❌ Lỗi khi gửi card: {str(e)}"),
                    thread_id=thread_id,
                    thread_type=thread_type
                )
        else:
            logger.warning(f"Invalid or missing card data for {thread_id} (type: {thread_type}): {card_data}")
        last_sent[thread_id] = time.time()
        return True
    except Exception as e:
        logger.error(f"Send error for {thread_id} (type: {thread_type}): {str(e)}")
        client.sendMessage(
            Message(text=f"❌ Lỗi khi gửi tin nhắn: {str(e)}"),
            thread_id=thread_id,
            thread_type=thread_type
        )
        return False

def auto_rai(client):
    global auto_thread
    while True:
        try:
            logger.info("Auto rai thread started")
            threads = load_threads()
            disbox = load_disbox()
            setup_data = load_setup()
            active_threads = [
                t for t in threads 
                if t['thread_id'] not in disbox and t['thread_type'] in [ThreadType.GROUP, ThreadType.USER]
            ]
            logger.info(f"Active threads: {[t['thread_id'] for t in active_threads]}, rai_states: {rai_states}")

            if not active_threads:
                logger.info("No active threads, waiting 300s")
                time.sleep(300)
                continue

            if os.path.exists('modules/cache/maintenance.txt'):
                logger.info("Maintenance mode active, waiting 300s")
                time.sleep(300)
                continue

            for thread in active_threads:
                thread_id = thread['thread_id']
                thread_type = thread['thread_type']
                if thread_id not in rai_states:
                    rai_states[thread_id] = True
                    logger.info(f"Initialized rai_states for thread {thread_id} (type: {thread_type})")
                if rai_states[thread_id]:
                    if thread_id not in last_sent or (time.time() - last_sent.get(thread_id, 0)) >= 300:
                        logger.info(f"Sending to thread {thread_id} (type: {thread_type}) with content: {setup_data['content']}")
                        if send_rai_message(client, thread_id, thread_type, setup_data['content'], setup_data.get('card', {})):
                            logger.info(f"Successfully sent to {thread_id} (type: {thread_type})")
                        else:
                            logger.error(f"Failed to send to {thread_id} (type: {thread_type}), removing from threads")
                            threads.remove(thread)
                            save_threads(threads)
                    else:
                        logger.info(f"Skipping {thread_id} (type: {thread_type}), recently sent")
                    time.sleep(2)

            logger.info("Cycle done, resting 300s")
            time.sleep(300)
        except Exception as e:
            logger.error(f"Auto rai error: {str(e)}")
            time.sleep(60)

def handle_rai_command(message, message_object, thread_id, thread_type, author_id, client):
    global auto_thread, rai_states
    logger.info(f"Command: {message}, Thread: {thread_id}, Type: {thread_type}, Author: {author_id}")

    prefix = getattr(client, 'prefix', '.')  
    if not message.strip().startswith(prefix + "rai"):
        return

    if auto_thread is None or not auto_thread.is_alive():
        auto_thread = threading.Thread(target=auto_rai, args=(client,), daemon=True)
        auto_thread.start()
        logger.info("Started auto_thread")

    parts = message.strip()[len(prefix + "rai"):].strip().split()
    logger.info(f"Parts: {parts}")

    ttl = 600000
    threads = load_threads()
    disbox = load_disbox()
    setup_data = load_setup()
    allowed = load_allowed()

    if not has_permission(author_id, thread_id):
        client.replyMessage(
            Message(text="❌ Không có quyền! Liên hệ admin."),
            message_object,
            thread_id,
            thread_type,
            ttl=ttl
        )
        return

    if len(parts) >= 1 and parts[0].lower() in ['on', 'off', 'all', 'disbox', 'undisbox', 'set', 'card']:
        if author_id not in ADMIN:
            client.replyMessage(
                Message(text="❌ Chỉ admin!"),
                message_object,
                thread_id,
                thread_type,
                ttl=ttl
            )
            return

        if parts[0].lower() == 'on':
            if any(t['thread_id'] == thread_id and t['thread_type'] == thread_type for t in threads) and thread_id not in disbox:
                client.replyMessage(
                    Message(text=f"⚠️ `{prefix}rai on` đã bật!"),
                    message_object,
                    thread_id,
                    thread_type,
                    ttl=ttl
                )
                return
            rai_states[thread_id] = True
            if not any(t['thread_id'] == thread_id for t in threads):
                threads.append({'thread_id': thread_id, 'thread_type': thread_type})
                save_threads(threads)
                logger.info(f"Added thread {thread_id} (type: {thread_type}) to rai_threads.json")
            if thread_id in disbox:
                disbox.remove(thread_id)
                save_disbox(disbox)
                logger.info(f"Removed thread {thread_id} from disbox")
            if send_rai_message(client, thread_id, thread_type, setup_data['content'], setup_data.get('card', {})):
                client.replyMessage(
                    Message(text=f"✅ `{prefix}rai on` đã bật và gửi tin nhắn!"),
                    message_object,
                    thread_id,
                    thread_type,
                    ttl=ttl
                )
            else:
                client.replyMessage(
                    Message(text=f"❌ `{prefix}rai on` đã bật nhưng gửi tin nhắn thất bại!"),
                    message_object,
                    thread_id,
                    thread_type,
                    ttl=ttl
                )
        elif parts[0].lower() == 'off':
            if not any(t['thread_id'] == thread_id for t in threads):
                client.replyMessage(
                    Message(text=f"⚠️ `{prefix}rai` chưa bật!"),
                    message_object,
                    thread_id,
                    thread_type,
                    ttl=ttl
                )
                return
            rai_states[thread_id] = False
            threads[:] = [t for t in threads if t['thread_id'] != thread_id]
            save_threads(threads)
            logger.info(f"Removed thread {thread_id} from rai_threads.json")
            client.replyMessage(
                Message(text=f"⛔ `{prefix}rai off` đã tắt!"),
                message_object,
                thread_id,
                thread_type,
                ttl=ttl
            )
        elif parts[0].lower() == 'all':
            threads = load_threads()
            disbox = load_disbox()
            active_threads = [t for t in threads if t['thread_id'] not in disbox]
            if not active_threads:
                client.replyMessage(
                    Message(text=f"⚠️ Không có nhóm!"),
                    message_object,
                    thread_id,
                    thread_type,
                    ttl=ttl
                )
                return
            for thread in active_threads:
                thread_id = thread['thread_id']
                thread_type = thread['thread_type']
                rai_states[thread_id] = True
                send_rai_message(client, thread_id, thread_type, setup_data['content'], setup_data.get('card', {}))
            client.replyMessage(
                Message(text=f"✅ `{prefix}rai all` đã bật và gửi tin nhắn!"),
                message_object,
                thread_id,
                thread_type,
                ttl=ttl
            )
        elif parts[0].lower() == 'disbox':
            if thread_id in disbox:
                client.replyMessage(
                    Message(text=f"⚠️ `{prefix}rai disbox` đã tắt!"),
                    message_object,
                    thread_id,
                    thread_type,
                    ttl=ttl
                )
                return
            disbox.append(thread_id)
            save_disbox(disbox)
            client.replyMessage(
                Message(text=f"⛔ `{prefix}rai disbox` đã tắt rải!"),
                message_object,
                thread_id,
                thread_type,
                ttl=ttl
            )
        elif parts[0].lower() == 'undisbox':
            if thread_id not in disbox:
                client.replyMessage(
                    Message(text=f"⚠️ `{prefix}rai undisbox` không cần!"),
                    message_object,
                    thread_id,
                    thread_type,
                    ttl=ttl
                )
                return
            disbox.remove(thread_id)
            save_disbox(disbox)
            client.replyMessage(
                Message(text=f"✅ `{prefix}rai undisbox` đã xóa!"),
                message_object,
                thread_id,
                thread_type,
                ttl=ttl
            )
        elif parts[0].lower() == 'set':
            if len(parts) < 2:
                client.replyMessage(
                    Message(text=f"❌ `{prefix}rai set [nội dung]`!"),
                    message_object,
                    thread_id,
                    thread_type,
                    ttl=ttl
                )
                return
            content = ' '.join(parts[1:])
            setup_data['content'] = content
            save_setup(setup_data)
            logger.info(f"Content updated: {content}")
            client.replyMessage(
                Message(text=f"✅ Nội dung: {content}"),
                message_object,
                thread_id,
                thread_type,
                ttl=ttl
            )
        elif parts[0].lower() == 'card':
            if len(parts) < 2 or parts[1].lower() != 'set':
                client.replyMessage(
                    Message(text=f"❌ Sử dụng: `{prefix}rai card set [uid] [nội dung]`!"),
                    message_object,
                    thread_id,
                    thread_type,
                    ttl=ttl
                )
                return
            if len(parts) < 3:
                client.replyMessage(
                    Message(text=f"❌ Cần [uid] và [nội dung]!"),
                    message_object,
                    thread_id,
                    thread_type,
                    ttl=ttl
                )
                return
            uid = parts[2]
            content = ' '.join(parts[3:]) if len(parts) > 3 else ''
            if uid and content:
                setup_data['card'] = {'uid': uid, 'content': content}
                save_setup(setup_data)
                logger.info(f"Card updated - UID: {uid}, Content: {content}")
                client.replyMessage(
                    Message(text=f"✅ Card - UID: {uid}, Content: {content}"),
                    message_object,
                    thread_id,
                    thread_type,
                    ttl=ttl
                )
            else:
                client.replyMessage(
                    Message(text=f"❌ `{prefix}rai card set [uid] [nội dung]`!"),
                    message_object,
                    thread_id,
                    thread_type,
                    ttl=ttl
                )
        return

    if os.path.exists('modules/cache/maintenance.txt'):
        client.replyMessage(
            Message(text="⚠️ Đang bảo trì!"),
            message_object,
            thread_id,
            thread_type,
            ttl=ttl
        )
        return

    if not any(t['thread_id'] == thread_id for t in threads) or not rai_states.get(thread_id, False):
        rai_states[thread_id] = True
        if not any(t['thread_id'] == thread_id for t in threads):
            threads.append({'thread_id': thread_id, 'thread_type': thread_type})
            save_threads(threads)
            logger.info(f"Added thread {thread_id} (type: {thread_type}) to rai_threads.json")
        if send_rai_message(client, thread_id, thread_type, setup_data['content'], setup_data.get('card', {})):
            client.replyMessage(
                Message(text=f"✅ Đã gửi tin nhắn thủ công và bật auto!"),
                message_object,
                thread_id,
                thread_type,
                ttl=ttl
            )
        else:
            client.replyMessage(
                Message(text=f"❌ Đã bật auto nhưng gửi tin nhắn thất bại!"),
                message_object,
                thread_id,
                thread_type,
                ttl=ttl
            )
        return

    if send_rai_message(client, thread_id, thread_type, setup_data['content'], setup_data.get('card', {})):
        client.replyMessage(
            Message(text="✅ Đã gửi tin nhắn thủ công!"),
            message_object,
            thread_id,
            thread_type,
            ttl=ttl
        )
    else:
        client.replyMessage(
            Message(text="❌ Gửi tin nhắn thủ công thất bại!"),
            message_object,
            thread_id,
            thread_type,
            ttl=ttl
        )

def handle_card_setup(message, message_object, thread_id, thread_type, author_id, client):
    pass

def ft_vxkiue():
    return {
        'rai': handle_rai_command,
    }