import pandas as pd
import requests
import logging
import time
import json
from sqlalchemy import create_engine
from urllib.parse import quote_plus
from datetime import datetime

# 配置日志

logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s %(levelname)s %(name)s %(message)s'
    )

# ====================== 全局配置 ======================
# 数据库连接配置
DB_CONFIG = {
    'host': 'eutsp-prod.mysql.germany.rds.aliyuncs.com',
    'port': 3306,
    'user': 'international_tsp_eu_r',
    'password': 'ZXhBgo1TB2XbF3kP',
    'database': 'chery_international_tsp_eu'
}

# 飞书多维表格配置
FEISHU_APP_TOKEN = "T3QLbmpqma014ussjy9cgitqnSh"  # 应用Token
FEISHU_TABLE_ID = "tbloPJHLc05MHIAY"  # 表格ID
VIN_FIELD_NAME = "车架号"  # VIN字段名称
ACTIVE_FIELD_NAME = "激活状态"  # 激活状态字段名称
VEHICLE_NAME_FIELD = "车型"

# 飞书应用凭证
APP_ID = "cli_a8b50ec0eed1500d"
APP_SECRET = "ccxkE7ZCFQZcwkkM1rLy0ccZRXYsT2xK"

# 飞书机器人配置
WEBHOOK_URL = "https://open.feishu.cn/open-apis/bot/v2/hook/3bc45247-c469-47a0-bfe9-c62e46c5aca0"
MULTI_TABLE_URL = "https://my-ichery.feishu.cn/base/T3QLbmpqma014ussjy9cgitqnSh?from=from_copylink"

# ====================== 通用函数 ======================
def get_access_token():
    """获取飞书访问令牌"""
    api_token_url = "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal/"
    api_post_data = {"app_id": APP_ID, "app_secret": APP_SECRET}
    try:
        response = requests.post(api_token_url, json=api_post_data, timeout=10)
        response.raise_for_status()
        resp_data = response.json()
        if resp_data.get("code") == 0:
            return resp_data["tenant_access_token"]
        else:
            raise Exception(f"获取Token失败: {resp_data.get('msg')}")
    except Exception as e:
        logging.error(f"获取飞书Token异常: {e}")
        raise

def send_feishu_message(message):
    """发送飞书通知[9,10](@ref)"""
    headers = {'Content-Type': 'application/json'}

    # 构建交互式卡片
    payload = {
        "msg_type": "interactive",
        "card": {
            "config": {"wide_screen_mode": True},
            "elements": [
                {
                    "tag": "div",
                    "text": {"content": message, "tag": "lark_md"}
                },
                {
                    "tag": "action",
                    "actions": [
                        {
                            "tag": "button",
                            "text": {"content": "查看多维表格", "tag": "plain_text"},
                            "type": "primary",
                            "url": MULTI_TABLE_URL
                        }
                    ]
                }
            ],
            "header": {
                "title": {"content": "车辆状态同步报告", "tag": "plain_text"},
                "template": "blue"
            }
        }
    }

    try:
        response = requests.post(WEBHOOK_URL, headers=headers, json=payload, timeout=10)
        response.raise_for_status()
        return response.json()
    except Exception as e:
        logging.error(f"飞书消息发送失败: {str(e)}")
        return None
def read_feishu_records(app_token, table_id, retry=3):
    """从飞书多维表格读取车辆记录"""
    access_token = get_access_token()
    headers = {
        "Authorization": f"Bearer {access_token}",
        "Content-Type": "application/json; charset=utf-8",
    }

    url = f"https://open.feishu.cn/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/records"
    params = {"page_size": 500}

    all_records = []
    page_token = None

    while True:
        if page_token:
            params["page_token"] = page_token

        for attempt in range(retry):
            try:
                response = requests.get(url, headers=headers, params=params, timeout=30)
                response.raise_for_status()
                resp_data = response.json()
                if resp_data.get("code") != 0:
                    raise Exception(f"API错误: {resp_data.get('msg')}")
                records = resp_data["data"]["items"]
                all_records.extend(records)
                has_more = resp_data["data"].get("has_more")
                page_token = resp_data["data"].get("page_token") if has_more else None
                break
            except Exception as e:
                logging.warning(f"读取多维表格失败(尝试 {attempt+1}/{retry}): {e}")
                time.sleep(2 ** attempt)
        else:
            raise Exception("无法读取多维表格数据")

        if not page_token:
            break

    return all_records


def fetch_activation_data():
    """从数据库查询车辆激活状态和车型"""
    try:
        safe_password = quote_plus(DB_CONFIG['password'])
        engine = create_engine(
            f"mysql+pymysql://{DB_CONFIG['user']}:{safe_password}@{DB_CONFIG['host']}:{DB_CONFIG['port']}/{DB_CONFIG['database']}",
            pool_recycle=3600
        )

        sql_query = """
        SELECT
            v.VIN AS car_vins,
            CASE s.STATE
                WHEN 2 THEN 'active'
                ELSE 'no_active'
            END AS active_status,
            iv.`NAME` AS `车型`
        FROM v_vehicle_info v
        JOIN v_tbox_info t USING (VIN)
        JOIN v_sim_info s USING (SN)
        LEFT JOIN v_material_info m ON m.MATERIAL_ID = v.MATERIAL_ID
        LEFT JOIN v_outside_vehicle_type ov ON ov.TYPE_CODE = m.OUTSIDE_TYPE_CODE
        LEFT JOIN v_inside_vehicle_type iv ON iv.TYPE_CODE = ov.INSIDE_TYPE_CODE
        """

        df = pd.read_sql(sql_query, engine)
        # --- 新增：按 VIN 去重，保留第一条记录 ---
        df = df.drop_duplicates(subset=['car_vins'], keep='first')
        # 校验列是否都在
        expected = ['car_vins', 'active_status', VEHICLE_NAME_FIELD]
        missing = [c for c in expected if c not in df.columns]
        if missing:
            logging.error(f"查询结果缺少列: {missing}")
            raise KeyError(f"Missing columns: {missing}")

        # 设索引并返回字典
        df2 = df.set_index('car_vins')[['active_status', VEHICLE_NAME_FIELD]]
        return df2.to_dict(orient='index')

    except Exception as e:
        logging.error(f"数据库查询失败: {e}")
        raise



