import os
import re
import asyncio
from pathlib import Path
from dotenv import load_dotenv

# .env 로드 (systemd 단독 실행 대비)
BASE_DIR = Path(__file__).resolve().parents[2]  # /var/www/html/govbot
load_dotenv(BASE_DIR / ".env")

from telegram import Update, InlineKeyboardMarkup, InlineKeyboardButton, ReplyKeyboardMarkup, ReplyKeyboardRemove
from telegram.constants import ParseMode
from telegram.ext import (
    Application, CommandHandler, CallbackQueryHandler, ContextTypes,
    ConversationHandler, MessageHandler, filters
)

from app.services.supabase_service import get_subscriber, add_subscriber, delete_subscriber
# lazy import in handler
from app.workers.org_sync import run as sync_all_org_run   # ← 통합 실행
from app.services.motie_org_service import search_org
from app.services.moef_org_service import search_moef_org

TOKEN = os.getenv("TELEGRAM_BOT_TOKEN")

# 콜백 데이터 키
CB_UNSUB_CONFIRM = "unsub_confirm"
CB_UNSUB_CANCEL  = "unsub_cancel"

# 대화 상태
AWAIT_QUERY = 1
AWAIT_MOEF_QUERY = 2

# ---------- helpers ----------
def _esc(s: str) -> str:
    s = s or ""
    return s.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")

def _tel_href(raw: str) -> tuple[str, str]:
    disp = (raw or "").strip()
    href = re.sub(r"[^\d+]", "", disp)
    if not href:
        return disp, ""
    return disp, f"tel:{href}"

def _format_rows_chunks(rows, max_chunk_len=3500):
    chunks, block, cur = [], [], 0
    for r in rows or []:
        dept = _esc(r.get("department") or "-")
        pos  = _esc(r.get("position") or "-")
        name = _esc(r.get("name") or "-")
        phone_raw = r.get("phone") or ""
        task = _esc(r.get("task") or "")

        disp_phone, tel = _tel_href(phone_raw)
        disp_phone_esc = _esc(disp_phone)

        lines = []
        lines.append(f"[{dept}]")
        lines.append(f"{pos} {name}")
        if tel:
            lines.append(f'<a href="{tel}">{disp_phone_esc}</a>')
        elif disp_phone_esc:
            lines.append(disp_phone_esc)
        if task:
            lines.append(task)

        entry = "\n".join(lines) + "\n\n"
        if cur + len(entry) > max_chunk_len and block:
            chunks.append("".join(block)); block, cur = [], 0
        block.append(entry); cur += len(entry)

    if block:
        chunks.append("".join(block))
    return chunks or ["결과가 없습니다."]

# ---------- handlers ----------
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
    await update.message.reply_text(
        "정부 인사 추적 봇입니다.\n"
        "/subscribe : 구독 시작/해지\n"
        "/crawl : 즉시 수집 실행(모티/기재부)\n"
        "/sync_org : 조직도 갱신(MOTIE + MOEF)\n"
        "/motie_search : MOTIE 직원/부서 검색 (대화형)\n"
        "/moef_search : MOEF 직원/부서 검색 (대화형)"
    )

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

    subscriber = get_subscriber(chat_id)
    if subscriber is None:
        add_subscriber(chat_id, first_name)
        await update.message.reply_text("✅ 구독이 시작되었습니다. 이제부터 알림을 보내드립니다.")
        return

    keyboard = InlineKeyboardMarkup([
        [InlineKeyboardButton("🔕 해지", callback_data=CB_UNSUB_CONFIRM)],
        [InlineKeyboardButton("유지", callback_data=CB_UNSUB_CANCEL)]
    ])
    await update.message.reply_text("이미 구독 중입니다. 해지하시겠습니까?", reply_markup=keyboard)

async def on_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    chat_id = query.message.chat.id
    data = query.data

    if data == CB_UNSUB_CONFIRM:
        delete_subscriber(chat_id)
        await query.answer("구독 해지 완료")
        await query.edit_message_text("🔕 구독이 해지되었습니다. 다시 원하시면 /subscribe 를 입력하세요.")
        return

    if data == CB_UNSUB_CANCEL:
        await query.answer("구독 유지")
        await query.edit_message_text("유지로 선택하셨습니다. 계속 알림을 보내드릴게요.")
        return

    await query.answer()

async def crawl(update: Update, context: ContextTypes.DEFAULT_TYPE):
    await update.message.reply_text("⏳ 크롤 실행 중...")
    try:
        from app.workers.crawl_runner import run_once
        await asyncio.to_thread(run_once)  # MOTIE + MOEF 동시
        await update.message.reply_text("✅ 크롤 실행 완료(신규만 알림).")
    except Exception as e:
        await update.message.reply_text(f"❌ 크롤 실패: {e}")

async def sync_org(update: Update, context: ContextTypes.DEFAULT_TYPE):
    await update.message.reply_text("⏳ 조직도 갱신 중...(MOTIE + MOEF)")
    try:
        await asyncio.to_thread(sync_all_org_run)  # 두 조직도 통합 실행
        await update.message.reply_text("✅ 조직도 갱신 완료")
    except Exception as e:
        await update.message.reply_text(f"❌ 조직도 갱신 실패: {e}")

