import os
import sys
import time
import json
import logging
try:
 import requests
 import pymysql
except:
    import pip
    pip.main(['install','requests'])
    pip.main(['install','pymysql'])
    import requests
    import pymysql
    
from concurrent.futures import ThreadPoolExecutor
PC = "@hsjsjsijss"
# ================= CONFIGURATION & LOGGING =================
DB_CONFIG = {
    "host": "localhost",
    "user": "xeznqcyz_swiftotp",
    "password": "xeznqcyz_swiftotp",
    "database": "xeznqcyz_swiftotp",
    "cursorclass": pymysql.cursors.DictCursor,
    "autocommit": True,
    "connect_timeout": 5,
    "read_timeout": 5,
    "write_timeout": 5,
    "charset": "utf8mb4"
}

BOT_TOKEN = "7679448689:AAE9LavWq8BadJkyY4ejXEUsXELkVSE042I"
TG_API = f"https://api.telegram.org/bot{BOT_TOKEN}"
RUNNER_FILE = "runner.json"

# Logging Setup: Console aur File dono me dikhega
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - [%(levelname)s] - %(message)s',
    handlers=[
        logging.FileHandler("answer/error_otp.py.log"),
        logging.StreamHandler(sys.stdout)
    ]
)
logger = logging.getLogger(__name__)

# ================= INITIALIZATION =================
BASE_DIR = os.path.dirname(os.path.abspath(sys.argv[0]))
os.chdir(BASE_DIR)

def save_runner_info():
    runner_data = {
        "command": f'cd "{BASE_DIR}" && "{sys.executable}" "{os.path.abspath(sys.argv[0])}"',
        "pid": os.getpid(),
        "created_at": int(time.time())
    }
    with open(RUNNER_FILE, "w", encoding="utf-8") as f:
        json.dump(runner_data, f, indent=4)


# ================= DB CONNECTION =================
def get_db():
    return pymysql.connect(**DB_CONFIG)

def cancel(order_id, api):  
    try:
        url = f"{api['api_url']}?api_key={api['api_key']}&action=setStatus&status=8&id={order_id}"
        requests.get(url, timeout=10)
    except Exception as e:
        pass
def resend(order_id, api):
    try:
        url = f"{api['api_url']}?api_key={api['api_key']}&action=setStatus&status=3&id={order_id}"
        requests.get(url, timeout=10)
    except Exception as e:
        pass
def send_otp_notification(user_id, service, order_id, price, otp):
    text = (
        "🔔 *New OTP Request*\n\n"
        f"👤 User: [Open Profile](tg://user?id={user_id})\n"
        f"🆔 Telegram ID: `{user_id}`\n"
        f"📦 Service: `{service}`\n"
        f"🛒 Service ID: `{order_id}`\n"
        f"💰 Price: ₹`{price}`\n"
        f"📨 OTP: `{otp}`"
    )

    try:
        resp = requests.post(
            f"{TG_API}/sendMessage",
            data={
                "chat_id": PC,
                "text": text,
                "parse_mode": "Markdown"
            }
        )
        return resp.json()
    except Exception as e:
        logger.error(f"📡 TG Send OTP Error: {e}")
# ================= TELEGRAM HELPER =================
def edit_message(chat_id, message_id, text, keyboard=[]):
    try:
        resp =  requests.post(
        f"{TG_API}/editMessageText",
        data={
            "chat_id": chat_id,
            "message_id": message_id,
            "text": text,
            "parse_mode": "Markdown",
            "reply_markup": json.dumps(keyboard) if keyboard else ""
        }
    )
        return resp.json()
    except Exception as e:
        logger.error(f"📡 TG Edit Error: {e}")

# ================= ORDER PROCESSING =================
def refund(user_id, amount):
    with get_db() as db:
        with db.cursor() as c:
            c.execute(
                "UPDATE user_data SET balance = balance + %s , spend = spend - %s WHERE user_id=%s",
                (amount, amount, user_id)
            )

