import concurrent.futures
import sys
import requests
from typing import List, Set, Dict, Tuple

class DingTalkDocsFetcher:

    @staticmethod
    def get_access_token(app_key: str, app_secret: str) -> str:
        url = "https://oapi.dingtalk.com/gettoken"
        params = {
            "appkey": app_key,
            "appsecret": app_secret
        }
        resp = requests.get(url, params=params)
        data = resp.json()
        if data.get("errcode") == 0:
            print("✅ AccessToken 获取成功:", data.get("access_token"))
            return data.get("access_token")
        print("❌ 获取 AccessToken 失败:", data)
        return ""

    @staticmethod
    def get_sub_departments(token: str, dept_id: int = None) -> List[Dict]:
        url = "https://oapi.dingtalk.com/topapi/v2/department/listsub"
        params = {"access_token": token}
        payload = {}
        if dept_id is not None:
            payload["dept_id"] = dept_id
        resp = requests.post(url, params=params, json=payload)
        data = resp.json()
        if data.get("errcode") == 0:
            return data.get("result", [])
        else:
            print(f"❌ 获取部门列表失败 dept_id={dept_id}: {data}")
            return []

    @staticmethod
    def get_users_by_dept(token: str, dept_id: int) -> List[str]:
        url = "https://oapi.dingtalk.com/topapi/user/listid"
        params = {"access_token": token}
        payload = {"dept_id": dept_id}
        resp = requests.post(url, params=params, json=payload)
        data = resp.json()
        if data.get("errcode") == 0:
            return data.get("result", {}).get("userid_list", [])
        else:
            print(f"❌ 获取部门用户失败 dept_id={dept_id}: {data}")
            return []

    @staticmethod
    def get_all_departments(token: str) -> List[Dict]:
        all_depts = []

        def recurse(dept_id: int = None, parent_id: int = 0):
            depts = DingTalkDocsFetcher.get_sub_departments(token, dept_id)
            for d in depts:
                dept_info = {
                    "dept_id": d["dept_id"],
                    "name": d["name"],
                    "parent_id": parent_id  # 这里用调用时的 parent_id
                }
                all_depts.append(dept_info)
                recurse(d["dept_id"], parent_id=d["dept_id"])  # 递归时传当前dept_id作为父部门ID

        recurse()
        return all_depts
    @staticmethod
    def get_user_detail(token: str, userid: str) -> dict:
        url = "https://oapi.dingtalk.com/topapi/v2/user/get"
        params = {"access_token": token}
        payload = {"userid": userid}
        resp = requests.post(url, params=params, json=payload)
        data = resp.json()
        if data.get("errcode") == 0:
            return data.get("result", {})
        else:
            print(f"获取用户详情失败: {data}")
            return None

    @staticmethod
    def get_all_user_ids(token: str, departments: List[Dict]) -> Set[str]:
        """
        根据部门列表，获取所有部门用户ID集合（去重）
        """
        user_ids = set()
        for dept in departments:
            dept_id = dept["dept_id"]
            ids = DingTalkDocsFetcher.get_users_by_dept(token, dept_id)
            user_ids.update(ids)
        return user_ids

    @staticmethod
    def get_attendance_records(token: str, user_ids: List[str], date_from: str, date_to: str):
        url = f"https://oapi.dingtalk.com/attendance/listRecord?access_token={token}"
        payload = {
            "checkDateFrom": date_from,
            "checkDateTo": date_to,
            "userIds": user_ids,
            "isI18n": "false"
        }
        resp = requests.post(url, json=payload)
        r = resp.json()
        if r.get("errcode") == 0:
            return r.get("recordresult", [])
        else:
            print(f"❌ 获取打卡记录失败: {r}")
            return []

    @staticmethod
    def main(args: List[str]) -> None:
        app_key = "dinguetojbaxvvhzpk3d"
        app_secret = "lMFqns_ceLIcXvfLL8GKfa3ZiPKHcaZq0VbGtJXJlDuK8AEJ2WV3-PN8zv61ajm3"

        token = DingTalkDocsFetcher.get_access_token(app_key, app_secret)
        if not token:
            return

        print("开始获取所有部门...")
        departments = DingTalkDocsFetcher.get_all_departments(token)
        print(f"✅ 获取部门总数: {len(departments)}")

        print("开始获取所有部门用户ID...")
        user_ids_set = DingTalkDocsFetcher.get_all_user_ids(token, departments)
        user_ids = list(user_ids_set)
        print(f"✅ 获取用户总数: {len(user_ids)}")

        date_from = "2025-08-10 12:00:00"
        date_to = "2025-08-12 12:00:00"

        print("开始获取打卡记录...")
        records = DingTalkDocsFetcher.get_attendance_records(token, user_ids, date_from, date_to)
        print(f"✅ 打卡记录数: {len(records)}")

        user_cache = {}

        def fetch_user_detail(userid):
            if userid in user_cache:
                return userid, user_cache[userid]
            detail = DingTalkDocsFetcher.get_user_detail(token, userid)
            user_cache[userid] = detail
            return userid, detail

        user_ids_in_records = list({r.get("userId") for r in records if r.get("userId")})

        with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
            futures = [executor.submit(fetch_user_detail, uid) for uid in user_ids_in_records]
            for future in concurrent.futures.as_completed(futures):
                uid, detail = future.result()
                user_cache[uid] = detail

        enhanced_records = []
        for r in records:
            userid = r.get("userId")
            user_detail = user_cache.get(userid)
            if user_detail:
                r["user_name"] = user_detail.get("name", "")
            else:
                r["user_name"] = ""
            enhanced_records.append(r)

        for r in enhanced_records:
            print(r)



if __name__ == '__main__':
    DingTalkDocsFetcher.main(sys.argv[1:])
