#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
简单的数据库备份工具
无需特殊权限，通过应用程序直接备份
"""

import os
import sys
import pymysql
import json
from datetime import datetime
import zipfile

# 数据库配置
DB_CONFIG = {
    'host': 'localhost',
    'port': 3306,
    'user': 'callback_user',
    'password': 'dev_password_123',
    'database': 'callback_system',
    'charset': 'utf8mb4'
}

def create_backup_directory():
    """创建备份目录"""
    backup_dir = "database_backups"
    if not os.path.exists(backup_dir):
        os.makedirs(backup_dir)
        print(f"✅ 创建备份目录: {backup_dir}")
    return backup_dir

def backup_database(backup_dir):
    """备份数据库"""
    try:
        print("🔌 连接数据库...")
        connection = pymysql.connect(**DB_CONFIG)
        cursor = connection.cursor()
        
        # 生成备份文件名
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        backup_file = os.path.join(backup_dir, f"production_backup_{timestamp}.sql")
        
        print(f"📋 开始备份数据库: {DB_CONFIG['database']}")
        
        # 获取所有表名
        cursor.execute("SHOW TABLES")
        tables = [table[0] for table in cursor.fetchall()]
        print(f"📊 发现 {len(tables)} 个表")
        
        with open(backup_file, 'w', encoding='utf-8') as f:
            # 写入备份头部信息
            f.write(f"-- 患者画像回访话术系统数据库备份\n")
            f.write(f"-- 备份时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
            f.write(f"-- 数据库: {DB_CONFIG['database']}\n")
            f.write(f"-- 表数量: {len(tables)}\n\n")
            
            # 备份每个表
            for i, table_name in enumerate(tables, 1):
                print(f"  [{i}/{len(tables)}] 备份表: {table_name}")
                
                # 获取表结构
                cursor.execute(f"SHOW CREATE TABLE `{table_name}`")
                create_table_sql = cursor.fetchone()[1]
                f.write(f"\n-- 表结构: {table_name}\n")
                f.write(f"DROP TABLE IF EXISTS `{table_name}`;\n")
                f.write(f"{create_table_sql};\n\n")
                
                # 获取表数据
                cursor.execute(f"SELECT COUNT(*) FROM `{table_name}`")
                row_count = cursor.fetchone()[0]
                
                if row_count > 0:
                    f.write(f"-- 表数据: {table_name} ({row_count} 行)\n")
                    
                    # 分批获取数据避免内存问题
                    batch_size = 1000
                    offset = 0
                    
                    while offset < row_count:
                        cursor.execute(f"SELECT * FROM `{table_name}` LIMIT {batch_size} OFFSET {offset}")
                        rows = cursor.fetchall()
                        
                        for row in rows:
                            # 构建INSERT语句
                            values = []
                            for value in row:
                                if value is None:
                                    values.append('NULL')
                                elif isinstance(value, (int, float)):
                                    values.append(str(value))
                                else:
                                    # 转义字符串
                                    escaped_value = str(value).replace("'", "''").replace("\\", "\\\\")
                                    values.append(f"'{escaped_value}'")
                            
                            f.write(f"INSERT INTO `{table_name}` VALUES ({', '.join(values)});\n")
                        
                        offset += batch_size
                        print(f"    ✅ 已备份 {min(offset, row_count)}/{row_count} 行")
                    
                    f.write("\n")
                else:
                    print(f"    ⚠️  表 {table_name} 无数据")
        
        connection.close()
        
        # 获取备份文件大小
        file_size = os.path.getsize(backup_file)
        size_mb = file_size / (1024 * 1024)
        
        print(f"✅ 数据库备份完成!")
        print(f"📁 备份文件: {backup_file}")
        print(f"📏 文件大小: {size_mb:.2f} MB")
        
        return backup_file
        
    except Exception as e:
        print(f"❌ 数据库备份失败: {e}")
        if 'connection' in locals():
            connection.close()
        return None

def create_backup_zip(backup_file, backup_dir):
    """创建备份压缩包"""
    try:
        # 生成压缩包文件名
        backup_name = os.path.basename(backup_file)
        zip_name = backup_name.replace('.sql', '.zip')
        zip_path = os.path.join(backup_dir, zip_name)
        
        print(f"📦 创建压缩包: {zip_name}")
        
        with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
            # 添加备份文件
            zipf.write(backup_file, backup_name)
            
            # 添加备份信息
            info = {
                'backup_time': datetime.now().isoformat(),
                'database': DB_CONFIG['database'],
                'backup_file': backup_name,
                'backup_size': os.path.getsize(backup_file),
                'compressed_size': os.path.getsize(zip_path)
            }
            
            zipf.writestr('backup_info.json', json.dumps(info, ensure_ascii=False, indent=2))
        
        # 获取压缩包大小
        zip_size = os.path.getsize(zip_path)
        zip_size_mb = zip_size / (1024 * 1024)
        
        print(f"✅ 压缩包创建完成!")
        print(f"📁 压缩包: {zip_path}")
        print(f"📏 压缩后大小: {zip_size_mb:.2f} MB")
        
        return zip_path
        
    except Exception as e:
        print(f"❌ 创建压缩包失败: {e}")
        return None

def cleanup_old_backups(backup_dir, keep_days=7):
    """清理旧备份文件"""
    try:
        print(f"🧹 清理 {keep_days} 天前的旧备份文件...")
        
        current_time = datetime.now()
        deleted_count = 0
        
        for filename in os.listdir(backup_dir):
            file_path = os.path.join(backup_dir, filename)
            
            # 检查文件修改时间
            file_time = datetime.fromtimestamp(os.path.getmtime(file_path))
            days_old = (current_time - file_time).days
            
            if days_old > keep_days:
                os.remove(file_path)
                print(f"  🗑️  删除旧文件: {filename}")
                deleted_count += 1
        
        if deleted_count > 0:
            print(f"✅ 清理完成，删除了 {deleted_count} 个旧文件")
        else:
            print("✅ 无需清理，所有备份文件都是最新的")
            
    except Exception as e:
        print(f"⚠️  清理旧备份失败: {e}")

def show_backup_list(backup_dir):
    """显示备份文件列表"""
    try:
        print(f"\n📋 备份文件列表 ({backup_dir}):")
        print("-" * 80)
        
        files = []
        for filename in os.listdir(backup_dir):
            if filename.endswith(('.sql', '.zip')):
                file_path = os.path.join(backup_dir, filename)
                file_size = os.path.getsize(file_path)
                file_time = datetime.fromtimestamp(os.path.getmtime(file_path))
                files.append((filename, file_size, file_time))
        
        if not files:
            print("暂无备份文件")
            return
        
        # 按时间排序
        files.sort(key=lambda x: x[2], reverse=True)
        
        for filename, file_size, file_time in files:
            size_mb = file_size / (1024 * 1024)
            time_str = file_time.strftime("%Y-%m-%d %H:%M:%S")
            file_type = "📦" if filename.endswith('.zip') else "🗄️"
            
            print(f"{file_type} {filename}")
            print(f"    📅 创建时间: {time_str}")
            print(f"    📏 文件大小: {size_mb:.2f} MB")
            print()
            
    except Exception as e:
        print(f"❌ 显示备份列表失败: {e}")

def main():
    """主函数"""
    print("🚀 患者画像回访话术系统 - 数据库备份工具")
    print("=" * 60)
    
    try:
        # 创建备份目录
        backup_dir = create_backup_directory()
        
        # 备份数据库
        backup_file = backup_database(backup_dir)
        if not backup_file:
            print("❌ 备份失败，程序退出")
            return
        
        # 创建压缩包
        zip_file = create_backup_zip(backup_file, backup_dir)
        if zip_file:
            # 删除原始SQL文件（保留压缩包）
            os.remove(backup_file)
            print(f"🗑️  已删除原始SQL文件，保留压缩包")
        
        # 清理旧备份
        cleanup_old_backups(backup_dir)
        
        # 显示备份列表
        show_backup_list(backup_dir)
        
        print("\n🎉 备份流程完成!")
        print(f"💡 提示: 备份文件保存在 {backup_dir} 目录中")
        print(f"💡 提示: 建议将备份文件复制到安全位置保存")
        
    except KeyboardInterrupt:
        print("\n\n⚠️  用户中断操作")
    except Exception as e:
        print(f"\n❌ 备份过程出错: {e}")

if __name__ == "__main__":
    main() 