from typing import Annotated

from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel
from sqlalchemy.orm import Session

from app.core.database import get_db
from app.core.models import TelegramLog, TelegramLogStatus
from app.core.config import get_telegram_config
from app.core.security import get_current_user
from app.services import receipt_service
from app.services.telegram_service import (
    download_telegram_file,
    get_telegram_webhook_info,
    send_telegram_message,
    set_telegram_webhook,
)

router = APIRouter(prefix="/api/telegram", tags=["telegram"])


class TelegramSendRequest(BaseModel):
    chat_id: str
    message: str


class TelegramWebhookUpdate(BaseModel):
    url: str


def _raise_telegram_error(result: dict) -> None:
    status_code = int(result.get("status_code") or 400)
    detail = result.get("error") or "Telegram send failed"
    raise HTTPException(status_code=status_code, detail=detail)


def _chat_id_from_update(update: dict) -> str:
    message = update.get("message") or update.get("edited_message") or {}
    chat = message.get("chat") or {}
    chat_id = chat.get("id")
    return str(chat_id).strip() if chat_id is not None else ""


def _telegram_username(update: dict) -> str | None:
    message = update.get("message") or update.get("edited_message") or {}
    sender = message.get("from") or {}
    username = (sender.get("username") or "").strip()
    return username or None


def _is_authorized_chat(chat_id: str) -> bool:
    configured_chat_id = str(get_telegram_config().get("chat_id") or "").strip()
    return bool(configured_chat_id and chat_id == configured_chat_id)


def _receipt_file_id_from_update(update: dict) -> str | None:
    message = update.get("message") or update.get("edited_message") or {}
    photos = message.get("photo") or []
    if photos:
        largest = max(photos, key=lambda item: int(item.get("file_size") or 0))
        return largest.get("file_id")

    document = message.get("document") or {}
    mime_type = (document.get("mime_type") or "").lower()
    file_name = (document.get("file_name") or "").lower()
    if mime_type.startswith("image/") or mime_type == "application/pdf" or file_name.endswith(".pdf"):
        return document.get("file_id")
    return None


def _text_from_update(update: dict) -> str:
    message = update.get("message") or update.get("edited_message") or {}
    return str(message.get("text") or message.get("caption") or "").strip()


def _receipt_summary(expense_id: int, processing_status: str) -> str:
    return (
        f"已生成待处理支出草稿 #{expense_id}。\n"
        f"处理状态：{processing_status}\n\n"
        "这还没有进入财务报告或 GST。请到网页版票据收件箱最终确认。"
    )


@router.post("/webhook")
async def telegram_webhook(update: dict, db: Session = Depends(get_db)):
    chat_id = _chat_id_from_update(update)
    if not _is_authorized_chat(chat_id):
        return {"ok": True, "ignored": True}

    file_id = _receipt_file_id_from_update(update)
    if not file_id:
        text = _text_from_update(update)
        if text:
            await send_telegram_message(
                chat_id,
                "ERP Telegram bot connected.\n"
                "Send a receipt photo, image document, or PDF and I will create a pending expense draft for web review.",
            )
            return {"ok": True, "handled": "text_help"}
        return {"ok": True, "ignored": True}

    await send_telegram_message(chat_id, "已收到收据，正在保存并分析，请稍等。")
    downloaded = await download_telegram_file(file_id)
    if not downloaded.get("success"):
        await send_telegram_message(chat_id, f"收据下载失败：{downloaded.get('error') or '未知错误'}")
        return {"ok": False, "error": downloaded.get("error")}

    result = await receipt_service.process_receipt_upload(
        db=db,
        filename=downloaded["filename"],
        content_type=downloaded["content_type"],
        file_bytes=downloaded["file_bytes"],
        upload_user=f"telegram:{_telegram_username(update) or chat_id}",
        source_channel="telegram",
    )
    await send_telegram_message(chat_id, _receipt_summary(result["expense_id"], result["processing_status"]))
    return {"ok": True, **result}


@router.post("/send")
async def send_message(
    req: TelegramSendRequest,
    current_user: Annotated[dict, Depends(get_current_user)],
    db: Session = Depends(get_db),
):
    """Send a Telegram message."""
    result = await send_telegram_message(req.chat_id, req.message)
    log = TelegramLog(
        chat_id=req.chat_id,
        message=req.message,
        status=TelegramLogStatus.sent if result["success"] else TelegramLogStatus.failed,
        error_message=result.get("error"),
    )
    db.add(log)
    db.commit()
    if not result["success"]:
        _raise_telegram_error(result)
    return {"success": True}


@router.post("/test")
async def test_telegram(
    current_user: Annotated[dict, Depends(get_current_user)],
    db: Session = Depends(get_db),
):
    """Send test message to configured chat_id."""
    from app.core.config import get_telegram_config

    config = get_telegram_config()
    chat_id = (config.get("chat_id") or "").strip()
    if not chat_id:
        raise HTTPException(status_code=400, detail="Telegram chat_id not configured")

    test_msg = (
        "ERP System Test Message\n"
        "------------------------\n"
        "Telegram bot is working."
    )
    result = await send_telegram_message(chat_id, test_msg)
    log = TelegramLog(
        chat_id=chat_id,
        message=test_msg,
        status=TelegramLogStatus.sent if result["success"] else TelegramLogStatus.failed,
        error_message=result.get("error"),
    )
    db.add(log)
    db.commit()
    if not result["success"]:
        _raise_telegram_error(result)
    return {"success": True, "message": "Test sent"}


@router.get("/webhook-info")
async def webhook_info(
    current_user: Annotated[dict, Depends(get_current_user)],
):
    """Get Telegram webhook status from Telegram API."""
    result = await get_telegram_webhook_info()
    if not result.get("success"):
        _raise_telegram_error(result)
    return result


@router.post("/webhook-url")
async def update_webhook_url(
    req: TelegramWebhookUpdate,
    current_user: Annotated[dict, Depends(get_current_user)],
):
    """Set Telegram webhook URL. Must be a public HTTPS URL."""
    result = await set_telegram_webhook(req.url)
    if not result.get("success"):
        _raise_telegram_error(result)
    return result


@router.get("/logs")
async def get_logs(
    current_user: Annotated[dict, Depends(get_current_user)],
    page: int = 1,
    page_size: int = 50,
    db: Session = Depends(get_db),
):
    """Get Telegram sending logs."""
    query = db.query(TelegramLog).order_by(TelegramLog.sent_at.desc())
    total = query.count()
    items = query.offset((page - 1) * page_size).limit(page_size).all()
    return {"items": items, "total": total, "page": page, "page_size": page_size}
