import os
import time
import json
from flask import Flask, request, jsonify, redirect
import requests
import base64
import hashlib

app = Flask(__name__)

TOKEN_STORE_FILE = "token_store.json"

# 全局变量缓存token和配置
token_data = {}
APP_ID = None
APP_SECRET = None
REDIRECT_URI = None
code_verifier = None


def save_token(app_id, data):
    store = {}
    if os.path.exists(TOKEN_STORE_FILE):
        with open(TOKEN_STORE_FILE, "r") as f:
            store = json.load(f)
    store[app_id] = data
    with open(TOKEN_STORE_FILE, "w") as f:
        json.dump(store, f)


def load_token(app_id):
    if os.path.exists(TOKEN_STORE_FILE):
        with open(TOKEN_STORE_FILE, "r") as f:
            store = json.load(f)
        return store.get(app_id, {})
    return {}


def ensure_token_valid():
    global token_data
    now = time.time()
    if not token_data or not token_data.get("access_token") or now > token_data.get("expires_at", 0):
        print("[ensure_token_valid] Access token expired or missing, try refresh token...")
        if not refresh_access_token():
            print("[ensure_token_valid] Refresh token failed, need user authorization")
            return False
    return True


def refresh_access_token():
    global token_data, APP_ID, APP_SECRET
    if not token_data.get("refresh_token"):
        print("[refresh_access_token] No refresh_token available")
        return False

    resp = requests.post(
        "https://open.feishu.cn/open-apis/authen/v2/oauth/token",
        json={
            "grant_type": "refresh_token",
            "client_id": APP_ID,
            "client_secret": APP_SECRET,
            "refresh_token": token_data["refresh_token"]
        }
    )
    data = resp.json()
    print(f"[refresh_access_token] Response: {data}")

    if data.get("code") == 0:
        token_data["access_token"] = data["access_token"]
        token_data["refresh_token"] = data["refresh_token"]
        token_data["expires_at"] = time.time() + data["expires_in"] - 60
        save_token(APP_ID, token_data)
        print("[refresh_access_token] Refresh success")
        return True
    else:
        print("[refresh_access_token] Refresh failed")
        return False


def generate_code_verifier():
    # 生成随机字符串作为 code_verifier
    return base64.urlsafe_b64encode(os.urandom(32)).rstrip(b'=').decode('utf-8')

def generate_code_challenge(code_verifier):
    # 对 code_verifier 做 sha256，再 base64 urlsafe 编码得到 code_challenge
    sha256 = hashlib.sha256(code_verifier.encode('utf-8')).digest()
    return base64.urlsafe_b64encode(sha256).rstrip(b'=').decode('utf-8')

@app.route("/pkce", methods=["GET"])
def get_pkce():
    code_verifier = generate_code_verifier()
    code_challenge = generate_code_challenge(code_verifier)
    return jsonify({
        "code_verifier": code_verifier,
        "code_challenge": code_challenge
    })

@app.route("/oauth/callback")
def oauth_callback():
    global token_data, APP_ID, APP_SECRET, REDIRECT_URI, code_verifier

    code = request.args.get("code")
    state = request.args.get("state")

    if not code:
        return jsonify({"error": "Missing code param"}), 400
    if not all([APP_ID, APP_SECRET, REDIRECT_URI, code_verifier]):
        return jsonify({"error": "Missing config parameters"}), 400

    # 用code换token
    resp = requests.post(
        "https://open.feishu.cn/open-apis/authen/v2/oauth/token",
        json={
            "grant_type": "authorization_code",
            "client_id": APP_ID,
            "client_secret": APP_SECRET,
            "code": code,
            "redirect_uri": REDIRECT_URI,
            "code_verifier": code_verifier
        }
    )
    data = resp.json()
    print(f"[oauth_callback] token response: {data}")

    if data.get("code") == 0:
        token_data = {
            "access_token": data["access_token"],
            "refresh_token": data["refresh_token"],
            "expires_at": time.time() + data["expires_in"] - 60
        }
        save_token(APP_ID, token_data)
        return "授权成功！请关闭此窗口。"
    else:
        return jsonify({"error": "Token获取失败", "raw": data}), 400


@app.route("/set_config", methods=["POST"])
def set_config():
    global APP_ID, APP_SECRET, REDIRECT_URI, code_verifier, token_data
    data = request.get_json(force=True)
    APP_ID = data.get("APP_ID")
    APP_SECRET = data.get("APP_SECRET")
    REDIRECT_URI = data.get("REDIRECT_URI")
    code_verifier = data.get("code_verifier")

    if not all([APP_ID, APP_SECRET, REDIRECT_URI, code_verifier]):
        return jsonify({"error": "缺少必要参数 APP_ID, APP_SECRET, REDIRECT_URI 或 code_verifier"}), 400

    # 读取之前保存的token
    token_data = load_token(APP_ID)
    return jsonify({"message": "配置成功", "token_data": token_data})


@app.route("/calendar_events", methods=["POST"])
def calendar_events():
    global APP_ID, APP_SECRET, token_data
    if not all([APP_ID, APP_SECRET]):
        return jsonify({"error": "请先调用 /set_config 设置参数"}), 400

    if not ensure_token_valid():
        # 引导用户去授权页面
        auth_url = (
            f"https://accounts.feishu.cn/open-apis/authen/v1/authorize"
            f"?client_id={APP_ID}"
            f"&redirect_uri={REDIRECT_URI}"
            f"&scope=calendar:calendar.event:read calendar:calendar:readonly offline_access"
            f"&state=auth"
            f"&code_challenge=YOUR_CODE_CHALLENGE"  # 需要用你的code_challenge替换
            f"&code_challenge_method=S256"
        )
        return jsonify({
            "message": "请先授权",
            "auth_url": auth_url
        }), 401

    headers = {
        "Authorization": f"Bearer {token_data['access_token']}"
    }
    resp = requests.get("https://open.feishu.cn/open-apis/calendar/v4/calendars", headers=headers)
    data = resp.json()
    if data.get("code") != 0:
        return jsonify({"error": "获取日历列表失败", "raw": data}), 500

    calendars = data.get("data", {}).get("calendar_list", [])
    events_all = []
    for calendar in calendars:
        calendar_id = calendar["calendar_id"]
        ev_resp = requests.get(
            f"https://open.feishu.cn/open-apis/calendar/v4/calendars/{calendar_id}/events",
            headers=headers
        )
        ev_data = ev_resp.json()
        if ev_data.get("code") != 0:
            continue
        events = ev_data.get("data", {}).get("items", [])
        events_all.extend(events)

    return jsonify({"events": events_all})


if __name__ == "__main__":
    app.run(port=8888, debug=True)
