#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
pip3 install pymysql requests

使用方法 本地离线查找DML
python3 bin2sql_local.py \
    --host rm-bp14458076dkw81mo.mysql.rds.aliyuncs.com \
    --port 3306 \
    --user root \
    --password '123456' \
    --database db0 \
    --table resources \
    --types update \
    --local-file ./mysql-bin.000413 \
    --start-time '2026-07-27 14:45:00' \
    --stop-time '2026-07-27 14:55:00'
"""

import os
import sys
import subprocess
import pymysql
import requests
import argparse
import logging
from pathlib import Path

# 日志配置
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')


def download_bingo2sql(url, dest_path):
    """下载 bingo2sql 并设置可执行权限"""
    if os.path.exists(dest_path):
        logging.info(f"{dest_path} 已存在, 跳过下载")
        return True
    try:
        logging.info(f"正在从 {url} 下载 bingo2sql ...")
        response = requests.get(url, stream=True)
        response.raise_for_status()
        with open(dest_path, 'wb') as f:
            for chunk in response.iter_content(chunk_size=8192):
                f.write(chunk)
        os.chmod(dest_path, 0o755)  # 添加可执行权限
        logging.info(f"下载已完成并保存至 {dest_path}")
        return True
    except Exception as e:
        logging.error(f"下载失败: {e}")
        return False


def get_create_table_sql(host, port, user, password, database, table_name, output_file):
    """连接数据库, 获取建表语句并写入文件"""
    try:
        conn = pymysql.connect(
            host=host,
            port=port,
            user=user,
            password=password,
            database=database,
            charset='utf8mb4'
        )
        with conn.cursor() as cursor:
            cursor.execute(f"SHOW CREATE TABLE `{table_name}`")
            row = cursor.fetchone()
            if not row:
                logging.error(f"表 {table_name} 不存在")
                return False
            create_sql = row[1]  # 第二列是 Create Table 的内容
            with open(output_file, 'w', encoding='utf-8') as f:
                f.write(create_sql + ';\n')
            os.chmod(output_file, 0o644)  # 明确设为 rw-r--r--
            logging.info(f"建表语句已保存至 {output_file}")
            return True
    except Exception as e:
        logging.error(f"数据库操作失败: {e}")
        return False
    finally:
        if conn:
            conn.close()


def run_bingo2sql(bingo2sql_path, database, table_name, sql_type, start_file, start_time, stop_time, output_file):
    """执行 bingo2sql 命令"""
    cmd = (
        f"{bingo2sql_path} "
        f"-d {database} "
        f"-t {table_name} "
        f"--sql-type={sql_type} "
        f"--start-file={start_file} "
        f"--start-time='{start_time}' "
        f"--stop-time='{stop_time}' "        
        f"> {output_file}"
    )
    logging.info(f"执行查找DML语句命令: {cmd}")
    try:
        # 使用 shell=True 以便支持重定向
        result = subprocess.run(cmd, shell=True, executable='/bin/bash', check=True)
        os.chmod(output_file, 0o644)  # 明确设为 rw-r--r--
        logging.info(f"命令执行成功, 结果已保存至 {output_file}")
        return True
    except subprocess.CalledProcessError as e:
        logging.error(f"命令执行失败,返回码: {e.returncode}")
        return False


def main():
    parser = argparse.ArgumentParser(description="本地离线查找DML")
    parser.add_argument('--host', default='localhost', help='数据库主机')
    parser.add_argument('--port', type=int, default=3306, help='数据库端口')
    parser.add_argument('--user', required=True, help='数据库用户名')
    parser.add_argument('--password', required=True, help='数据库密码')
    parser.add_argument('--database', required=True, help='数据库名称')
    parser.add_argument('--table', required=True, help='表名')
    parser.add_argument('--types', required=True, help='类型')
    parser.add_argument('--local-file', required=True, help='Binlog 文件名, 如 ./mysql-bin.000413')
    parser.add_argument('--start-time', required=True, help='开始时间, 格式 "YYYY-MM-DD HH:MM:SS"')
    parser.add_argument('--stop-time', required=True, help='结束时间, 格式 "YYYY-MM-DD HH:MM:SS"')

    args = parser.parse_args()

    # 1. 创建 bin2sql_local 目录
    dir_name = "bin2sql_local"
    dir_path = Path(dir_name)
    dir_path.mkdir(exist_ok=True)  # 如果目录已存在则不报错，否则创建

    # 2. 下载 bingo2sql(如果不存在)
    if not download_bingo2sql('https://t.infuq.com/dl/bingo2sql', f'./{dir_name}/bingo2sql'):
        sys.exit(1)

    # 3. 获取建表语句(离线场景需要使用该建表语句)
    if not get_create_table_sql(
        args.host, args.port, args.user, args.password,
        args.database, args.table, f'./{dir_name}/create_table.sql'
    ):
        sys.exit(1)

    # 4. 执行 bingo2sql
    if not run_bingo2sql(
        f'./{dir_name}/bingo2sql',
        args.database,
        f'./{dir_name}/create_table.sql',
        args.types,
        args.local_file,
        args.start_time,
        args.stop_time,
        f'./{dir_name}/dml_statement.sql'
    ):
        sys.exit(1)

    logging.info("所有步骤执行完成")


if __name__ == '__main__':
    main()