def process_order(order):

    
    try:
        order_id = order["order_id"]
        user_id = order["user_id"]
        age = time.time() - order["created_at"].timestamp()

        # Get API Details
        with get_db() as db:
          with db.cursor() as c:
            c.execute("SELECT api_url, api_key FROM api_details WHERE id=%s", (order["api_id"],))
            api = c.fetchone()

        if not api:
            
            resp = "STATUS_CANCEL"
        else:
        # Request Status from Provider
         url = f"{api['api_url']}?api_key={api['api_key']}&action=getStatus&id={order_id}"
        
         try:
            resp = requests.get(url, timeout=10).text.strip()
         
         except Exception as e:
          
            return

        # Logic 1: CANCELLED

        if "STATUS_CANCEL" in resp:
            refund( user_id, order["price"])
            with get_db() as db:
               with db.cursor() as c:
                c.execute("UPDATE otp_history SET status='CANCELLED' WHERE order_id=%s", (order_id,))
            
            edit_message(user_id, order["message_id"], 
                               f"""🧾 *Service:* {order['service_name']}\n\n📞 *Number:* +91 `{order['number'][2:]}`\n\n *❌ Status:* Cancelled\n\n💰 *Refunded:* ₹{order['price']}""")
        # Logic 2: OTP RECEIVED (SUCCESS)
        elif "STATUS_OK" in resp:
            otp = resp.split(":")[-1].strip()
            sms_list = json.loads(order["sms"] or "[]")
            
            if otp not in sms_list:
                sms_list.append(otp)
                with get_db() as db:
                 with db.cursor() as c:
                    c.execute("UPDATE otp_history SET status='RECEIVED', sms=%s WHERE order_id=%s", 
                              (json.dumps(sms_list), order_id))
                
                edit_message(user_id, order["message_id"], 
                      f"""🧾 *Service:* {order['service_name']}\n\n📞 *Number:* +91 `{order['number'][2:]}`\n\n🔐 *OTP'S:* `{', '.join(sms_list)}`\n\n📩 *Total OTPs:* {len(sms_list)}""", {
        "inline_keyboard": [
            [
                {
                    "text": "🔁 New OTP",
                    "callback_data": f"NEW_OTP {order_id}"
                }
            ]
        ]
    }

      
    )
                send_otp_notification(user_id,order['service_name'],order_id,order['price'],otp)
                resend(order_id,api)
                
        # Logic 3: WAITING / TIMEOUT
        elif "STATUS_WAIT_CODE" in resp:
            if age > 600: # 10 Minutes Timeout
                cancel(order_id,api)
                refund(user_id, order["price"])
                with get_db() as db:
                  with db.cursor() as c:
                    c.execute("UPDATE otp_history SET status='CANCELLED' WHERE order_id=%s", (order_id,))
                
                edit_message(user_id, order["message_id"], 
                               f"""🧾 *Service:* {order['service_name']}\n\n📞 *Number:* +91 `{order['number'][2:]}`\n\n *❌ Status:* Cancelled\n\n💰 *Refunded:* ₹{order['price']}""")
              
                
                
    except Exception as e:
        logger.critical(f"💥 Critical Error in process_order: {e}", exc_info=True)
def process_order_2(order):

   
    try:
        order_id = order["order_id"]
        user_id = order["user_id"]
        age = time.time() - order["created_at"].timestamp()

        # Get API Details
        with get_db() as db:
          with db.cursor() as c:
            c.execute("SELECT api_url, api_key FROM api_details WHERE id=%s", (order["api_id"],))
            api = c.fetchone()

        if not api:
            
            resp = "STATUS_CANCEL"
        else:
        # Request Status from Provider
         url = f"{api['api_url']}?api_key={api['api_key']}&action=getStatus&id={order_id}"
        
         try:
            resp = requests.get(url, timeout=10).text.strip()
         
         except Exception as e:
          
            return
        if "STATUS_OK" in resp:
            otp = resp.split(":")[-1].strip()
            sms_list = json.loads(order["sms"] or "[]")
            
            if otp not in sms_list:
                sms_list.append(otp)
                with get_db() as db:
                 with db.cursor() as c:
                    c.execute("UPDATE otp_history SET  sms=%s WHERE order_id=%s", 
                              (json.dumps(sms_list), order_id))
                
                edit_message(user_id, order["message_id"], 
                      f"""🧾 *Service:* {order['service_name']}\n\n📞 *Number:* +91 `{order['number'][2:]}`\n\n🔐 *OTP'S:* `{', '.join(sms_list)}`\n\n📩 *Total OTPs:* {len(sms_list)}""", {
        "inline_keyboard": [
            [
                {
                    "text": "🔁 New OTP",
                    "callback_data": f"NEW_OTP {order_id}"
                }
            ]
        ]
    }

      
    )
                resend(order_id,api)
                

                
                
    except Exception as e:
        logger.critical(f"💥 Critical Error in process_order: {e}", exc_info=True)

            
# ================= MAIN LOOP =================
def main_2():
    try:
       
        with get_db() as db:
          with db.cursor() as c:
            c.execute("""
                SELECT *
                FROM otp_history
                WHERE status = 'RECEIVED'
                AND created_at >= NOW() - INTERVAL 15 MINUTE
            """)
            orders = c.fetchall()

        if orders:
            with ThreadPoolExecutor(max_workers=5) as pool:
                pool.map(process_order_2, orders)

    except Exception as e:
        logger.error(f"💀 Received Loop Error: {e}")
def main():
    save_runner_info()
 
    while True:
        try:
          with get_db() as db:
            with db.cursor() as c:
             c.execute("SELECT * FROM otp_history WHERE status='WAITING'")
             orders = c.fetchall()
            
             if orders:
              
                with ThreadPoolExecutor(max_workers=5) as pool:
                    pool.map(process_order, orders)
            
        except Exception as e:
            logger.error(f"💀 Main Loop Error: {e}")
        finally:
          main_2()
          pass
        
            
        time.sleep(5)

if __name__ == "__main__":
    try:
        main()

    except Exception as e:
        logger.error(f"🛑 Bot Crashed: {e}")

