"""
Handwritten training program OCR handler.
Uses OpenRouter API (Gemini Flash) — FREE tier available.
"""
from telegram import Update, InlineKeyboardMarkup, InlineKeyboardButton
from telegram.ext import (
    ContextTypes, ConversationHandler,
    MessageHandler, CallbackQueryHandler, filters,
)
import base64, json, re, httpx
import database.db as db
from config.settings import HANDWRITTEN_PHOTO, HANDWRITTEN_CONFIRM
from utils.helpers import go_main_menu, track_message, delete_bot_messages, persian_num
from utils.keyboards import BACK_KB, MAIN_COACH_KB

# ── کلید OpenRouter رو اینجا وارد کن ─────────────────────────────────────────
OPENROUTER_KEY = "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"
# ─────────────────────────────────────────────────────────────────────────────

OPENROUTER_URL = "https://openrouter.ai/api/v1/chat/completions"
MODEL = "qwen/qwen2.5-vl-72b-instruct:free"
MODEL_FALLBACK = "google/gemma-4-31b-it:free"

_PROMPT = """You are a fitness assistant reading handwritten Persian workout tables.
Extract all exercises from the image.
Return ONLY this JSON format, no other text:
{"exercises": [{"name": "exercise name in Persian", "sets": 3, "reps": "12"}, ...]}
Important:
- Keep exercise names in Persian as written
- Use Arabic/Latin numbers for sets and reps (not Persian digits)
- Return pure JSON only"""


async def _ocr_image(photo_bytes: bytes) -> list:
    """Send image to OpenRouter and extract exercises."""
    if "اینجا" in OPENROUTER_KEY or len(OPENROUTER_KEY) < 20:
        raise ValueError("کلید OpenRouter تنظیم نشده! فایل handwritten.py را ویرایش کنید.")
    b64 = base64.standard_b64encode(photo_bytes).decode("ascii")

    # Build payload
    payload = {
        "model": MODEL,
        "messages": [{
            "role": "user",
            "content": [
                {
                    "type": "image_url",
                    "image_url": {
                        "url": f"data:image/jpeg;base64,{b64}",
                        "detail": "high"
                    }
                },
                {
                    "type": "text",
                    "text": _PROMPT
                }
            ]
        }],
        "max_tokens": 1000,
        "temperature": 0.1,
    }

    headers = {
        "Authorization": f"Bearer {OPENROUTER_KEY}",
        "Content-Type": "application/json; charset=utf-8",
        "HTTP-Referer": "https://t.me/milad_gym_bot",
        "X-Title": "Milad Gym Bot",
    }

    # Serialize with ensure_ascii=False to handle Persian
    payload_str = json.dumps(payload, ensure_ascii=False).encode("utf-8")

    import asyncio
    async with httpx.AsyncClient(timeout=45) as client:
        # Try up to 3 times with backoff for rate limits
        for attempt in range(3):
            resp = await client.post(
                OPENROUTER_URL,
                content=payload_str,
                headers=headers
            )
            if resp.status_code == 429:
                if attempt < 2:
                    await asyncio.sleep(10 * (attempt + 1))
                    continue
                raise httpx.HTTPStatusError(
                    "429 - Rate limit. چند ثانیه صبر کن و دوباره امتحان کن.",
                    request=resp.request, response=resp)
            if resp.status_code == 404:
                body = resp.content.decode("utf-8", errors="replace")[:200]
                raise httpx.HTTPStatusError(
                    f"404 - مدل پیدا نشد: {body}",
                    request=resp.request, response=resp)
            if resp.status_code == 400:
                body = resp.content.decode("utf-8", errors="replace")[:300]
                raise httpx.HTTPStatusError(
                    f"400 - خطای درخواست: {body}",
                    request=resp.request, response=resp)
            resp.raise_for_status()
            break
        # Decode response as UTF-8
        data = json.loads(resp.content.decode("utf-8"))

    # Safely get text from response
    try:
        text = data["choices"][0]["message"]["content"]
    except (KeyError, IndexError, TypeError):
        text = ""
    
    if not text:
        return []

    # Extract JSON - handle Persian digits in response
    fa_to_la = str.maketrans("۰۱۲۳۴۵۶۷۸۹", "0123456789")
    text_clean = text.replace("\n", " ").replace("\\", "").translate(fa_to_la)
    
    # Try to find exercises JSON
    match = re.search(r"\{[^{}]*exercises[^{}]*\}", text_clean, re.DOTALL)
    if not match:
        match = re.search(r"\{.*?\}", text_clean, re.DOTALL)
    if match:
        try:
            parsed = json.loads(match.group())
            exs = parsed.get("exercises", [])
            if exs:
                return exs
        except Exception:
            pass
    
    # If no JSON found, try to parse plain text response
    # Model might return: "جلو بازو دمبل - 8 ست - 12 تایی"
    lines = [l.strip() for l in text.split("\n") if l.strip()]
    exercises = []
    for line in lines:
        line = line.translate(fa_to_la)
        # Look for pattern: name + sets + reps
        nums = re.findall(r"\d+", line)
        if nums and len(line) > 3:
            name = re.sub(r"[\d\-\|×x,،]+", "", line).strip()
            if name:
                sets = int(nums[0]) if nums else 3
                reps = nums[1] if len(nums) > 1 else "12"
                exercises.append({"name": name, "sets": sets, "reps": reps})
    
    return exercises


