import os, json, time
import requests
from fastapi import FastAPI, Request
import uvicorn
from dotenv import load_dotenv

BASE_DIR = os.path.dirname(os.path.abspath(__file__))
ENV_PATH = os.path.join(BASE_DIR, ".env")
load_dotenv(ENV_PATH, override=True)

app = FastAPI()

APP_ID = (os.getenv("LARK_APP_ID") or "").strip()
APP_SECRET = (os.getenv("LARK_APP_SECRET") or "").strip()
BITABLE_APP_TOKEN = (os.getenv("BITABLE_APP_TOKEN") or "").strip()
BITABLE_TABLE_ID = (os.getenv("BITABLE_TABLE_ID") or "").strip()

_cache = {"token": None, "exp": 0}

def tenant_token():
    now = int(time.time())
    if _cache["token"] and now < _cache["exp"]:
        return _cache["token"]

    url = "https://open.larksuite.com/open-apis/auth/v3/tenant_access_token/internal"
    r = requests.post(url, json={"app_id": APP_ID, "app_secret": APP_SECRET}, timeout=15)
    data = r.json()
    if data.get("code") != 0:
        raise RuntimeError(f"Get token failed: {data}")

    _cache["token"] = data["tenant_access_token"]
    _cache["exp"] = now + 7000
    return _cache["token"]

def reply_msg(message_id: str, text: str):
    token = tenant_token()
    url = f"https://open.larksuite.com/open-apis/im/v1/messages/{message_id}/reply"
    headers = {
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json; charset=utf-8"
    }
    payload = {
        "msg_type": "text",
        "content": json.dumps({"text": text}, ensure_ascii=False)
    }
    r = requests.post(url, headers=headers, json=payload, timeout=15)
    return r.json()

def safe_get_text(raw_content):
    if raw_content is None:
        return ""
    if isinstance(raw_content, dict):
        return (raw_content.get("text") or "").strip()
    s = str(raw_content).strip()
    try:
        obj = json.loads(s)
        if isinstance(obj, dict):
            return (obj.get("text") or "").strip()
        if isinstance(obj, str):
            try:
                obj2 = json.loads(obj)
                if isinstance(obj2, dict):
                    return (obj2.get("text") or "").strip()
            except Exception:
                return obj.strip()
            return obj.strip()
    except Exception:
        pass
    return s

def bitable_list_first_n(n=5):
    token = tenant_token()
    url = f"https://open.larksuite.com/open-apis/bitable/v1/apps/{BITABLE_APP_TOKEN}/tables/{BITABLE_TABLE_ID}/records"
    headers = {
        "Authorization": f"Bearer {token}"
    }
    params = {
        "page_size": max(1, min(200, n))
    }

    r = requests.get(url, headers=headers, params=params, timeout=15)

    ct = r.headers.get("content-type", "")
    prefix = (r.text or "")[:200].replace("\n", "\\n")
    print("BITABLE_HTTP =", r.status_code, "CT =", ct, "PREFIX =", prefix)

    try:
        return r.json()
    except Exception as e:
        return {
            "code": -1,
            "msg": f"bitable non-json response: {repr(e)}",
            "http": r.status_code,
            "content_type": ct,
            "prefix": prefix
        }

@app.post("/lark/webhook")
async def webhook(req: Request):
    body = await req.json()

    if "challenge" in body:
        return {"challenge": body["challenge"]}

    event = body.get("event", {})
    msg = event.get("message", {})

    if msg.get("message_type") != "text":
        return {"code": 0}

    message_id = msg.get("message_id")
    if not message_id:
        return {"code": 0}

    text = safe_get_text(msg.get("content")).strip()

    if text in ["base测试", "base test", "bitable测试"]:
        data = bitable_list_first_n(5)

        if data.get("code") != 0:
            reply_msg(
                message_id,
                f"Base读取失败：{data.get('msg')}（code={data.get('code')}）\n"
                f"HTTP={data.get('http')} CT={data.get('content_type')}\n"
                f"PREFIX={data.get('prefix')}"
            )
        else:
            items = data.get("data", {}).get("items", [])
            lines = [f"共返回 {len(items)} 条（展示字段名）:"]
            for i, it in enumerate(items, 1):
                keys = list((it.get("fields") or {}).keys())
                lines.append(f"{i}. {', '.join(keys[:12])}")
            reply_msg(message_id, "\n".join(lines))
    else:
        reply_msg(message_id, f"收到：{text}\n可用命令：base测试")

    return {"code": 0}

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000)
