# -*- coding: utf-8 -*-
import os
from flask import Flask, g, jsonify
from flask_session import Session
import markdown
from .routes import register_all_blueprints
from config import Config

def create_app():
    # 根据数据库类型决定是否使用 instance 目录
    use_instance = Config.DATABASE_TYPE == 'sqlite'
    app = Flask(__name__, instance_relative_config=use_instance)
    
    # 配置
    app.config.from_object(Config)
    app.config.from_mapping(
        SECRET_KEY='dev',
        TEMPLATES_AUTO_RELOAD=True,  # 自动重载模板文件（开发模式）
    )
    
    # 创建实例目录（仅SQLite模式需要）
    if use_instance:
        try:
            os.makedirs(app.instance_path, exist_ok=True)
            import logging
            logger = logging.getLogger(__name__)
            logger.info(f"已创建实例目录: {app.instance_path}")
        except OSError as ose:
            import logging
            logger = logging.getLogger(__name__)
            logger.error(f"创建应用实例目录出错: {str(ose)}")
        except Exception as e:
            import logging
            logger = logging.getLogger(__name__)
            logger.error(f"创建应用实例目录出错: {str(e)}")
    
    # 初始化数据库
    try:
        from app.models.database import init_db
        db = init_db(app)

        # 检查数据库连接
        try:
            import logging
            logger = logging.getLogger(__name__)

            if Config.DATABASE_TYPE == 'postgresql':
                logger.info(f"使用 PostgreSQL 数据库: {Config.POSTGRES_DB}")
                logger.info(f"连接地址: {Config.POSTGRES_HOST}:{Config.POSTGRES_PORT}")
            else:
                db_path = os.path.join(app.instance_path, Config.SQLITE_DB_NAME)
                if not os.path.exists(db_path):
                    logger.warning(f"SQLite 数据库文件不存在: {db_path}")
                    logger.warning("请运行 python3 scripts/init_db.py 初始化数据库")
                else:
                    logger.info(f"使用 SQLite 数据库: {db_path}")
        except Exception as e:
            import logging
            logger = logging.getLogger(__name__)
            logger.error(f"检查数据库连接出错: {str(e)}")
    except Exception as e:
        print(f"初始化数据库出错: {str(e)}")
        print("将使用JSON加载器")
        import traceback
        traceback.print_exc()
    
    # 初始化会话
    Session(app)

    # 初始化Session自动清理器
    try:
        from app.services.storage import SessionCleaner
        session_dir = app.config.get('SESSION_FILE_DIR')
        session_lifetime = app.config.get('PERMANENT_SESSION_LIFETIME', 3600)
        
        if session_dir:
            session_cleaner = SessionCleaner(
                session_dir=session_dir,
                session_lifetime=session_lifetime,
                cleanup_interval=3600  # 每小时清理一次
            )
            session_cleaner.start()
            
            # 应用启动时立即清理一次
            with app.app_context():
                deleted_count = session_cleaner.cleanup_now()
                if deleted_count > 0:
                    import logging
                    logger = logging.getLogger(__name__)
                    logger.info(f"启动时清理了 {deleted_count} 个过期Session文件")
    except Exception as e:
        import logging
        logger = logging.getLogger(__name__)
        logger.warning(f"初始化Session清理器失败: {e}")
    
    # 添加时间格式化过滤器
    @app.template_filter('datetime')
    def datetime_filter(dt, format_str='%Y-%m-%d %H:%M:%S'):
        """格式化日期时间为北京时间"""
        if not dt:
            return "未知时间"
        
        from app.utils.time_utils import TimeUtils
        return TimeUtils.format_datetime(dt, format_str)
    
    @app.template_filter('relative_time')
    def relative_time_filter(dt):
        """格式化相对时间"""
        if not dt:
            return "未知时间"
        
        from app.utils.time_utils import TimeUtils
        return TimeUtils.format_relative_time(dt)
    
    @app.template_filter('beijing_time')
    def beijing_time_filter(dt, format_str='%Y-%m-%d %H:%M:%S'):
        """将UTC时间转换为北京时间并格式化"""
        if not dt:
            return "未知时间"
        
        from app.utils.time_utils import TimeUtils
        beijing_time = TimeUtils.utc_to_beijing(dt)
        return TimeUtils.format_datetime(beijing_time, format_str)
    
    @app.template_filter('strftime')
    def strftime_filter(dt, format_str='%Y-%m-%d %H:%M:%S'):
        """格式化datetime对象为字符串"""
        if not dt:
            return "未知时间"
        
        try:
            return dt.strftime(format_str)
        except (AttributeError, ValueError):
            return "时间格式错误"
    
    # 添加markdown过滤器
    @app.template_filter('markdown')
    def render_markdown(text):
        if not text:
            return ""

        try:
            # 先检查和清理可能存在的markdown标记
            import re

            # 处理嵌套的markdown代码块
            if '```markdown' in text:
                # 提取所有markdown代码块的内容
                markdown_blocks = re.findall(r'```markdown\s*\n(.*?)\n```', text, re.DOTALL)
                if markdown_blocks:
                    # 如果找到markdown代码块，使用提取的内容
                    text = '\n\n'.join(markdown_blocks)
                else:
                    # 如果正则表达式没有匹配，尝试简单的行分割方法
                    lines = text.strip().split('\n')
                    start_idx = -1
                    end_idx = -1
                    for i, line in enumerate(lines):
                        if line.strip() == '```markdown':
                            start_idx = i + 1
                        elif line.strip() == '```' and start_idx != -1:
                            end_idx = i
                            break
                    if start_idx != -1 and end_idx != -1:
                        text = '\n'.join(lines[start_idx:end_idx])

            # 移除最外层可能存在的markdown代码块标记（保留原有逻辑作为备用）
            text = re.sub(r'^```markdown\s*', '', text)
            text = re.sub(r'\s*```$', '', text)

            # 使用更多的扩展来增强Markdown解析能力
            result = markdown.markdown(
                text,
                extensions=[
                    'fenced_code',           # 支持围栏式代码块
                    'codehilite',            # 代码高亮
                    'tables',                # 表格支持
                    'nl2br',                 # 换行转为<br>
                    'sane_lists',            # 更智能的列表处理
                    'attr_list'              # 属性列表
                ],
                extension_configs={
                    'codehilite': {
                        'css_class': 'highlight',
                        'use_pygments': True,
                        'noclasses': True
                    }
                }
            )

            return result

        except Exception as e:
            print(f"Markdown渲染错误: {str(e)}")
            # 如果渲染失败，返回原始文本的HTML转义版本
            from html import escape
            return f'<pre>{escape(text)}</pre>'
    
    # 添加basename过滤器
    @app.template_filter('basename')
    def basename_filter(path):
        """提取文件路径的基本名称"""
        if not path:
            return ""
        import os
        return os.path.basename(path)
    
    # 添加图标类名过滤器
    @app.template_filter('icon_class')
    def icon_class_filter(icon_name, default='fas'):
        """
        根据图标名称返回完整的 Font Awesome 图标类名
        如果输入已经是完整的类名（如 'fab fa-python'），直接返回
        如果只是图标名称（如 'python'），根据图标数据自动判断前缀
        """
        if not icon_name:
            return f"{default} fa-folder"  # 默认图标
        
        icon_name = str(icon_name).strip()
        
        # 如果已经是完整的类名（包含空格或 fa- 前缀），直接返回
        if ' ' in icon_name or icon_name.startswith('fa-') or icon_name.startswith('fab ') or \
           icon_name.startswith('fas ') or icon_name.startswith('far ') or \
           icon_name.startswith('fal ') or icon_name.startswith('fad '):
            return icon_name
        
        # 品牌图标列表（需要 fab 前缀）
        brand_icons = {
            'github', 'gitlab', 'docker', 'python', 'java', 'js', 'node-js', 'php',
            'linux', 'windows', 'apple', 'android', 'react', 'vuejs', 'angular',
            'html5', 'css3-alt', 'bootstrap', 'npm', 'git-alt', 'aws', 'google',
            'microsoft', 'slack', 'discord', 'telegram', 'weixin', 'qq', 'weibo', 'alipay'
        }
        
        # 根据图标名称判断前缀
        if icon_name in brand_icons:
            return f"fab fa-{icon_name}"
        else:
            # 默认使用 fas 前缀
            return f"{default} fa-{icon_name}"
    
    # 用户加载中间件
    @app.before_request
    def load_logged_in_user():
        """在每个请求前加载当前用户"""
        from app.services.auth import AuthService
        g.user = AuthService.get_current_user()

    # 添加模板上下文处理器
    @app.context_processor
    def inject_system_config():
        """向所有模板注入系统配置"""
        return {}

    # 注册所有蓝图
    from app.routes import register_all_blueprints
    register_all_blueprints(app)
    
    # 注册认证蓝图
    from app.routes.auth import bp as auth_bp
    app.register_blueprint(auth_bp)
    
    # 注册全局异常处理器
    from app.core.exceptions import (
        CTFError, ValidationError, NotFoundError, PermissionDeniedError,
        AuthenticationError, AIServiceError, GenerationError, DeploymentError,
        DatabaseError, ConfigurationError
    )
    import logging
    
    logger = logging.getLogger(__name__)
    
    @app.errorhandler(CTFError)
    def handle_ctf_error(error: CTFError):
        """处理 CTF 系统自定义异常"""
        logger.warning(f"CTF Error [{error.code}]: {error.message}", extra=error.details)
        return jsonify(error.to_dict()), error.code
    
    @app.errorhandler(404)
    def handle_not_found(error):
        """处理 404 错误"""
        return jsonify({
            'status': 'error',
            'message': '资源不存在',
            'code': 404
        }), 404
    
    @app.errorhandler(500)
    def handle_internal_error(error):
        """处理 500 错误"""
        logger.error(f"Internal Server Error: {str(error)}", exc_info=True)
        return jsonify({
            'status': 'error',
            'message': '服务器内部错误',
            'code': 500
        }), 500
    
    @app.errorhandler(Exception)
    def handle_generic_exception(error):
        """处理未捕获的异常"""
        logger.error(f"Unhandled Exception: {str(error)}", exc_info=True)
        return jsonify({
            'status': 'error',
            'message': '服务器内部错误',
            'code': 500
        }), 500
    
    # 不再自动恢复生成状态
    # 原因：会导致每次启动应用都显示"正在加载上次生成结果"
    # 用户可以通过"题目管理"页面查看历史题目
    # with app.app_context():
    #     try:
    #         from .routes.generator.core import init_generation_state
    #         init_generation_state()
    #     except Exception as e:
    #         print(f"初始化生成状态时出错: {str(e)}")
    #         import traceback
    #         traceback.print_exc()
    
    return app
    