async def handwritten_start(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query; await query.answer()
    chat_id = query.message.chat_id
    await delete_bot_messages(context, chat_id)
    sent = await query.message.reply_text(
        "✍️ *ثبت برنامه دست‌نویس*\n\n"
        "📸 عکس جدول تمرینی دست‌نویس را ارسال کن.\n\n"
        "🤖 هوش مصنوعی به صورت خودکار حرکات، ست و تکرار را تشخیص می‌دهد!",
        reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton("🔙 بازگشت", callback_data="main_menu")]]), parse_mode="Markdown")
    track_message(context, chat_id, sent.message_id)
    return HANDWRITTEN_PHOTO


async def handwritten_got_photo(update: Update, context: ContextTypes.DEFAULT_TYPE):
    chat_id = update.effective_chat.id

    if not update.message.photo:
        sent = await update.message.reply_text("❗️ لطفاً عکس ارسال کن.")
        track_message(context, chat_id, sent.message_id)
        return HANDWRITTEN_PHOTO

    await delete_bot_messages(context, chat_id)
    loading = await update.message.reply_text(
        "⏳ در حال تحلیل تصویر با هوش مصنوعی...\nلطفاً چند ثانیه صبر کن 🤖")
    track_message(context, chat_id, loading.message_id)

    try:
        # دانلود عکس
        photo = update.message.photo[-1]
        file  = await context.bot.get_file(photo.file_id)
        photo_bytes = await file.download_as_bytearray()

        # OCR با Gemini
        exercises = await _ocr_image(bytes(photo_bytes))

        try:
            await context.bot.delete_message(chat_id=chat_id, message_id=loading.message_id)
        except Exception:
            pass

        if not exercises:
            sent = await update.message.reply_text(
                "❌ نتوانستم جدول را تشخیص دهم.\n"
                "لطفاً عکس واضح‌تری ارسال کن 📸",
                reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton("🔙 بازگشت", callback_data="main_menu")]]))
            track_message(context, chat_id, sent.message_id)
            return HANDWRITTEN_PHOTO

        # ذخیره موقت
        context.user_data["handwritten_exercises"] = exercises

        # نمایش نتیجه
        fa = str.maketrans('0123456789', '۰۱۲۳۴۵۶۷۸۹')
        lines = ["✅ *حرکات تشخیص داده شده:*\n"]
        for i, ex in enumerate(exercises, 1):
            lines.append(
                f"*{str(i).translate(fa)}.* {ex['name']}\n"
                f"   📊 ست: `{str(ex['sets']).translate(fa)}` | تکرار: `{str(ex['reps']).translate(fa)}`\n"
            )
        lines.append("\n⬇️ *آیا این اطلاعات صحیح است؟*")

        kb = InlineKeyboardMarkup([
            [InlineKeyboardButton("✅ تأیید و ذخیره", callback_data="hw_confirm"),
             InlineKeyboardButton("🔄 دوباره امتحان", callback_data="hw_retry")],
            [InlineKeyboardButton("❌ لغو", callback_data="main_menu")],
        ])
        sent = await update.message.reply_text(
            "\n".join(lines), reply_markup=kb, parse_mode="Markdown")
        track_message(context, chat_id, sent.message_id)
        return HANDWRITTEN_CONFIRM

    except httpx.HTTPStatusError as e:
        try:
            await context.bot.delete_message(chat_id=chat_id, message_id=loading.message_id)
        except Exception:
            pass
        if "401" in str(e):
            msg = ("❌ کلید OpenRouter نامعتبر است!\n\n"
                   "در فایل `handlers/handwritten.py`\n"
                   "مقدار `OPENROUTER_KEY` را درست وارد کنید.")
        else:
            msg = f"❌ خطا در اتصال به سرویس:\n`{str(e)[:150]}`"
        sent = await update.message.reply_text(msg, reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton("🔙 بازگشت", callback_data="main_menu")]]), parse_mode="Markdown")
        track_message(context, chat_id, sent.message_id)
        return HANDWRITTEN_PHOTO

    except Exception as e:
        try:
            await context.bot.delete_message(chat_id=chat_id, message_id=loading.message_id)
        except Exception:
            pass
        sent = await update.message.reply_text(
            f"❌ خطا: `{str(e)[:150]}`", reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton("🔙 بازگشت", callback_data="main_menu")]]), parse_mode="Markdown")
        track_message(context, chat_id, sent.message_id)
        return HANDWRITTEN_PHOTO