def compare_and_update_records(app_token, table_id, activation_data):
    """比较并更新飞书多维表格记录：既更新激活状态，也写入车型"""
    access_token = get_access_token()
    headers = {
        "Authorization": f"Bearer {access_token}",
        "Content-Type": "application/json; charset=utf-8",
    }

    feishu_records = read_feishu_records(app_token, table_id)
    logging.info(f"成功读取{len(feishu_records)}条多维表格记录")

    records_to_update = []
    activated_count = not_activated_count = 0

    for record in feishu_records:
        record_id = record.get("record_id")
        fields = record.get("fields", {})
        vin = fields.get(VIN_FIELD_NAME)
        if not vin:
            logging.warning(f"记录 {record_id} 缺少VIN字段")
            continue

        db = activation_data.get(vin)
        if not db:
            logging.warning(f"VIN {vin} 在数据库中未找到")
            continue

        db_status = db['active_status']
        db_name   = db[VEHICLE_NAME_FIELD]

        current_status = fields.get(ACTIVE_FIELD_NAME, "").lower()
        current_name   = fields.get(VEHICLE_NAME_FIELD, "")

        if db_status != current_status or db_name != current_name:
            update_fields = {
                ACTIVE_FIELD_NAME:  db_status,
                VEHICLE_NAME_FIELD: db_name
            }
            records_to_update.append({
                "record_id": record_id,
                "fields": update_fields
            })
            logging.debug(f"VIN {vin} 需要更新: 状态 {current_status}→{db_status}, 车型 {current_name}→{db_name}")

            if db_status == "active":
                activated_count += 1
            else:
                not_activated_count += 1

    total_updated = len(records_to_update)
    logging.info(f"需要更新 {total_updated} 条记录（激活：{activated_count}，未激活：{not_activated_count}）")

    # 批量更新
    batch_size = 50
    for i in range(0, total_updated, batch_size):
        batch = records_to_update[i:i+batch_size]
        payload = {"records": batch}
        url = f"https://open.feishu.cn/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/records/batch_update"
        for attempt in range(3):
            try:
                r = requests.post(url, headers=headers, json=payload, timeout=30)
                data = r.json()
                if r.status_code == 200 and data.get("code") == 0:
                    logging.info(f"第{i//batch_size+1}批更新成功，{len(batch)}条")
                    break
                else:
                    logging.warning(f"第{i//batch_size+1}批更新失败(尝试{attempt+1}/3)：{data.get('msg')}")
            except Exception as e:
                logging.warning(f"网络异常(尝试{attempt+1}/3)：{e}")
                time.sleep(2 ** attempt)

    return total_updated, activated_count, not_activated_count


def sync_vehicle_activation():
    """执行车辆激活状态同步流程"""
    try:
        start_time = time.time()
        logging.info("开始车辆激活状态同步流程...")

        activation_data = fetch_activation_data()
        logging.info(f"从数据库获取{len(activation_data)}条激活状态记录")

        db_activated     = sum(1 for v in activation_data.values() if v['active_status']=='active')
        db_not_activated = sum(1 for v in activation_data.values() if v['active_status']=='no_active')
        logging.info(f"数据库统计: 激活车辆 {db_activated}台, 未激活车辆 {db_not_activated}台")

        total_updated, activated_count, not_activated_count = compare_and_update_records(
            FEISHU_APP_TOKEN, FEISHU_TABLE_ID, activation_data
        )

        logging.info("="*50)
        logging.info(f"本次更新统计: 总更新 {total_updated}台, 激活 {activated_count}台, 未激活 {not_activated_count}台")
        logging.info("="*50)

        elapsed = time.time()-start_time
        logging.info(f"流程完成! 耗时 {elapsed:.2f}秒")
        return {
            "total_updated": total_updated,
            "activated_count": activated_count,
            "not_activated_count": not_activated_count,
            "elapsed_time": elapsed
        }

    except Exception as e:
        logging.error(f"流程执行异常: {e}")
        logging.exception("详细错误信息")
        return None

if __name__ == '__main__':
    sync_result=sync_vehicle_activation()


    if sync_result:
        # 构建飞书消息
        current_time = datetime.now().strftime("%Y-%m-%d %H:%M")
        message = (
            f"🚗 **车辆激活状态同步完成** ✅\n"
            f"⏰ 同步时间: {current_time}\n"
            f"⏱️ 处理耗时: {sync_result['elapsed_time']:.2f}秒\n\n"
            f"📊 **同步统计结果:**\n"
            f"• 更新车辆总数: {sync_result['total_updated']}台\n"
            f"• ✅ 激活车辆数量: {sync_result['activated_count']}台\n"
            f"• ❌ 未激活车辆数量: {sync_result['not_activated_count']}台\n\n"
            f"🔗 查看多维表格: [点击访问]({MULTI_TABLE_URL})"
        )

        # 发送飞书通知
        send_result = send_feishu_message(message)
        if send_result:
            logging.info(f"飞书消息发送成功: {send_result}")
        else:
            logging.error("飞书消息发送失败")
    else:
        error_message = "❌ 车辆激活状态同步失败，请检查日志"
        send_feishu_message(error_message)
        logging.error(error_message)