# ===== MOTIE 검색: 대화형 =====
async def motie_search_entry(update: Update, context: ContextTypes.DEFAULT_TYPE):
    await update.message.reply_text(
        "검색할 키워드를 입력해 주세요.\n"
        "예) 홍길동 / 산업정책국",
        reply_markup=ReplyKeyboardRemove()
    )
    return AWAIT_QUERY

async def motie_search_query(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = (update.message.text or "").strip()
    if not query:
        await update.message.reply_text("키워드를 다시 입력해 주세요.")
        return AWAIT_QUERY

    await update.message.reply_text(f"🔎 검색 중: {query}")
    try:
        rows = await asyncio.to_thread(search_org, query, 80)
        chunks = _format_rows_chunks(rows)
        for c in chunks:
            await update.message.reply_text(c, parse_mode=ParseMode.HTML, disable_web_page_preview=True)
        await update.message.reply_text(
            "검색을 종료합니다. 추가 검색이 필요하면 아래 버튼을 누르세요.",
            reply_markup=ReplyKeyboardMarkup([["/motie_search"]], resize_keyboard=True, one_time_keyboard=True)
        )
        return ConversationHandler.END
    except Exception as e:
        await update.message.reply_text(f"❌ 검색 중 오류: {e}")
        await update.message.reply_text(
            "검색을 종료합니다. 추가 검색이 필요하면 아래 버튼을 누르세요.",
            reply_markup=ReplyKeyboardMarkup([["/motie_search"]], resize_keyboard=True, one_time_keyboard=True)
        )
        return ConversationHandler.END

# ===== MOEF 검색: 대화형 =====
async def moef_search_entry(update: Update, context: ContextTypes.DEFAULT_TYPE):
    await update.message.reply_text(
        "MOEF 검색할 키워드를 입력해 주세요.\n"
        "예) 홍길동 / 경제정책국",
        reply_markup=ReplyKeyboardRemove()
    )
    return AWAIT_MOEF_QUERY

async def moef_search_query(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = (update.message.text or "").strip()
    if not query:
        await update.message.reply_text("키워드를 다시 입력해 주세요.")
        return AWAIT_MOEF_QUERY

    await update.message.reply_text(f"🔎 검색 중: {query}")
    try:
        rows = await asyncio.to_thread(search_moef_org, query, 80)
        chunks = _format_rows_chunks(rows)
        for c in chunks:
            await update.message.reply_text(c, parse_mode=ParseMode.HTML, disable_web_page_preview=True)
        await update.message.reply_text(
            "검색을 종료합니다. 추가 검색이 필요하면 아래 버튼을 누르세요.",
            reply_markup=ReplyKeyboardMarkup([["/moef_search"]], resize_keyboard=True, one_time_keyboard=True)
        )
        return ConversationHandler.END
    except Exception as e:
        await update.message.reply_text(f"❌ 검색 중 오류: {e}")
        await update.message.reply_text(
            "검색을 종료합니다. 추가 검색이 필요하면 아래 버튼을 누르세요.",
            reply_markup=ReplyKeyboardMarkup([["/moef_search"]], resize_keyboard=True, one_time_keyboard=True)
        )
        return ConversationHandler.END

async def cancel(update: Update, context: ContextTypes.DEFAULT_TYPE):
    await update.message.reply_text(
        "검색을 종료합니다. 추가 검색이 필요하면 아래 버튼을 누르세요.",
        reply_markup=ReplyKeyboardMarkup([["/motie_search"], ["/moef_search"]], resize_keyboard=True, one_time_keyboard=True)
    )
    return ConversationHandler.END

def main():
    if not TOKEN:
        raise RuntimeError("TELEGRAM_BOT_TOKEN 미설정")

    app = Application.builder().token(TOKEN).build()

    # 기본 명령
    app.add_handler(CommandHandler("start", start))
    app.add_handler(CommandHandler("subscribe", subscribe))
    app.add_handler(CommandHandler("crawl", crawl))
    app.add_handler(CommandHandler("sync_org", sync_org))
    app.add_handler(CallbackQueryHandler(on_callback))

    # /motie_search 대화형
    conv_motie = ConversationHandler(
        entry_points=[CommandHandler("motie_search", motie_search_entry)],
        states={ AWAIT_QUERY: [MessageHandler(filters.TEXT & ~filters.COMMAND, motie_search_query)] },
        fallbacks=[CommandHandler("cancel", cancel)],
        allow_reentry=True,
    )
    app.add_handler(conv_motie)

    # /moef_search 대화형
    conv_moef = ConversationHandler(
        entry_points=[CommandHandler("moef_search", moef_search_entry)],
        states={ AWAIT_MOEF_QUERY: [MessageHandler(filters.TEXT & ~filters.COMMAND, moef_search_query)] },
        fallbacks=[CommandHandler("cancel", cancel)],
        allow_reentry=True,
    )
    app.add_handler(conv_moef)

    app.run_polling(allowed_updates=Update.ALL_TYPES)

if __name__ == "__main__":
    main()