async def handwritten_confirm(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query; await query.answer()
    athlete_id = context.user_data.get("selected_athlete")
    exercises  = context.user_data.get("handwritten_exercises", [])
    chat_id    = query.message.chat_id

    if not exercises or not athlete_id:
        await go_main_menu(update, context)
        return ConversationHandler.END

    day_num = db.get_athlete_day_count(athlete_id) + 1
    fa = str.maketrans('0123456789', '۰۱۲۳۴۵۶۷۸۹')

    for ex in exercises:
        # جستجو یا ایجاد حرکت در کتابخانه
        existing = db.search_exercises(ex["name"])
        if existing:
            ex_id = existing[0]["id"]
        else:
            ex_id = db.create_exercise(ex["name"])

        db.add_exercise_to_athlete_day(
            athlete_id, day_num, ex_id,
            int(str(ex.get("sets", 3)).translate(str.maketrans('۰۱۲۳۴۵۶۷۸۹','0123456789'))),
            str(ex.get("reps", "12"))
        )

    await delete_bot_messages(context, chat_id)
    sent = await query.message.reply_text(
        f"✅ برنامه *روز {persian_num(day_num)}* با *{len(exercises)} حرکت* ذخیره شد! 💪\n\n"
        f"🤖 هوش مصنوعی همه حرکات را با موفقیت تشخیص داد!",
        reply_markup=MAIN_COACH_KB, parse_mode="Markdown")
    track_message(context, chat_id, sent.message_id)
    context.user_data.pop("handwritten_exercises", None)
    return ConversationHandler.END


async def handwritten_retry(update: Update, context: ContextTypes.DEFAULT_TYPE):
    """کاربر می‌خواد دوباره عکس بفرسته."""
    query = update.callback_query; await query.answer()
    chat_id = query.message.chat_id
    await delete_bot_messages(context, chat_id)
    sent = await query.message.reply_text(
        "📸 عکس جدید تمرینی را ارسال کن:", reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton("🔙 بازگشت", callback_data="main_menu")]]))
    track_message(context, chat_id, sent.message_id)
    return HANDWRITTEN_PHOTO


async def _cancel(update, context):
    await go_main_menu(update, context)
    return ConversationHandler.END


handwritten_conv = ConversationHandler(
    entry_points=[CallbackQueryHandler(handwritten_start, pattern="^ath_handwritten$")],
    states={
        HANDWRITTEN_PHOTO: [
            MessageHandler(filters.PHOTO, handwritten_got_photo),
        ],
        HANDWRITTEN_CONFIRM: [
            CallbackQueryHandler(handwritten_confirm, pattern="^hw_confirm$"),
            CallbackQueryHandler(handwritten_retry,  pattern="^hw_retry$"),
        ],
    },
    fallbacks=[
        CallbackQueryHandler(_cancel, pattern="^main_menu$"),
    ],
    per_message=False,
)


def register(app):
    app.add_handler(handwritten_conv)
