import json
# from fastapi import FastAPI, Request
from pydantic import BaseModel
import requests
import logging
# import uvicorn
import time
import nahj_engine as nahj_chat
import data_model as dm
# ===========================
# پیکربندی اولیه
# ===========================
TOKEN = "602738113:OcVhjcsXqvE6D9FUytdoMZ096DPKYIUwnrk"
API_URL = f"https://tapi.bale.ai/bot{TOKEN}/"

# راه‌اندازی لاگر
logging.basicConfig(
    filename="./bale_bot/bot.log",
    level=logging.INFO,
    format="%(asctime)s - %(levelname)s - %(message)s"
)

# ===========================
# define import model class
# ===========================
class Message(BaseModel):
    chat: dict
    text: str | None = None

class Update(BaseModel):
    message: Message | None = None

# ===========================
# کلاس اصلی ربات بله
# ===========================
class BaleBot:
    def __init__(self, token: str):
        # self.api_url = f"https://api.bale.ai/bot{token}/"
        self.api_url = API_URL
        self.user_states = {}

    async def get_updates(self, offset = None):
        params = {"timeout": 20}
        if offset:
            params["offset"] = offset
        # print("get_updates function")
        resp = requests.get(f"{self.api_url}getUpdates", params=params)
        return resp.json().get("result", [])

    async def send_message(self, chat_id: int, text: str, keyboard=None):
        payload = {
            "chat_id": chat_id,
            "text": text,
            "parse_mode": "HTML"
        }
        if keyboard:
            payload["reply_markup"] = keyboard
        try:
            response = requests.post(self.api_url + "sendMessage", json=payload)
            return response.json()
        except Exception as e:
            logging.error(f"Error sending message: {e}")
            return None

    async def get_latest_req_id(self):

        latest_request = dm.get_last_request()
        latest_req_id = latest_request['update_id']
        if not latest_req_id:
            latest_req_id = 0

        return latest_req_id + 1

    async def save_entery(self, update_item):
        is_active = True
        answer = ''
        message = update_item['message']
        fromm = message['from']
        chat = message['chat']
        username, first_name, last_name = '','',''
        if 'username' in fromm:
            username = fromm['username']  
        if 'first_name' in fromm:
            first_name = fromm['first_name']  
        if 'last_name' in fromm:
            last_name = fromm['last_name']      
        try:
            dm.insert_request(update_item['update_id'],username,message['text'], answer, message['message_id'],fromm['id'],fromm['is_bot'],message['date'],chat['id'],chat['type'],first_name,last_name, is_active)
        except:
            return update_item['update_id']
        
        return update_item['update_id']
    
    async def update_request(self, update_id, answer):
        dm.update_request(update_id= update_id, answer= answer)
        
    
    async def split_text_into_chunks(self, text, max_length=4000):
        """
        تقسیم یک متن به چانک‌های حداکثر max_length کاراکتری، بدون خراب کردن معنا با رعایت انتهای جمله‌ها.
        
        :param text: متن ورودی
        :param max_length: حداکثر طول هر چانک (پیش‌فرض 4000)
        :return: لیستی از چانک‌های متن
        """
        chunks = []  # لیستی برای ذخیره چانک‌ها
        start = 0    # شروع متن برای هر چانک
        
        while start < len(text):
            # اگر متن باقی‌مانده کوتاه‌تر از max_length باشد، کل آن را اضافه کنید
            if len(text) - start <= max_length:
                chunks.append(text[start:])
                break
            
            # پیدا کردن نقطه پایانی چانک (حداکثر تا max_length کاراکتر جلو بروید)
            end = start + max_length
            # اگر در وسط یک جمله هستیم، به عقب برگردید تا انتهای جمله پیدا شود
            while end > start and text[end - 1] not in '.!?':
                end -= 1
            
            # اگر هیچ انتهای جمله پیدا نشد، متن را تا max_length ببرید
            if end == start:
                end = start + max_length
            
            # اضافه کردن چانک به لیست
            chunks.append(text[start:end])
            # شروع چانک بعدی
            start = end
    
        return chunks
    
    async def save_chat_data(self,query, answer, first_name, username):
        chat_data = f'''username: {username}\nfirstname: {first_name}\nquery: {query}\nanswer:{answer}\n+ + + + + + + + + + + + + + + + + + + + \n+ + + + + + + + + + + + + + + + + + + + \n\n'''
        # # should write in DATABASE
        with open('./bale_bot/chat-data.txt', 'a+', encoding='utf-8') as file:
            file.write(chat_data)
        
    async def handle_update(self, update_reqs: dict):
        print(f"handle update ...")
        data = update_reqs
        if "message" not in data:
            return
        message = data["message"]
        chat_id = message["chat"]["id"]
        text = message.get("text", "").strip()
        
        fromm = message['from']
        # first_name = fromm['first_name']
        # username = fromm['username']
        
        logging.info(f"Received message from {chat_id}: {text}")
        
        keyboard = {
                "keyboard": [["جستجو","پرسش","پرسش عمیق"]],# ,"شبکه معنایی"
                "resize_keyboard": True,
                "one_time_keyboard": True
            }
        
        if text == "/start":
            reply = "سلام، من دستیار هوشمند نهج‌البلاغه هستم. لطفا یکی از گزینه‌های زیر را انتخاب نمائید ..."
            
            await self.send_message(chat_id, reply, keyboard)
            return

        elif text == "پرسش":
            # حذف نوع درخواست قبلی کاربر
            self.user_states.pop(chat_id, None)
            # ایجاد وضعیت پرسش برای کاربر جاری
            self.user_states[chat_id] = "simple_question"
            reply = "لطفا متن «پرسش» را وارد نمائید ..."
            await self.send_message(chat_id, reply, keyboard)
            return
        
        elif text == "جستجو":
            # حذف نوع درخواست قبلی کاربر
            self.user_states.pop(chat_id, None)
            # ایجاد وضعیت جستجو برای کاربر جاری
            self.user_states[chat_id] = "search"
            reply = "لطفا متن موردنظر جهت «جستجو» را وارد نمائید ..."
            await self.send_message(chat_id, reply, keyboard)
            return
            
        elif text == "شبکه معنایی":
            # حذف نوع درخواست قبلی کاربر
            self.user_states.pop(chat_id, None)
            # ایجاد وضعیت شبکه معنایی برای کاربر جاری
            self.user_states[chat_id] = "semantic-network"
            reply = "لطفا کلمه موردنظر جهت ترسیم «شبکه معنایی» را وارد نمائید ..."
            await self.send_message(chat_id, reply, keyboard)
            return
            
        elif text == "پرسش عمیق":
            # حذف نوع درخواست قبلی کاربر
            self.user_states.pop(chat_id, None)
            # ایجاد وضعیت پرسش برای کاربر جاری
            self.user_states[chat_id] = "deep_question"
            reply = "لطفا متن «پرسش عمیق» را وارد نمائید ..."
            await self.send_message(chat_id, reply, keyboard)
            return

        # elif text == "/help":
        #     reply = (
        #         "دستورهای موجود:\n"
        #         "/start - شروع ربات\n"
        #         "/chat - گفت‌گو با دستیار هوشمند نهج البلاغه\n"
        #         "/status - وضعیت ربات"
        #     )
        #     self.send_message(chat_id, reply)

        elif text == "ربات":
            reply = "ربات فعال است ✅"
            await self.send_message(chat_id, reply, keyboard)
            return

        elif self.user_states.get(chat_id) == "semantic-network":
            await self.send_message(chat_id, f"⏳ در حال ایجاد شبکه معنایی برای کلمه «{text}» ...")
            reply = 'با عرض پوزش؛ این امکان، در حال حاضر در دسترس نیست'
            
        elif self.user_states.get(chat_id) == "search":
            await self.send_message(chat_id, f"⏳ در حال جستجو برای «{text}» ...")
            
            answer = nahj_chat.bale_search(text)
            
            if answer:
                reply = answer
            else:
                reply = 'خطا در تولید پاسخ!'
            
        elif self.user_states.get(chat_id) == "simple_question":
            
            await self.send_message(chat_id, f"⏳ در حال آماده‌سازی پاسخ به «{text}» ...")
            
            answer = nahj_chat.bale_chat(text)
            
            if answer:
                reply = answer
            else:
                reply = 'خطا در تولید پاسخ!'
            
        elif self.user_states.get(chat_id) == "deep_question":
            
            await self.send_message(chat_id, f"⏳ در حال آماده‌سازی پاسخ به «{text}» ...")
            
            # answer = nahj_chat.bale_chat(text)
            final_result = await nahj_chat.bale_complex_chat(text)
            
            if final_result:
                
                sub_questions = 'سوالات جزئی مرتبط با سوال کاربر:\n'
                for i, q in enumerate(final_result.get('sub_qa'),1):
                    sub_questions += f'{i}. {q.get("question")}\n'
                    
                sub_qa_text = ''
                for i, qa in enumerate(final_result.get('sub_qa'),1):
                    sub_qa_text += f'{i}. {qa.get("question")}\n{qa.get("answer")}\n\n'
                # reply_content = f'''سوال اصلی: {text}\n\n{sub_questions}\n\n* * * * *سوالات جزئی:\n{sub_qa_text.strip()}\n\nپاسخ نهائی:\n{final_result.get('final_answer',0)}'''
                reply_content = f'''{final_result.get('final_answer',0)}'''
                reply = reply_content.strip()
            
            else:
                reply = 'خطا در تولید پاسخ!'
                
        else:
            reply = "لطفا یکی از گزینه‌های زیر را انتخاب نمائید"
            await self.send_message(chat_id, reply, keyboard)
            return

        reply_len = len(reply.split())
        print(f"len answer: {reply_len}")
        print(f"ready for next ...")
        print('+'*20)
        print('+'*20)
        reply_chuncs = []

        reply_chuncs = await self.split_text_into_chunks(reply)

        for i, paragraph in enumerate(reply_chuncs):
            await self.send_message(chat_id, paragraph, keyboard)

        # await self.save_chat_data(text, reply, first_name, username)
        return reply
        
        
async def main():
    print(f'!!! BALE-NAHJ-BOT IS READY !!!')
    while True:
        last_req_id = await bale_bot.get_latest_req_id()
        # print(f"last req id: {last_req_id}")
        update = await bale_bot.get_updates(last_req_id)
        # print(f"reading bale-bot server. len update: {len(update)}")
        if update:
            print(f'{len(update)} requests recognized!')
            for i, item in enumerate(update, 1):
                    print(f'handle input {i}/{len(update)}')
                    update_id = await bale_bot.save_entery(item)
                    answer = await bale_bot.handle_update(item)
                    if answer:
                        await bale_bot.update_request(update_id, answer)
        time.sleep(1)

# ===========================
# ساخت اپلیکیشن FastAPI
# ===========================
# app = FastAPI()
bale_bot = BaleBot(TOKEN)

# ===========================
# (local execution)
# ===========================

if __name__ == "__main__":
    import asyncio
    result = asyncio.run(main())
