"""
CTF 方向配置服务

提供方向配置的 CRUD 操作和初始化功能。
"""
import json
import os
from typing import Optional, List, Dict, Any

from app.models.database.models import (
    db, CategoryConfig, CategoryAdmin
)
from app.services.knowledge.path_config import KnowledgePathConfig


class CategoryService:
    """方向配置服务"""

    # 默认的 Web 方向配置
    DEFAULT_WEB_CONFIG = {
        'id': 'web',
        'name': 'Web 安全',
        'icon': 'globe',
        'description': 'Web 应用安全漏洞题目，包括 SQL 注入、XSS、SSRF 等常见漏洞',
        'enabled': True,
        'sort_order': 1,
        'form_fields': [
            {
                'id': 'language',
                'type': 'select',
                'label': '编程语言',
                'icon': 'code',
                'required': True,
                'placeholder': '请选择编程语言',
                'options_source': 'languages',
                'visible': True,
                'order': 1,
                'help_text': '选择题目使用的后端语言'
            },
            {
                'id': 'difficulty',
                'type': 'select',
                'label': '难度级别',
                'icon': 'signal',
                'required': True,
                'options': [
                    {'value': '入门', 'label': '入门', 'icon': 'seedling', 'description': '最多1个漏洞'},
                    {'value': '简单', 'label': '简单', 'icon': 'leaf', 'description': '最多2个漏洞'},
                    {'value': '中等', 'label': '中等', 'icon': 'tree', 'description': '最多3个漏洞'},
                    {'value': '困难', 'label': '困难', 'icon': 'mountain', 'description': '最多5个漏洞'}
                ],
                'visible': True,
                'order': 2,
                'depends_on': {'field': 'language', 'condition': 'not_empty'}
            },
            {
                'id': 'vulnerability',
                'type': 'multi_select_categorized',
                'label': '漏洞类型',
                'icon': 'bug',
                'required': True,
                'options_source': 'vulnerability_db',
                'visible': True,
                'order': 3,
                'max_count_rules': {
                    'source': 'difficulty',
                    'mapping': {'入门': 1, '简单': 2, '中等': 3, '困难': 5}
                },
                'depends_on': {'field': 'difficulty', 'condition': 'not_empty'},
                'filter_by': {'field': 'language', 'key': 'languages'}
            },
            {
                'id': 'scene',
                'type': 'select_with_sub',
                'label': '应用场景',
                'icon': 'building',
                'required': False,
                'options_source': 'scenes',
                'allow_none': True,
                'none_option': {'value': 'none', 'label': '无场景', 'icon': 'ban'},
                'visible': True,
                'order': 4,
                'depends_on': {'field': 'vulnerability', 'condition': 'count_gt_0'}
            }
        ],
        'form_layout': {
            'rows': [
                {'id': 'row_1', 'columns': 2, 'fields': ['language', 'difficulty']},
                {'id': 'row_2', 'columns': 2, 'fields': ['vulnerability', 'scene']}
            ]
        },
        # 不再提供默认的 stages，必须由管理员在后台配置
        # 'stages': [],
        'difficulty_rules': [
            {'name': '入门', 'max_count': 1, 'writeup_count': 5, 'depth_range': [1.5, 4.0], 'diff_rate': 0.2},
            {'name': '简单', 'max_count': 2, 'writeup_count': 5, 'depth_range': [2.5, 5.0], 'diff_rate': 0.3},
            {'name': '中等', 'max_count': 3, 'writeup_count': 8, 'depth_range': [4.0, 7.0], 'diff_rate': 0.4},
            {'name': '困难', 'max_count': 5, 'writeup_count': 10, 'depth_range': [6.0, 10.0], 'diff_rate': 0.5}
        ],
        'output_config': {
            'docker': True,
            'exp': True,
            'writeup': True,
            'attachment': False,
            'directory_pattern': '{timestamp}_{name}',
            'port_range': [42500, 42600],
            'flag_format': 'DASCTF{...}'
        },
        'ui_config': {
            'page_title': 'CTF Web 题目生成向导',
            'page_description': '按顺序完成配置，快速生成高质量 CTF 题目',
            'generate_button': '开始生成',
            'reset_button': '重置',
            'primary_color': '#6366f1',
            'secondary_color': '#ec4899'
        },
        'advanced_config': {
            'ai_timeout': 600,
            'docker_timeout': 300,
            'max_retries': 3,
            'retry_interval': 10
        }
    }

    # 默认的 Crypto 方向配置
    DEFAULT_CRYPTO_CONFIG = {
        'id': 'crypto',
        'name': '密码学',
        'icon': 'key',
        'description': '密码学相关题目，包括古典密码、对称加密、非对称加密、哈希算法等',
        'enabled': False,
        'sort_order': 2,
        'form_fields': [
            {
                'id': 'difficulty',
                'type': 'select',
                'label': '难度级别',
                'icon': 'signal',
                'required': True,
                'options': [
                    {'value': '入门', 'label': '入门', 'icon': 'seedling'},
                    {'value': '简单', 'label': '简单', 'icon': 'leaf'},
                    {'value': '中等', 'label': '中等', 'icon': 'tree'},
                    {'value': '困难', 'label': '困难', 'icon': 'mountain'}
                ],
                'visible': True,
                'order': 1
            },
            {
                'id': 'algorithm_type',
                'type': 'multi_select_categorized',
                'label': '密码算法',
                'icon': 'lock',
                'required': True,
                'options': [
                    {'category': '古典密码', 'items': [
                        {'value': 'caesar', 'label': '凯撒密码'},
                        {'value': 'vigenere', 'label': '维吉尼亚密码'},
                        {'value': 'playfair', 'label': 'Playfair密码'},
                        {'value': 'hill', 'label': 'Hill密码'},
                        {'value': 'affine', 'label': '仿射密码'},
                        {'value': 'substitution', 'label': '替换密码'}
                    ]},
                    {'category': '对称加密', 'items': [
                        {'value': 'aes', 'label': 'AES'},
                        {'value': 'des', 'label': 'DES/3DES'},
                        {'value': 'rc4', 'label': 'RC4'},
                        {'value': 'chacha20', 'label': 'ChaCha20'},
                        {'value': 'block_mode', 'label': '分组模式攻击(ECB/CBC/CTR)'},
                        {'value': 'padding_oracle', 'label': 'Padding Oracle'}
                    ]},
                    {'category': '非对称加密', 'items': [
                        {'value': 'rsa_basic', 'label': 'RSA基础'},
                        {'value': 'rsa_attack', 'label': 'RSA攻击(小指数/共模/广播)'},
                        {'value': 'rsa_factorization', 'label': 'RSA分解(Fermat/Pollard)'},
                        {'value': 'ecc', 'label': '椭圆曲线(ECC)'},
                        {'value': 'dsa', 'label': 'DSA/ECDSA'},
                        {'value': 'diffie_hellman', 'label': 'Diffie-Hellman'}
                    ]},
                    {'category': '哈希与签名', 'items': [
                        {'value': 'hash_collision', 'label': '哈希碰撞'},
                        {'value': 'length_extension', 'label': '长度扩展攻击'},
                        {'value': 'hmac', 'label': 'HMAC'},
                        {'value': 'digital_signature', 'label': '数字签名'}
                    ]},
                    {'category': '数论与格', 'items': [
                        {'value': 'crt', 'label': '中国剩余定理(CRT)'},
                        {'value': 'discrete_log', 'label': '离散对数'},
                        {'value': 'lattice', 'label': '格密码(LLL/CVP/SVP)'},
                        {'value': 'coppersmith', 'label': 'Coppersmith攻击'}
                    ]},
                    {'category': '其他', 'items': [
                        {'value': 'prng', 'label': '伪随机数生成器'},
                        {'value': 'mt19937', 'label': 'MT19937预测'},
                        {'value': 'xor', 'label': '异或加密'},
                        {'value': 'custom', 'label': '自定义加密算法'}
                    ]}
                ],
                'visible': True,
                'order': 2,
                'max_count': 3,
                'depends_on': {'field': 'difficulty', 'condition': 'not_empty'}
            },
            {
                'id': 'math_level',
                'type': 'select',
                'label': '数学难度',
                'icon': 'calculator',
                'required': False,
                'options': [
                    {'value': '基础', 'label': '基础', 'description': '模运算、异或'},
                    {'value': '中等', 'label': '中等', 'description': '扩展欧几里得、CRT'},
                    {'value': '高级', 'label': '高级', 'description': '格基约化、椭圆曲线'}
                ],
                'visible': True,
                'order': 3,
                'depends_on': {'field': 'algorithm_type', 'condition': 'count_gt_0'}
            }
        ],
        'form_layout': {
            'rows': [
                {'id': 'row_1', 'columns': 2, 'fields': ['difficulty', 'math_level']},
                {'id': 'row_2', 'columns': 1, 'fields': ['algorithm_type']}
            ]
        },
        # 不再提供默认的 stages，必须由管理员在后台配置
        # 'stages': [],
        'difficulty_rules': [
            {'name': '入门', 'max_count': 1, 'writeup_count': 3, 'math_level': '基础'},
            {'name': '简单', 'max_count': 2, 'writeup_count': 5, 'math_level': '基础'},
            {'name': '中等', 'max_count': 2, 'writeup_count': 5, 'math_level': '中等'},
            {'name': '困难', 'max_count': 3, 'writeup_count': 8, 'math_level': '高级'}
        ],
        'output_config': {
            'docker': False,
            'exp': True,
            'writeup': True,
            'attachment': True,
            'attachment_types': ['.py', '.txt', '.zip'],
            'directory_pattern': '{timestamp}_{name}'
        },
        'ui_config': {
            'page_title': 'CTF Crypto 题目生成向导',
            'page_description': '配置密码学题目参数',
            'generate_button': '开始生成',
            'reset_button': '重置',
            'primary_color': '#10b981',
            'secondary_color': '#3b82f6'
        },
        'advanced_config': {
            'ai_timeout': 600,
            'max_retries': 3
        }
    }

    # 默认的 Reverse 方向配置
    DEFAULT_REVERSE_CONFIG = {
        'id': 'reverse',
        'name': '逆向工程',
        'icon': 'microchip',
        'description': '逆向工程题目，包括 ELF、PE、APK 等二进制文件分析',
        'enabled': False,
        'sort_order': 3,
        'form_fields': [
            {
                'id': 'difficulty',
                'type': 'select',
                'label': '难度级别',
                'icon': 'signal',
                'required': True,
                'options': [
                    {'value': '入门', 'label': '入门'},
                    {'value': '简单', 'label': '简单'},
                    {'value': '中等', 'label': '中等'},
                    {'value': '困难', 'label': '困难'}
                ],
                'visible': True,
                'order': 1
            },
            {
                'id': 'platform',
                'type': 'select',
                'label': '目标平台',
                'icon': 'desktop',
                'required': True,
                'options': [
                    {'value': 'linux_elf', 'label': 'Linux ELF'},
                    {'value': 'windows_pe', 'label': 'Windows PE'},
                    {'value': 'android_apk', 'label': 'Android APK'},
                    {'value': 'wasm', 'label': 'WebAssembly'}
                ],
                'visible': True,
                'order': 2,
                'depends_on': {'field': 'difficulty', 'condition': 'not_empty'}
            },
            {
                'id': 'technique',
                'type': 'multi_select',
                'label': '逆向技术',
                'icon': 'tools',
                'required': True,
                'options_source': 'technique_db',
                'max_count': 3,
                'visible': True,
                'order': 3,
                'depends_on': {'field': 'platform', 'condition': 'not_empty'}
            },
            {
                'id': 'obfuscation',
                'type': 'select',
                'label': '混淆程度',
                'icon': 'eye-slash',
                'required': False,
                'options': [
                    {'value': 'none', 'label': '无'},
                    {'value': 'light', 'label': '轻度'},
                    {'value': 'medium', 'label': '中度'},
                    {'value': 'heavy', 'label': '重度'}
                ],
                'visible': True,
                'order': 4
            }
        ],
        # 不再提供默认的 stages，必须由管理员在后台配置
        # 'stages': [],
        'output_config': {
            'docker': False,
            'exp': True,
            'writeup': True,
            'attachment': True
        }
    }

    # 默认的 Pwn 方向配置
    DEFAULT_PWN_CONFIG = {
        'id': 'pwn',
        'name': '二进制漏洞',
        'icon': 'bug',
        'description': '二进制漏洞利用题目，包括栈溢出、堆利用、格式化字符串等',
        'enabled': False,
        'sort_order': 4,
        'form_fields': [
            {
                'id': 'difficulty',
                'type': 'select',
                'label': '难度级别',
                'icon': 'signal',
                'required': True,
                'options': [
                    {'value': '入门', 'label': '入门'},
                    {'value': '简单', 'label': '简单'},
                    {'value': '中等', 'label': '中等'},
                    {'value': '困难', 'label': '困难'}
                ],
                'visible': True,
                'order': 1
            },
            {
                'id': 'arch',
                'type': 'select',
                'label': '架构',
                'icon': 'microchip',
                'required': True,
                'options': [
                    {'value': 'x86', 'label': 'x86 (32位)'},
                    {'value': 'x86_64', 'label': 'x86_64 (64位)'},
                    {'value': 'arm', 'label': 'ARM'},
                    {'value': 'mips', 'label': 'MIPS'}
                ],
                'visible': True,
                'order': 2
            },
            {
                'id': 'vulnerability',
                'type': 'multi_select',
                'label': '漏洞类型',
                'icon': 'bug',
                'required': True,
                'options_source': 'pwn_vulnerability_db',
                'max_count': 3,
                'visible': True,
                'order': 3
            },
            {
                'id': 'protection',
                'type': 'multi_select',
                'label': '保护机制',
                'icon': 'shield-alt',
                'required': False,
                'options': [
                    {'value': 'nx', 'label': 'NX'},
                    {'value': 'canary', 'label': 'Canary'},
                    {'value': 'pie', 'label': 'PIE'},
                    {'value': 'relro', 'label': 'RELRO'},
                    {'value': 'aslr', 'label': 'ASLR'}
                ],
                'visible': True,
                'order': 4
            }
        ],
        # 不再提供默认的 stages，必须由管理员在后台配置
        # 'stages': [],
        'output_config': {
            'docker': True,
            'exp': True,
            'writeup': True,
            'attachment': True
        }
    }

    # 默认的 Misc 方向配置
    DEFAULT_MISC_CONFIG = {
        'id': 'misc',
        'name': '杂项',
        'icon': 'puzzle-piece',
        'description': '杂项题目，包括隐写、取证、编码、脑洞等',
        'enabled': False,
        'sort_order': 5,
        'form_fields': [
            {
                'id': 'difficulty',
                'type': 'select',
                'label': '难度级别',
                'icon': 'signal',
                'required': True,
                'options': [
                    {'value': '入门', 'label': '入门'},
                    {'value': '简单', 'label': '简单'},
                    {'value': '中等', 'label': '中等'},
                    {'value': '困难', 'label': '困难'}
                ],
                'visible': True,
                'order': 1
            },
            {
                'id': 'skill_type',
                'type': 'multi_select',
                'label': '技能类型',
                'icon': 'tools',
                'required': True,
                'options_source': 'misc_skill_db',
                'max_count': 3,
                'visible': True,
                'order': 2
            }
        ],
        # 不再提供默认的 stages，必须由管理员在后台配置
        # 'stages': [],
        'output_config': {
            'docker': False,
            'exp': True,
            'writeup': True,
            'attachment': True
        }
    }

    @classmethod
    def init_default_categories(cls):
        """初始化默认方向配置"""
        default_configs = [
            cls.DEFAULT_WEB_CONFIG,
            cls.DEFAULT_CRYPTO_CONFIG,
            cls.DEFAULT_REVERSE_CONFIG,
            cls.DEFAULT_PWN_CONFIG,
            cls.DEFAULT_MISC_CONFIG
        ]

        for config in default_configs:
            existing = CategoryConfig.query.get(config['id'])
            if not existing:
                cls.create_category(config)

    @classmethod
    def create_category(cls, config: Dict[str, Any]) -> CategoryConfig:
        """创建方向配置"""
        category = CategoryConfig(
            id=config['id'],
            name=config['name'],
            icon=config.get('icon', 'folder'),
            description=config.get('description', ''),
            enabled=config.get('enabled', False),
            sort_order=config.get('sort_order', 0)
        )

        # 设置 JSON 配置
        if 'form_fields' in config:
            category.set_form_fields(config['form_fields'])
        if 'form_layout' in config:
            category.set_form_layout(config['form_layout'])
        
        # 支持新格式（difficulties）和旧格式（stages + difficulty_rules）
        if 'difficulties' in config:
            # 新格式：直接设置 difficulties
            category.set_difficulties(config['difficulties'])
        else:
            # 旧格式：设置 stages 和 difficulty_rules（向后兼容）
            if 'stages' in config:
                category.set_stages(config['stages'])
            if 'difficulty_rules' in config:
                category.set_difficulty_rules(config['difficulty_rules'])
        
        if 'output_config' in config:
            category.set_output_config(config['output_config'])
        if 'ui_config' in config:
            category.set_ui_config(config['ui_config'])
        if 'advanced_config' in config:
            category.set_advanced_config(config['advanced_config'])

        # 设置文件路径
        # 注意：prompt_template_path 已废弃，CLAUDE.md 会在运行时自动生成
        category.prompt_template_path = config.get('prompt_template_path', f'ge10/{config["id"]}/CLAUDE.md')
        # 使用新的目录结构作为默认值
        # 默认路径统一为data目录
        category.knowledge_base_path = config.get('knowledge_base_path', f'ge10/{config["id"]}/data')
        category.knowledge_db_path = config.get('knowledge_db_path', f'ge10/{config["id"]}/data/vulnerability_db.json')
        category.choice_script_path = config.get('choice_script_path', f'ge10/{config["id"]}/data/scripts/choice.py')

        db.session.add(category)
        db.session.commit()

        # ========== 初始化方向对应的文件目录结构 ==========
        try:
            # 使用统一的路径配置管理器，创建目录：
            # ge10/{id}/data/          - 统一的数据目录（所有文件都在这里）
            # ge10/{id}/prompts/       - Prompt文件目录
            # ge10/{id}/output/        - 输出目录
            path_config = KnowledgePathConfig(category.id)
            # 创建 data、prompts、output 等必要目录
            path_config.ensure_directories()

            # 注意：CLAUDE.md 和 config.json 不再手动创建
            # - CLAUDE.md 会在运行时由 guideline_manager 根据难度自动生成
            # - config.json 已被废弃，所有配置都存储在数据库中
        except Exception:
            # 目录创建失败不影响方向在后台使用，错误记录到日志由上层处理
            pass

        # ========== 自动编译并存储 Prompt 模板 ==========
        # 如果配置中包含 stages 或 difficulties，自动编译 prompt
        if 'stages' in config or 'difficulties' in config:
            from app.services.prompt.compiler_service import PromptCompilerService
            try:
                PromptCompilerService.compile_and_save_prompts(category)
                db.session.commit()
            except Exception as e:
                import logging
                logging.warning(f'创建方向后自动编译 Prompt 失败: {str(e)}')
                # 编译失败不影响创建，只记录日志

        return category

    @classmethod
    def update_category(cls, category_id: str, updates: Dict[str, Any]) -> Optional[CategoryConfig]:
        """更新方向配置"""
        category = CategoryConfig.query.get(category_id)
        if not category:
            return None

        # 更新基本字段
        if 'name' in updates:
            category.name = updates['name']
        if 'icon' in updates:
            category.icon = updates['icon']
        if 'description' in updates:
            category.description = updates['description']
        if 'enabled' in updates:
            category.enabled = updates['enabled']
        if 'sort_order' in updates:
            category.sort_order = updates['sort_order']

        # 更新 JSON 配置
        should_recompile_prompt = False
        if 'form_fields' in updates:
            category.set_form_fields(updates['form_fields'])
        if 'form_layout' in updates:
            category.set_form_layout(updates['form_layout'])
        
        # 支持新格式（difficulties）和旧格式（stages + difficulty_rules）
        if 'difficulties' in updates:
            # 新格式：直接设置 difficulties
            category.set_difficulties(updates['difficulties'])
            should_recompile_prompt = True
        else:
            # 旧格式：设置 stages 和 difficulty_rules（向后兼容）
            if 'stages' in updates:
                category.set_stages(updates['stages'])
                should_recompile_prompt = True
            
            # 处理 prompt_extensions：将 prompt_extensions 合并到 stages 中（旧格式）
            if 'prompt_extensions' in updates:
                stages = category.get_stages() or []
                prompt_extensions = updates['prompt_extensions']
                if isinstance(prompt_extensions, dict):
                    for stage in stages:
                        stage_id = str(stage.get('id', ''))
                        if stage_id in prompt_extensions:
                            # 将 prompt_extensions 中的 prompts 合并到 stage 中
                            if not stage.get('prompts'):
                                stage['prompts'] = {}
                            # prompt_extensions[stage_id] 应该是一个字典，键是难度（中文），值是 prompt 内容
                            extensions = prompt_extensions[stage_id]
                            if isinstance(extensions, dict):
                                stage['prompts'].update(extensions)
                    # 更新 stages
                    category.set_stages(stages)
                    should_recompile_prompt = True
            
            if 'difficulty_rules' in updates:
                category.set_difficulty_rules(updates['difficulty_rules'])
                should_recompile_prompt = True
        if 'output_config' in updates:
            category.set_output_config(updates['output_config'])
        if 'ui_config' in updates:
            category.set_ui_config(updates['ui_config'])
        # 处理 system_prompt（可以单独传递，也可以放在 advanced_config 中）
        if 'system_prompt' in updates:
            advanced = category.get_advanced_config() or {}
            advanced['system_prompt'] = updates['system_prompt']
            category.set_advanced_config(advanced)
            should_recompile_prompt = True
        elif 'advanced_config' in updates:
            category.set_advanced_config(updates['advanced_config'])
            # 如果系统提示词发生变化，需要重新编译
            if isinstance(updates['advanced_config'], dict) and 'system_prompt' in updates['advanced_config']:
                should_recompile_prompt = True

        # 更新文件路径
        if 'prompt_template_path' in updates:
            category.prompt_template_path = updates['prompt_template_path']
        if 'knowledge_base_path' in updates:
            category.knowledge_base_path = updates['knowledge_base_path']
        if 'knowledge_db_path' in updates:
            category.knowledge_db_path = updates['knowledge_db_path']
        if 'choice_script_path' in updates:
            category.choice_script_path = updates['choice_script_path']
        if 'output_dir' in updates:
            category.output_dir = updates['output_dir']

        # 如果相关配置发生变化，自动编译并存储 Prompt 模板
        if should_recompile_prompt:
            from app.services.prompt.compiler_service import PromptCompilerService
            try:
                PromptCompilerService.compile_and_save_prompts(category)
            except Exception as e:
                import logging
                logging.warning(f'自动编译 Prompt 失败: {str(e)}')

        db.session.commit()
        
        # 不再自动生成 Prompt 文件，所有配置存储在数据库中

        return category

    @classmethod
    def delete_category(cls, category_id: str) -> bool:
        """删除方向配置"""
        category = CategoryConfig.query.get(category_id)
        if not category:
            return False

        # 先删除所有相关的 category_admins 记录
        # 即使数据库有级联删除，手动删除可以避免约束错误
        CategoryAdmin.query.filter_by(category_id=category_id).delete()

        db.session.delete(category)
        db.session.commit()
        return True

    @classmethod
    def get_category(cls, category_id: str) -> Optional[CategoryConfig]:
        """获取方向配置"""
        return CategoryConfig.query.get(category_id)

    @classmethod
    def get_all_categories(cls) -> List[CategoryConfig]:
        """获取所有方向配置"""
        return CategoryConfig.get_all_categories()

    @classmethod
    def get_enabled_categories(cls) -> List[CategoryConfig]:
        """获取所有启用的方向配置"""
        return CategoryConfig.get_enabled_categories()

    @classmethod
    def export_category(cls, category_id: str) -> Optional[Dict[str, Any]]:
        """导出方向配置为 JSON"""
        category = CategoryConfig.query.get(category_id)
        if not category:
            return None

        return category.to_dict(include_config=True)

    @classmethod
    def import_category(cls, config: Dict[str, Any], overwrite: bool = False) -> Optional[CategoryConfig]:
        """从 JSON 导入方向配置"""
        category_id = config.get('id')
        if not category_id:
            return None

        existing = CategoryConfig.query.get(category_id)
        if existing:
            if overwrite:
                return cls.update_category(category_id, config)
            else:
                return None

        return cls.create_category(config)
