#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
通过Web API备份数据库
无需SSH权限，通过应用程序接口备份数据
"""

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

from auth_system import app
from flask import jsonify, request, send_file
import pymysql
import json
from datetime import datetime
import tempfile
import zipfile

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

def backup_database():
    """备份数据库到临时文件"""
    try:
        connection = pymysql.connect(**DB_CONFIG)
        cursor = connection.cursor()
        
        # 创建临时文件
        temp_file = tempfile.NamedTemporaryFile(mode='w', suffix='.sql', delete=False, encoding='utf-8')
        temp_file_path = temp_file.name
        
        # 获取所有表名
        cursor.execute("SHOW TABLES")
        tables = [table[0] for table in cursor.fetchall()]
        
        print(f"📋 开始备份 {len(tables)} 个表...")
        
        # 写入备份头部信息
        temp_file.write(f"-- 患者画像回访话术系统数据库备份\n")
        temp_file.write(f"-- 备份时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
        temp_file.write(f"-- 数据库: {DB_CONFIG['database']}\n\n")
        
        # 备份每个表
        for table_name in tables:
            print(f"  📊 备份表: {table_name}")
            
            # 获取表结构
            cursor.execute(f"SHOW CREATE TABLE `{table_name}`")
            create_table_sql = cursor.fetchone()[1]
            temp_file.write(f"\n-- 表结构: {table_name}\n")
            temp_file.write(f"DROP TABLE IF EXISTS `{table_name}`;\n")
            temp_file.write(f"{create_table_sql};\n\n")
            
            # 获取表数据
            cursor.execute(f"SELECT COUNT(*) FROM `{table_name}`")
            row_count = cursor.fetchone()[0]
            
            if row_count > 0:
                temp_file.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}'")
                        
                        temp_file.write(f"INSERT INTO `{table_name}` VALUES ({', '.join(values)});\n")
                    
                    offset += batch_size
                    print(f"    ✅ 已备份 {min(offset, row_count)}/{row_count} 行")
                
                temp_file.write("\n")
        
        temp_file.close()
        connection.close()
        
        print(f"✅ 数据库备份完成: {temp_file_path}")
        return temp_file_path
        
    except Exception as e:
        print(f"❌ 数据库备份失败: {e}")
        if 'connection' in locals():
            connection.close()
        return None

def create_backup_zip(backup_file_path):
    """创建备份压缩包"""
    try:
        # 创建临时压缩文件
        zip_file = tempfile.NamedTemporaryFile(mode='wb', suffix='.zip', delete=False)
        zip_file_path = zip_file.name
        zip_file.close()
        
        # 压缩备份文件
        with zipfile.ZipFile(zip_file_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
            # 添加备份文件
            backup_filename = os.path.basename(backup_file_path)
            zipf.write(backup_file_path, backup_filename)
            
            # 添加备份信息
            info = {
                'backup_time': datetime.now().isoformat(),
                'database': DB_CONFIG['database'],
                'tables_count': len([f for f in os.listdir('.') if f.endswith('.sql')]),
                'backup_size': os.path.getsize(backup_file_path)
            }
            
            zipf.writestr('backup_info.json', json.dumps(info, ensure_ascii=False, indent=2))
        
        print(f"✅ 备份压缩包创建完成: {zip_file_path}")
        return zip_file_path
        
    except Exception as e:
        print(f"❌ 创建压缩包失败: {e}")
        return None

# 添加备份API路由到Flask应用
@app.route('/api/backup/database', methods=['POST'])
def api_backup_database():
    """API接口：备份数据库"""
    try:
        print("🚀 收到数据库备份请求...")
        
        # 执行备份
        backup_file_path = backup_database()
        if not backup_file_path:
            return jsonify({'error': '数据库备份失败'}), 500
        
        # 创建压缩包
        zip_file_path = create_backup_zip(backup_file_path)
        if not zip_file_path:
            return jsonify({'error': '创建压缩包失败'}), 500
        
        # 清理临时文件
        os.unlink(backup_file_path)
        
        # 返回下载链接
        backup_filename = f"database_backup_{datetime.now().strftime('%Y%m%d_%H%M%S')}.zip"
        
        return jsonify({
            'success': True,
            'message': '数据库备份成功',
            'backup_file': backup_filename,
            'download_url': f'/api/backup/download/{backup_filename}',
            'backup_time': datetime.now().isoformat()
        })
        
    except Exception as e:
        print(f"❌ API备份失败: {e}")
        return jsonify({'error': f'备份失败: {str(e)}'}), 500

@app.route('/api/backup/download/<filename>')
def api_download_backup(filename):
    """API接口：下载备份文件"""
    try:
        # 查找最新的备份文件
        backup_dir = tempfile.gettempdir()
        backup_files = [f for f in os.listdir(backup_dir) if f.endswith('.zip') and 'database_backup' in f]
        
        if not backup_files:
            return jsonify({'error': '未找到备份文件'}), 404
        
        # 使用最新的备份文件
        latest_backup = max(backup_files, key=lambda f: os.path.getctime(os.path.join(backup_dir, f)))
        backup_path = os.path.join(backup_dir, latest_backup)
        
        return send_file(
            backup_path,
            as_attachment=True,
            download_name=filename,
            mimetype='application/zip'
        )
        
    except Exception as e:
        print(f"❌ 下载备份文件失败: {e}")
        return jsonify({'error': f'下载失败: {str(e)}'}), 500

@app.route('/api/backup/status')
def api_backup_status():
    """API接口：获取备份状态"""
    try:
        backup_dir = tempfile.gettempdir()
        backup_files = [f for f in os.listdir(backup_dir) if f.endswith('.zip') and 'database_backup' in f]
        
        backups = []
        for backup_file in backup_files:
            backup_path = os.path.join(backup_dir, backup_file)
            backup_info = {
                'filename': backup_file,
                'size': os.path.getsize(backup_path),
                'created_time': datetime.fromtimestamp(os.path.getctime(backup_path)).isoformat(),
                'download_url': f'/api/backup/download/{backup_file}'
            }
            backups.append(backup_info)
        
        # 按创建时间排序
        backups.sort(key=lambda x: x['created_time'], reverse=True)
        
        return jsonify({
            'success': True,
            'backups': backups,
            'total_count': len(backups)
        })
        
    except Exception as e:
        print(f"❌ 获取备份状态失败: {e}")
        return jsonify({'error': f'获取状态失败: {str(e)}'}), 500

if __name__ == "__main__":
    print("🔧 数据库备份API已添加到Flask应用")
    print("📋 可用的API接口:")
    print("  POST /api/backup/database    - 创建数据库备份")
    print("  GET  /api/backup/status      - 获取备份状态")
    print("  GET  /api/backup/download/*  - 下载备份文件") 