import json
import time
from datetime import datetime

from flask import Flask, request, jsonify
from loguru import logger
# 引入逻辑类
from inv_img_double_search import AmazonImageSearch, SITE_CONFIG_MAPPER
from amazon_configs import site_name_secret_dict
from py_spider.utils.secure_db_client import get_remote_engine

app = Flask(__name__)

# 让 Flask 支持中文返回不乱码
app.config['JSON_AS_ASCII'] = False


@app.route('/', methods=['GET'])
def index():
    """
    首页：显示服务状态和简易文档
    """
    html_content = """
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <title>Amazon 以图搜图服务</title>
        <style>
            body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; max-width: 800px; margin: 0 auto; padding: 40px; line-height: 1.6; color: #333; }
            .container { background: #f9f9fa; padding: 30px; border-radius: 10px; border: 1px solid #e1e4e8; }
            h1 { color: #2c3e50; border-bottom: 2px solid #3498db; padding-bottom: 10px; }
            .status { color: #27ae60; font-weight: bold; font-size: 1.2em; }
            .endpoint { background: #2c3e50; color: #fff; padding: 5px 10px; border-radius: 4px; font-family: monospace; }
            .method { background: #e67e22; color: white; padding: 2px 6px; border-radius: 3px; font-size: 0.8em; font-weight: bold; }
            pre { background: #2d2d2d; color: #f8f8f2; padding: 15px; border-radius: 5px; overflow-x: auto; }
        </style>
    </head>
    <body>
        <div class="container">
            <h1>📸 Amazon Image Search API</h1>
            <p>状态：<span class="status">✅ 服务正在运行 (Service is Running)</span></p>

            <h3>接口信息</h3>
            <p>URL: <span class="endpoint">/api/search_image</span> <span class="method">POST</span></p>

            <h3>请求示例 (JSON)</h3>
            <pre>
{
    "image_url": "https://m.media-amazon.com/images/I/51i3aMcjmOL._SL600_.jpg",
    "site_name": "us",     // 可选: us
    "search_mode": "default" // 可选: default, full_image
}
            </pre>

            <h3>健康检查</h3>
            <p>URL: <a href="/health">/health</a> <span class="method">GET</span></p>
        </div>
    </body>
    </html>
    """
    return html_content


