"""Step 1: 全量采集ERP表结构到 erp_schema
通过 erp-api-gateway 采集985张表的字段信息
运行: python3 scripts/collect_erp_schema.py
"""

import sys
import os
import json
import urllib.request
import urllib.error
import logging
import time
from datetime import datetime

sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from app.database import get_session_local
from sqlalchemy import text

logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
logger = logging.getLogger("erp_schema_collect")

ERP_API_BASE = "http://127.0.0.1:8300/api/v1"
ERP_API_KEY = os.getenv("ERP_API_KEY", "erp-gateway-key-bhwl-2026")

HEADERS = {
    "X-API-Key": ERP_API_KEY,
    "User-Agent": "CMA-ERP-SCHEMA/1.0",
    "Content-Type": "application/json",
}


def api_get(path: str) -> dict:
    """调用ERP API"""
    url = f"{ERP_API_BASE}{path}"
    req = urllib.request.Request(url, headers=HEADERS)
    with urllib.request.urlopen(req, timeout=30) as resp:
        return json.loads(resp.read().decode())


def get_table_columns(table_name: str) -> list:
    """通过 INFORMATION_SCHEMA 查询表字段"""
    sql = f"""
    SELECT 
        COLUMN_NAME,
        DATA_TYPE,
        CHARACTER_MAXIMUM_LENGTH,
        IS_NULLABLE,
        COLUMN_DEFAULT
    FROM INFORMATION_SCHEMA.COLUMNS 
    WHERE TABLE_NAME = '{table_name}'
    ORDER BY ORDINAL_POSITION
    """
    params = json.dumps({"sql": sql}).encode()
    req = urllib.request.Request(
        f"{ERP_API_BASE}/query",
        data=params,
        headers=HEADERS,
        method="POST"
    )
    try:
        with urllib.request.urlopen(req, timeout=30) as resp:
            data = json.loads(resp.read().decode())
            return data.get("data", [])
    except Exception as e:
        logger.warning(f"  ⚠️ {table_name}: 查询失败 - {e}")
        return []


def get_row_count(table_name: str) -> int:
    """获取表行数"""
    sql = f"SELECT COUNT(*) as cnt FROM [{table_name}]"
    params = json.dumps({"sql": sql}).encode()
    req = urllib.request.Request(
        f"{ERP_API_BASE}/query",
        data=params,
        headers=HEADERS,
        method="POST"
    )
    try:
        with urllib.request.urlopen(req, timeout=30) as resp:
            data = json.loads(resp.read().decode())
            rows = data.get("data", [])
            return rows[0]["cnt"] if rows else 0
    except:
        return -1  # 未知


def main():
    db = get_session_local()()
    
    try:
        # 1. 获取全部表名
        logger.info("📡 获取ERP全量表名列表...")
        tables_data = api_get("/tables")
        all_tables = tables_data.get("tables", [])
        logger.info(f"  共 {len(all_tables)} 张表")

        # 2. 获取已采集的表名
        existing = set()
        try:
            rows = db.execute(text("SELECT table_name FROM erp_schema")).fetchall()
            existing = set(row[0] for row in rows)
        except:
            pass
        logger.info(f"  已采集 {len(existing)} 张表，待采集 {len(all_tables) - len(existing)} 张")

        # 3. 逐表采集
        collected = 0
        skipped = 0
        errors = 0
        
        for i, table_name in enumerate(all_tables):
            if table_name in existing:
                skipped += 1
                continue

            # 进度显示
            if (i + 1) % 50 == 0:
                logger.info(f"  进度: {i+1}/{len(all_tables)} (已采{collected}, 跳过{skipped}, 错误{errors})")

            # 采集字段
            columns = get_table_columns(table_name)
            if not columns:
                errors += 1
                # 即使查不到字段也记录一个空记录，避免重复查
                collect_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
                fields_json = "[]"
                db.execute(
                    text("""
                        INSERT INTO erp_schema (table_name, total_rows, field_count, fields_json, created_at, updated_at)
                        VALUES (:tn, :tr, :fc, :fj, NOW(), NOW())
                        ON DUPLICATE KEY UPDATE fields_json=:fj2, total_rows=:tr2, updated_at=NOW()
                    """),
                    {"tn": table_name, "tr": -1, "fc": 0, "fj": fields_json, "fj2": fields_json, "tr2": -1}
                )
                db.commit()
                continue

            # 获取行数
            row_count = get_row_count(table_name)
            field_count = len(columns)
            
            fields = []
            for col in columns:
                fields.append({
                    "name": col.get("COLUMN_NAME", ""),
                    "type": col.get("DATA_TYPE", ""),
                    "max_length": col.get("CHARACTER_MAXIMUM_LENGTH"),
                    "nullable": col.get("IS_NULLABLE", "YES"),
                    "default": col.get("COLUMN_DEFAULT"),
                })
            fields_json = json.dumps(fields, ensure_ascii=False)

            # 写入 erp_schema
            try:
                collect_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
                db.execute(
                    text("""
                        INSERT INTO erp_schema (table_name, total_rows, field_count, fields_json, created_at, updated_at)
                        VALUES (:tn, :tr, :fc, :fj, NOW(), NOW())
                        ON DUPLICATE KEY UPDATE total_rows=:tr2, field_count=:fc2, fields_json=:fj2, updated_at=NOW()
                    """),
                    {"tn": table_name, "tr": row_count, "fc": field_count, "fj": fields_json,
                     "tr2": row_count, "fc2": field_count, "fj2": fields_json}
                )
                db.commit()
                collected += 1
            except Exception as e:
                db.rollback()
                logger.warning(f"  ⚠️ {table_name}: 写入数据库失败 - {e}")
                errors += 1

            # 限流：不要打太快
            if collected > 0 and collected % 10 == 0:
                time.sleep(0.5)

        # 4. 统计
        total = db.execute(text("SELECT COUNT(*) FROM erp_schema")).scalar()
        with_data = db.execute(text("SELECT COUNT(*) FROM erp_schema WHERE field_count > 0")).scalar()
        logger.info(f"\n🎉 采集完成!")
        logger.info(f"  总计: {total} 张表 (erp_schema)")
        logger.info(f"  有字段信息: {with_data} 张")
        logger.info(f"  本次新增: {collected} 张")
        logger.info(f"  跳过(已存在): {skipped} 张")
        logger.info(f"  错误: {errors} 张")

    except Exception as e:
        logger.error(f"采集失败: {e}", exc_info=True)
    finally:
        db.close()


if __name__ == "__main__":
    main()
