#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
============================================================================
算子开发效率平台 - 后端服务
============================================================================

提供以下功能:
1. 环境部署 - 连接远程服务器、下载脚本、执行脚本、返回日志
2. 学习共享 - 管理学习分类和内容
3. 材料查询 - 管理查询分类和内容
4. 模块管理 - 管理平台功能模块

使用 Flask 框架,支持 RESTful API
"""

import os
import json
import time
import uuid
import threading
import logging
from datetime import datetime
from typing import Dict, List, Optional, Any
from dataclasses import dataclass, asdict
from flask import Flask, request, jsonify, Response, stream_with_context
from flask_cors import CORS

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

# Flask 应用
app = Flask(__name__)
CORS(app)

# 数据存储路径
DATA_DIR = os.path.join(os.path.dirname(__file__), 'data')
os.makedirs(DATA_DIR, exist_ok=True)

# ============================================================================
# 数据模型
# ============================================================================

@dataclass
class Module:
    """功能模块"""
    id: int
    name: str
    icon: str
    desc: str
    url: str
    enabled: bool = True

@dataclass
class LearningItem:
    """学习内容"""
    id: int
    title: str
    desc: str
    wiki_url: str

@dataclass
class LearningCategory:
    """学习分类"""
    id: int
    name: str
    icon: str
    items: List[LearningItem]

@dataclass
class QueryItem:
    """查询内容"""
    id: int
    title: str
    desc: str
    wiki_url: str

@dataclass
class QueryCategory:
    """查询分类"""
    id: int
    name: str
    icon: str
    items: List[QueryItem]

@dataclass
class DeploymentRecord:
    """部署记录"""
    id: str
    server: str
    port: int
    username: str
    version: str
    components: str
    success: bool
    time: str
    logs: List[Dict[str, str]]

@dataclass
class DeploymentTask:
    """部署任务"""
    id: str
    status: str  # pending, running, completed, failed, cancelled
    config: Dict[str, Any]
    logs: List[Dict[str, str]]
    start_time: Optional[str] = None
    end_time: Optional[str] = None

# ============================================================================
# 数据存储管理
# ============================================================================

class DataManager:
    """数据管理器"""

    def __init__(self):
        self.modules_file = os.path.join(DATA_DIR, 'modules.json')
        self.learning_file = os.path.join(DATA_DIR, 'learning.json')
        self.query_file = os.path.join(DATA_DIR, 'query.json')
        self.deployment_file = os.path.join(DATA_DIR, 'deployment.json')
        self.tasks: Dict[str, DeploymentTask] = {}

    def _load_json(self, filepath: str, default: Any = None) -> Any:
        """加载 JSON 文件"""
        if default is None:
            default = []
        if not os.path.exists(filepath):
            return default
        try:
            with open(filepath, 'r', encoding='utf-8') as f:
                return json.load(f)
        except Exception as e:
            logger.error(f"Failed to load {filepath}: {e}")
            return default

    def _save_json(self, filepath: str, data: Any) -> bool:
        """保存 JSON 文件"""
        try:
            with open(filepath, 'w', encoding='utf-8') as f:
                json.dump(data, f, ensure_ascii=False, indent=2)
            return True
        except Exception as e:
            logger.error(f"Failed to save {filepath}: {e}")
            return False

    # 模块管理
    def get_modules(self) -> List[Dict]:
        """获取所有模块"""
        return self._load_json(self.modules_file)

    def save_module(self, module: Dict) -> bool:
        """保存模块"""
        modules = self.get_modules()
        modules.append(module)
        return self._save_json(self.modules_file, modules)

    def update_module(self, module_id: int, data: Dict) -> bool:
        """更新模块"""
        modules = self.get_modules()
        for i, m in enumerate(modules):
            if m['id'] == module_id:
                modules[i] = {**m, **data}
                return self._save_json(self.modules_file, modules)
        return False

    def delete_module(self, module_id: int) -> bool:
        """删除模块"""
        modules = self.get_modules()
        modules = [m for m in modules if m['id'] != module_id]
        return self._save_json(self.modules_file, modules)

    # 学习管理
    def get_learning_categories(self) -> List[Dict]:
        """获取学习分类"""
        return self._load_json(self.learning_file)

    def save_learning_category(self, category: Dict) -> bool:
        """保存学习分类"""
        categories = self.get_learning_categories()
        categories.append(category)
        return self._save_json(self.learning_file, categories)

    def update_learning_category(self, category_id: int, data: Dict) -> bool:
        """更新学习分类"""
        categories = self.get_learning_categories()
        for i, c in enumerate(categories):
            if c['id'] == category_id:
                categories[i] = {**c, **data}
                return self._save_json(self.learning_file, categories)
        return False

    def delete_learning_category(self, category_id: int) -> bool:
        """删除学习分类"""
        categories = self.get_learning_categories()
        categories = [c for c in categories if c['id'] != category_id]
        return self._save_json(self.learning_file, categories)

    def add_learning_item(self, category_id: int, item: Dict) -> bool:
        """添加学习内容"""
        categories = self.get_learning_categories()
        for c in categories:
            if c['id'] == category_id:
                if 'items' not in c:
                    c['items'] = []
                c['items'].append(item)
                return self._save_json(self.learning_file, categories)
        return False

    def update_learning_item(self, category_id: int, item_id: int, data: Dict) -> bool:
        """更新学习内容"""
        categories = self.get_learning_categories()
        for c in categories:
            if c['id'] == category_id:
                if 'items' not in c:
                    return False
                for i, item in enumerate(c['items']):
                    if item['id'] == item_id:
                        c['items'][i] = {**item, **data}
                        return self._save_json(self.learning_file, categories)
        return False

    def delete_learning_item(self, category_id: int, item_id: int) -> bool:
        """删除学习内容"""
        categories = self.get_learning_categories()
        for c in categories:
            if c['id'] == category_id:
                if 'items' in c:
                    c['items'] = [item for item in c['items'] if item['id'] != item_id]
                    return self._save_json(self.learning_file, categories)
        return False

    # 查询管理
    def get_query_categories(self) -> List[Dict]:
        """获取查询分类"""
        return self._load_json(self.query_file)

    def save_query_category(self, category: Dict) -> bool:
        """保存查询分类"""
        categories = self.get_query_categories()
        categories.append(category)
        return self._save_json(self.query_file, categories)

    def update_query_category(self, category_id: int, data: Dict) -> bool:
        """更新查询分类"""
        categories = self.get_query_categories()
        for i, c in enumerate(categories):
            if c['id'] == category_id:
                categories[i] = {**c, **data}
                return self._save_json(self.query_file, categories)
        return False

    def delete_query_category(self, category_id: int) -> bool:
        """删除查询分类"""
        categories = self.get_query_categories()
        categories = [c for c in categories if c['id'] != category_id]
        return self._save_json(self.query_file, categories)

    def add_query_item(self, category_id: int, item: Dict) -> bool:
        """添加查询内容"""
        categories = self.get_query_categories()
        for c in categories:
            if c['id'] == category_id:
                if 'items' not in c:
                    c['items'] = []
                c['items'].append(item)
                return self._save_json(self.query_file, categories)
        return False

    def update_query_item(self, category_id: int, item_id: int, data: Dict) -> bool:
        """更新查询内容"""
        categories = self.get_query_categories()
        for c in categories:
            if c['id'] == category_id:
                if 'items' not in c:
                    return False
                for i, item in enumerate(c['items']):
                    if item['id'] == item_id:
                        c['items'][i] = {**item, **data}
                        return self._save_json(self.query_file, categories)
        return False

    def delete_query_item(self, category_id: int, item_id: int) -> bool:
        """删除查询内容"""
        categories = self.get_query_categories()
        for c in categories:
            if c['id'] == category_id:
                if 'items' in c:
                    c['items'] = [item for item in c['items'] if item['id'] != item_id]
                    return self._save_json(self.query_file, categories)
        return False

    # 部署管理
    def get_deployment_history(self) -> List[Dict]:
        """获取部署历史"""
        return self._load_json(self.deployment_file)

    def save_deployment_record(self, record: Dict) -> bool:
        """保存部署记录"""
        history = self.get_deployment_history()
        history.insert(0, record)
        # 只保留最近 50 条
        if len(history) > 50:
            history = history[:50]
        return self._save_json(self.deployment_file, history)

    def delete_deployment_record(self, record_id: str) -> bool:
        """删除部署记录"""
        history = self.get_deployment_history()
        history = [r for r in history if r.get('id') != record_id]
        return self._save_json(self.deployment_file, history)

    # 任务管理
    def create_task(self, config: Dict) -> str:
        """创建部署任务"""
        task_id = str(uuid.uuid4())
        task = DeploymentTask(
            id=task_id,
            status='pending',
            config=config,
            logs=[]
        )
        self.tasks[task_id] = task
        return task_id

    def get_task(self, task_id: str) -> Optional[DeploymentTask]:
        """获取任务"""
        return self.tasks.get(task_id)

    def update_task_status(self, task_id: str, status: str) -> bool:
        """更新任务状态"""
        if task_id in self.tasks:
            self.tasks[task_id].status = status
            if status == 'running':
                self.tasks[task_id].start_time = datetime.now().isoformat()
            elif status in ['completed', 'failed', 'cancelled']:
                self.tasks[task_id].end_time = datetime.now().isoformat()
            return True
        return False

    def add_task_log(self, task_id: str, level: str, content: str) -> bool:
        """添加任务日志"""
        if task_id in self.tasks:
            self.tasks[task_id].logs.append({
                'timestamp': datetime.now().strftime('%H:%M:%S'),
                'level': level,
                'content': content
            })
            return True
        return False

# 全局数据管理器
data_manager = DataManager()

# ============================================================================
# 部署执行器
# ============================================================================

class DeploymentExecutor:
    """部署执行器"""

    def __init__(self, data_manager: DataManager):
        self.data_manager = data_manager

    def execute_deployment(self, task_id: str):
        """执行部署"""
        task = self.data_manager.get_task(task_id)
        if not task:
            return

        config = task.config
        self.data_manager.update_task_status(task_id, 'running')
        self.data_manager.add_task_log(task_id, 'INFO', f'开始部署任务,任务ID: {task_id}')

        try:
            # 模拟部署流程
            self._simulate_deployment(task_id, config)
        except Exception as e:
            self.data_manager.add_task_log(task_id, 'ERROR', f'部署异常: {str(e)}')
            self.data_manager.update_task_status(task_id, 'failed')

    def _simulate_deployment(self, task_id: str, config: Dict):
        """模拟部署流程"""
        steps = [
            ('INFO', f'开始连接服务器 {config["server"]}:{config["port"]}...'),
            ('SUCCESS', f'服务器连接成功,用户: {config["username"]}'),
            ('INFO', '检查服务器环境...'),
            ('INFO', '系统版本: Ubuntu 22.04 LTS'),
            ('INFO', 'CPU: 8核, 内存: 16GB'),
            ('SUCCESS', '环境检查通过'),
            ('INFO', f'下载安装脚本 (版本: {config["version"]})...'),
            ('INFO', '下载进度: [=====>    ] 50%'),
            ('SUCCESS', '脚本下载完成,大小: 2.3MB'),
            ('INFO', '开始执行安装脚本...'),
            ('INFO', f'安装组件: {config["components"]}'),
            ('INFO', '正在安装基础组件...'),
            ('SUCCESS', '基础组件安装完成'),
        ]

        # 根据组件添加额外步骤
        if 'AI' in config['components']:
            steps.append(('INFO', '正在安装 AI 组件...'))
            steps.append(('SUCCESS', 'AI 组件安装完成'))

        if '监控' in config['components']:
            steps.append(('INFO', '正在安装监控组件...'))
            steps.append(('SUCCESS', '监控组件安装完成'))

        steps.extend([
            ('INFO', '配置服务...'),
            ('SUCCESS', '服务配置完成'),
            ('INFO', '启动服务...'),
            ('SUCCESS', '服务启动成功'),
            ('INFO', '运行健康检查...'),
            ('SUCCESS', '健康检查通过'),
            ('SUCCESS', '部署完成!服务已就绪'),
        ])

        # 执行步骤
        for level, content in steps:
            if self.data_manager.get_task(task_id).status == 'cancelled':
                self.data_manager.add_task_log(task_id, 'WARNING', '部署已取消')
                return

            self.data_manager.add_task_log(task_id, level, content)
            time.sleep(0.3 + 0.5 * (hash(content) % 10) / 10)

        # 完成部署
        self.data_manager.update_task_status(task_id, 'completed')

        # 保存到历史记录
        task = self.data_manager.get_task(task_id)
        record = {
            'id': task_id,
            'server': config['server'],
            'port': config['port'],
            'username': config['username'],
            'version': config['version'],
            'components': config['components'],
            'success': True,
            'time': datetime.now().isoformat(),
            'logs': task.logs
        }
        self.data_manager.save_deployment_record(record)

# 全局部署执行器
executor = DeploymentExecutor(data_manager)

# ============================================================================
# API 路由
# ============================================================================

@app.route('/api/health', methods=['GET'])
def health_check():
    """健康检查"""
    return jsonify({'status': 'ok', 'timestamp': datetime.now().isoformat()})

# ==================== 模块管理 ====================

@app.route('/api/modules', methods=['GET'])
def get_modules():
    """获取所有模块"""
    return jsonify({'modules': data_manager.get_modules()})

@app.route('/api/modules', methods=['POST'])
def create_module():
    """创建模块"""
    data = request.json
    module = {
        'id': int(time.time() * 1000),
        'name': data.get('name'),
        'icon': data.get('icon', '📦'),
        'desc': data.get('desc'),
        'url': data.get('url'),
        'enabled': data.get('enabled', True)
    }
    data_manager.save_module(module)
    return jsonify({'success': True, 'module': module})

@app.route('/api/modules/<int:module_id>', methods=['PUT'])
def update_module(module_id):
    """更新模块"""
    data = request.json
    success = data_manager.update_module(module_id, data)
    return jsonify({'success': success})

@app.route('/api/modules/<int:module_id>', methods=['DELETE'])
def delete_module(module_id):
    """删除模块"""
    success = data_manager.delete_module(module_id)
    return jsonify({'success': success})

# ==================== 学习共享 ====================

@app.route('/api/learning/categories', methods=['GET'])
def get_learning_categories():
    """获取学习分类"""
    return jsonify({'categories': data_manager.get_learning_categories()})

@app.route('/api/learning/categories', methods=['POST'])
def create_learning_category():
    """创建学习分类"""
    data = request.json
    category = {
        'id': int(time.time() * 1000),
        'name': data.get('name'),
        'icon': data.get('icon', '📚'),
        'items': []
    }
    data_manager.save_learning_category(category)
    return jsonify({'success': True, 'category': category})

@app.route('/api/learning/categories/<int:category_id>', methods=['PUT'])
def update_learning_category(category_id):
    """更新学习分类"""
    data = request.json
    success = data_manager.update_learning_category(category_id, data)
    return jsonify({'success': success})

@app.route('/api/learning/categories/<int:category_id>', methods=['DELETE'])
def delete_learning_category(category_id):
    """删除学习分类"""
    success = data_manager.delete_learning_category(category_id)
    return jsonify({'success': success})

@app.route('/api/learning/categories/<int:category_id>/items', methods=['GET'])
def get_learning_items(category_id):
    """获取分类下的内容"""
    categories = data_manager.get_learning_categories()
    for c in categories:
        if c['id'] == category_id:
            return jsonify({'items': c.get('items', [])})
    return jsonify({'items': []})

@app.route('/api/learning/categories/<int:category_id>/items', methods=['POST'])
def create_learning_item(category_id):
    """创建学习内容"""
    data = request.json
    item = {
        'id': int(time.time() * 1000),
        'title': data.get('title'),
        'desc': data.get('desc'),
        'wiki_url': data.get('wiki_url')
    }
    success = data_manager.add_learning_item(category_id, item)
    return jsonify({'success': success, 'item': item})

@app.route('/api/learning/categories/<int:category_id>/items/<int:item_id>', methods=['PUT'])
def update_learning_item(category_id, item_id):
    """更新学习内容"""
    data = request.json
    success = data_manager.update_learning_item(category_id, item_id, data)
    return jsonify({'success': success})

@app.route('/api/learning/categories/<int:category_id>/items/<int:item_id>', methods=['DELETE'])
def delete_learning_item(category_id, item_id):
    """删除学习内容"""
    success = data_manager.delete_learning_item(category_id, item_id)
    return jsonify({'success': success})

@app.route('/api/learning/search', methods=['GET'])
def search_learning():
    """搜索学习内容"""
    query = request.args.get('q', '').lower()
    if not query:
        return jsonify({'results': []})

    categories = data_manager.get_learning_categories()
    results = []
    for c in categories:
        for item in c.get('items', []):
            if query in item.get('title', '').lower() or query in item.get('desc', '').lower():
                results.append({
                    'category': c['name'],
                    'item': item
                })
    return jsonify({'results': results})

# ==================== 查询管理 ====================

@app.route('/api/query/categories', methods=['GET'])
def get_query_categories():
    """获取查询分类"""
    return jsonify({'categories': data_manager.get_query_categories()})

@app.route('/api/query/categories', methods=['POST'])
def create_query_category():
    """创建查询分类"""
    data = request.json
    category = {
        'id': int(time.time() * 1000),
        'name': data.get('name'),
        'icon': data.get('icon', '📦'),
        'items': []
    }
    data_manager.save_query_category(category)
    return jsonify({'success': True, 'category': category})

@app.route('/api/query/categories/<int:category_id>', methods=['PUT'])
def update_query_category(category_id):
    """更新查询分类"""
    data = request.json
    success = data_manager.update_query_category(category_id, data)
    return jsonify({'success': success})

@app.route('/api/query/categories/<int:category_id>', methods=['DELETE'])
def delete_query_category(category_id):
    """删除查询分类"""
    success = data_manager.delete_query_category(category_id)
    return jsonify({'success': success})

@app.route('/api/query/categories/<int:category_id>/items', methods=['GET'])
def get_query_items(category_id):
    """获取分类下的内容"""
    categories = data_manager.get_query_categories()
    for c in categories:
        if c['id'] == category_id:
            return jsonify({'items': c.get('items', [])})
    return jsonify({'items': []})

@app.route('/api/query/categories/<int:category_id>/items', methods=['POST'])
def create_query_item(category_id):
    """创建查询内容"""
    data = request.json
    item = {
        'id': int(time.time() * 1000),
        'title': data.get('title'),
        'desc': data.get('desc'),
        'wiki_url': data.get('wiki_url')
    }
    success = data_manager.add_query_item(category_id, item)
    return jsonify({'success': success, 'item': item})

@app.route('/api/query/categories/<int:category_id>/items/<int:item_id>', methods=['PUT'])
def update_query_item(category_id, item_id):
    """更新查询内容"""
    data = request.json
    success = data_manager.update_query_item(category_id, item_id, data)
    return jsonify({'success': success})

@app.route('/api/query/categories/<int:category_id>/items/<int:item_id>', methods=['DELETE'])
def delete_query_item(category_id, item_id):
    """删除查询内容"""
    success = data_manager.delete_query_item(category_id, item_id)
    return jsonify({'success': success})

@app.route('/api/query/search', methods=['GET'])
def search_query():
    """搜索查询内容"""
    query = request.args.get('q', '').lower()
    if not query:
        return jsonify({'results': []})

    categories = data_manager.get_query_categories()
    results = []
    for c in categories:
        for item in c.get('items', []):
            if query in item.get('title', '').lower() or query in item.get('desc', '').lower():
                results.append({
                    'category': c['name'],
                    'item': item
                })
    return jsonify({'results': results})

# ==================== 部署管理 ====================

@app.route('/api/deployment/deploy', methods=['POST'])
def deploy():
    """开始部署"""
    config = request.json
    task_id = data_manager.create_task(config)

    # 在后台线程中执行部署
    thread = threading.Thread(target=executor.execute_deployment, args=(task_id,))
    thread.daemon = True
    thread.start()

    return jsonify({'success': True, 'task_id': task_id})

@app.route('/api/deployment/status/<task_id>', methods=['GET'])
def get_deployment_status(task_id):
    """获取部署状态"""
    task = data_manager.get_task(task_id)
    if not task:
        return jsonify({'error': 'Task not found'}), 404
    return jsonify({
        'status': task.status,
        'start_time': task.start_time,
        'end_time': task.end_time
    })

@app.route('/api/deployment/logs/<task_id>', methods=['GET'])
def get_deployment_logs(task_id):
    """获取部署日志"""
    task = data_manager.get_task(task_id)
    if not task:
        return jsonify({'error': 'Task not found'}), 404

    offset = int(request.args.get('offset', 0))
    logs = task.logs[offset:]
    return jsonify({'logs': logs, 'total': len(task.logs)})

@app.route('/api/deployment/cancel/<task_id>', methods=['POST'])
def cancel_deployment(task_id):
    """取消部署"""
    task = data_manager.get_task(task_id)
    if not task:
        return jsonify({'error': 'Task not found'}), 404

    if task.status in ['pending', 'running']:
        data_manager.update_task_status(task_id, 'cancelled')
        return jsonify({'success': True})
    return jsonify({'error': 'Cannot cancel completed task'}), 400

@app.route('/api/deployment/history', methods=['GET'])
def get_deployment_history():
    """获取部署历史"""
    history = data_manager.get_deployment_history()
    return jsonify({'history': history})

@app.route('/api/deployment/history/<record_id>', methods=['DELETE'])
def delete_deployment_history(record_id):
    """删除部署记录"""
    success = data_manager.delete_deployment_record(record_id)
    return jsonify({'success': success})

@app.route('/api/deployment/versions', methods=['GET'])
def get_deployment_versions():
    """获取可用版本"""
    versions = [
        {'id': 'v2.0', 'name': 'v2.0 - 最新稳定版', 'stable': True},
        {'id': 'v1.0', 'name': 'v1.0 - LTS 版本', 'stable': True},
        {'id': 'v3.0', 'name': 'v3.0 - 测试版', 'stable': False},
        {'id': 'dev', 'name': 'dev - 开发版', 'stable': False}
    ]
    return jsonify({'versions': versions})

@app.route('/api/deployment/components', methods=['GET'])
def get_deployment_components():
    """获取可用组件"""
    components = [
        {'id': 'base', 'name': '基础组件', 'required': True},
        {'id': 'ai', 'name': 'AI 组件', 'required': False},
        {'id': 'monitor', 'name': '监控组件', 'required': False},
        {'id': 'log', 'name': '日志组件', 'required': False},
        {'id': 'cache', 'name': '缓存组件', 'required': False},
        {'id': 'ml', 'name': '机器学习组件', 'required': False}
    ]
    return jsonify({'components': components})

# ============================================================================
# 错误处理
# ============================================================================

@app.errorhandler(404)
def not_found(error):
    return jsonify({'error': 'Not found'}), 404

@app.errorhandler(500)
def internal_error(error):
    return jsonify({'error': 'Internal server error'}), 500

# ============================================================================
# 主函数
# ============================================================================

if __name__ == '__main__':
    logger.info("Starting Operator Efficiency Platform Server...")
    logger.info(f"Data directory: {DATA_DIR}")

    # 启动 Flask 服务器
    app.run(
        host='0.0.0.0',
        port=5000,
        debug=True,
        threaded=True
    )