# ==========================================
#  核心业务接口
# ==========================================
@app.route('/api/search_image', methods=['POST'])
def search_image_api():
    """
    接口描述：Amazon 以图搜图
    Method: POST
    """
    # 1. 获取并校验 JSON
    data = request.get_json(silent=True)
    if not data:
        return jsonify({"code": 400, "msg": "Body必须是JSON格式"}), 400

    image_url = data.get("image_url")
    site_name = data.get("site_name", "us")
    search_mode = data.get("search_mode", "default")
    if site_name not in SITE_CONFIG_MAPPER:
        return jsonify({"code": 400, "msg": "不支持的站点"}), 400
    # 连接数据库
    engine = get_remote_engine(site_name=site_name, db_type="mysql")

    if not engine:
        logger.error(f"站点 {site_name} 数据库连接失败")

    task_id = None
    # ======================================================
    # 2：写入数据库 (发布任务)
    # ======================================================
    try:
        now_time = datetime.now()  # 获取当前时间 mysql的时间慢20多秒
        now_time_str = now_time.strftime("%Y-%m-%d %H:%M:%S")
        sql = "INSERT INTO us_inv_img_result (img_url, state,search_mode,site_name,created_at) VALUES (%s, 1, %s, %s, %s);"
        # cursor.execute(sql, (image_url, now_time))
        with engine.begin() as conn:  # 把当前url写入sql 状态记录为1
            conn.execute(sql, [(image_url,search_mode,site_name, now_time_str)])
        # 查询url对应的id  注意 同一时间如果多个同样的链接插入 会查询最新的id
        sql_find = "SELECT id, created_at  FROM us_inv_img_result  WHERE img_url = '%s' AND state = 1 ORDER BY id DESC LIMIT 1;" % (image_url)
        df_data = engine.read_sql(sql_find).to_dict(orient='records') # 转字典  格式为 [{}]

        if df_data:
            db_id = df_data[0].get('id') # 获取id
            db_created_at = df_data[0].get('created_at') # 获取创建时间
            db_created_at = datetime.strptime(db_created_at, "%Y-%m-%dT%H:%M:%S") #转datetime类型计算
            # 计算查出来的数据时间，和我们刚才插入的时间差
            # 如果在误差范围内 -> 认定这就是刚才插的那条。
            # 如果时间差很大 -> 说明插入失败了，或者查到了很久以前的历史数据，报错处理
            if db_created_at:
                time_diff = abs((now_time - db_created_at).total_seconds())
                if time_diff < 3:
                    # 时间吻合，认定这就是我刚刚插入的那条
                    task_id = db_id
                    logger.info(f"任务已创建 ID: {task_id}, 等待 VPS 处理...")
                else:
                    logger.warning(f"查到了记录 ID:{db_id}，但时间相差太大({time_diff}s)，可能是历史旧数据，判定插入失败")
            else:
                # 极少情况：数据库里有数据但没时间，保守起见放行
                task_id = db_id
        else:
            logger.error("查询数据失败")
    except Exception as e:
        logger.error(f"数据库操作失败，直接转入本地运行: {e}")
        # 如果数据库挂了，不直接报错，而是直接去跑本地兜底逻辑

    # ======================================================
    # 3. 轮询等待结果
    # ======================================================
    if task_id:
        while True:
            row_dict = None
            try:
                 # 每次必须查 state, result_data 和 created_at
                select_sql = "SELECT state, result_data, created_at FROM us_inv_img_result WHERE id = %s;" % (task_id)
                select_df_data = engine.read_sql(select_sql).to_dict(orient='records')
                if select_df_data:
                    row_dict = select_df_data[0] # 取出这条数据  字典格式
            except Exception as e:
                logger.error(f"轮询异常: {e}")
            # 如果任务突然查不到了，直接跳出走本地
            if not row_dict:
                break
            state = row_dict.get('state')
            created_at  = row_dict.get('created_at')  # 类型是字符串
            created_at = datetime.strptime(created_at, "%Y-%m-%dT%H:%M:%S")
            # 计算耗时 (当前时间 - 数据库里的创建时间)
            elapsed_seconds = 0
            if created_at:
                elapsed_seconds = (datetime.now() - created_at).total_seconds()
            # 情况1: 状态为 3 (已完成) -> ，返回结果
            if state == 3:
                try:
                    res_data = json.loads(row_dict['result_data'])
                    if res_data.get("success") == 1:
                        logger.success(f"任务 {task_id} 状态3 VPS完成 (耗时{elapsed_seconds:.1f}s)")
                        return jsonify({"code": 200, "msg": "success", "data": res_data})
                    else:
                        # VPS 标记为失败 (success=0)
                        logger.warning(f"任务 {task_id} 状态3 VPS返回失败(success=0). 总耗时: {elapsed_seconds:.1f}s")
                        # 判断时间是否超过 1 分钟
                        if elapsed_seconds > 60:
                            logger.error("VPS失败状态3且已超时超过60s，不再兜底，直接返回失败")
                            return jsonify({"code": 500, "msg": "本地处理失败", "data": res_data}), 500
                        else:
                            logger.info("耗时未超60s，转本地兜底重试...")
                            break # 跳出循环，去执行本地逻辑
                except:
                    # 极少情况：JSON解析失败，视为失败走兜底
                    break

            # 情况2: 状态为 1 (待处理) 且 耗时超过 60秒 -> 超时兜底
            if state == 1 and elapsed_seconds > 60:
                logger.warning(f"任务 {task_id} [待处理 状态1] 超时 ({elapsed_seconds:.1f}s > 5s) -> 转本地")
                break

            # 情况3: 状态为 2 (爬取中) 且 耗时超过 60秒 -> 超时兜底
            if state == 2 and elapsed_seconds > 60:
                logger.warning(f"任务 {task_id} [进行中状态2] 超时 ({elapsed_seconds:.1f}s > 30s) -> 转本地")
                break

            # 没超时也没完成，休息0.3秒继续查
            time.sleep(0.3)

    # ======================================================
    # 4. 本地兜底逻辑
    # ======================================================
    try:
        logger.info(f"启动本地爬虫兜底: ")
        logger.info(f"收到API请求: Site={site_name}, Mode={search_mode}, URL={image_url}")
        client = AmazonImageSearch(site_name=site_name)
        result = client.search(image_url, search_mode=search_mode)
        # 简单检查本地是否成功
        if result.get("error") or result.get("success") == 0:
            return jsonify({"code": 500, "msg": "本地处理失败", "data": result}), 500
        if task_id:
            if result.get("success") == 1:
                try:
                    json_result = json.dumps(result, ensure_ascii=False)
                    finish_time = datetime.now()
                    finish_time_str = finish_time.strftime("%Y-%m-%d %H:%M:%S")
                    # 更新状态为 3 (已完成)，填入结果，更新时间
                    up_sql =  "UPDATE us_inv_img_result SET state = 3, result_data = %s, updated_at = %s WHERE id = %s"
                    with engine.begin() as conn:
                        conn.execute(up_sql, [(json_result, finish_time_str,task_id)])
                    logger.info(f"本地兜底结果已保存至数据库 ID: {task_id}")

                except Exception as save_e:
                    # 存库失败只记录日志，不影响给用户返回结果
                    logger.error(f"本地结果回写数据库失败: {save_e}")
            else:
                logger.info(f"本地兜底结果 解析失败 ID: {task_id}")
        return jsonify({"code": 200, "msg": "success", "data": result})
    except Exception as e:
        logger.error(f"本地执行出错: {e}")
        return jsonify({"code": 500, "msg": f"Server Error: {str(e)}"}), 500


@app.route('/health', methods=['GET'])
def health():
    """健康检查接口"""
    return jsonify({"status": "ok", "service": "Amazon Image Search"})


if __name__ == "__main__":
    # 启动服务
    logger.info("Flask 服务正在启动...")
    # logger.info("请访问 http://127.0.0.1:5000 查看首页")
    app.run(host='0.0.0.0', port=5000, debug=False)