"""
Preset Service
预设服务层 - 处理预设的 CRUD 操作
"""
import json
import os
from pathlib import Path
from typing import List, Dict, Any, Optional
from datetime import datetime

from core.config import settings


class PresetService:
    """预设服务类"""
    
    @staticmethod
    def _extract_preset_name_from_filename(filename: str) -> str:
        """
        从文件名提取预设名称，去掉时间戳和文件后缀
        
        Args:
            filename: 文件名（不含路径）
            
        Returns:
            清理后的预设名称
            
        Examples:
            "Default.json" -> "Default"
            "MyPreset_1234567890.json" -> "MyPreset"
            "Test_1714567890123.json" -> "Test"
        """
        # 去掉 .json 后缀
        name = filename.replace('.json', '')
        
        # 去掉末尾的时间戳（下划线+数字组合）
        # 匹配模式：_后面跟着10-13位数字（Unix时间戳）
        import re
        name = re.sub(r'_\d{10,13}$', '', name)
        
        return name
    
    @staticmethod
    def _get_preset_path(name: str) -> Path:
        """获取预设文件路径"""
        return settings.PRESET_PATH / f"{name}.json"
    
    @staticmethod
    def _load_preset(name: str) -> Optional[Dict[str, Any]]:
        """加载预设 JSON 文件"""
        path = PresetService._get_preset_path(name)
        if not path.exists():
            return None
        
        try:
            with open(path, 'r', encoding='utf-8') as f:
                return json.load(f)
        except Exception as e:
            raise ValueError(f"Failed to load preset '{name}': {str(e)}")
    
    @staticmethod
    def _save_preset(name: str, data: Dict[str, Any]):
        """保存预设到 JSON 文件"""
        path = PresetService._get_preset_path(name)
        try:
            # 确保 prompts 数组和 prompt_order 的顺序一致
            if "prompts" in data and "prompt_order" in data:
                prompts = data["prompts"]
                prompt_order = data.get("prompt_order", [{}])[0].get("order", [])
                
                if prompts and prompt_order:
                    # 创建 identifier 到 prompt 的映射
                    prompt_map = {prompt["identifier"]: prompt for prompt in prompts}
                    
                    # 按照 prompt_order 的顺序重新排列 prompts
                    reordered_prompts = []
                    for order_item in prompt_order:
                        identifier = order_item.get("identifier")
                        if identifier and identifier in prompt_map:
                            reordered_prompts.append(prompt_map[identifier])
                    
                    # 添加 prompt_order 中不存在的 prompts（如果有）
                    existing_identifiers = {item.get("identifier") for item in prompt_order}
                    for prompt in prompts:
                        if prompt["identifier"] not in existing_identifiers:
                            reordered_prompts.append(prompt)
                    
                    data["prompts"] = reordered_prompts
            
            with open(path, 'w', encoding='utf-8') as f:
                json.dump(data, f, ensure_ascii=False, indent=2)
        except Exception as e:
            raise ValueError(f"Failed to save preset '{name}': {str(e)}")
    
    @staticmethod
    def list_presets() -> List[Dict[str, Any]]:
        """
        获取所有预设的列表（仅基本信息）
        
        Returns:
            预设列表，每个包含 name, description, component_count, temperature 等
        """
        presets = []
        
        for json_file in settings.PRESET_PATH.glob("*.json"):
            try:
                with open(json_file, 'r', encoding='utf-8') as f:
                    data = json.load(f)
                
                # 计算组件数量 - 支持 SillyTavern 格式 (prompts) 和内部格式 (entries)
                prompts = data.get("prompts", [])
                entries = data.get("entries", [])
                component_count = len(prompts) if prompts else len(entries)
                
                # 提取温度参数 - 使用 SillyTavern 标准字段名
                temperature = data.get("temperature", 1.0)
                
                # 从文件名提取预设名称（去掉时间戳和后缀）
                preset_name = PresetService._extract_preset_name_from_filename(json_file.name)
                
                preset_info = {
                    "name": preset_name,
                    "description": data.get("description", ""),
                    "component_count": component_count,
                    "temperature": temperature
                }
                
                presets.append(preset_info)
            except Exception as e:
                print(f"Error loading preset {json_file.name}: {e}")
                continue
        
        # 按名称排序
        presets.sort(key=lambda x: x.get("name", ""))
        return presets
    
    @staticmethod
    def get_preset(name: str) -> Dict[str, Any]:
        """
        获取指定预设的完整数据
        
        Args:
            name: 预设名称
            
        Returns:
            预设完整数据
        """
        data = PresetService._load_preset(name)
        if not data:
            raise FileNotFoundError(f"Preset '{name}' not found")
        
        return data
    
    @staticmethod
    def create_preset(name: str, preset_data: Dict[str, Any]) -> Dict[str, Any]:
        """
        创建新预设
        
        Args:
            name: 预设名称
            preset_data: 预设数据
            
        Returns:
            创建的预设数据
        """
        # 检查是否已存在
        if PresetService._get_preset_path(name).exists():
            raise ValueError(f"Preset '{name}' already exists")
        
        # 确保有必要的字段
        if "name" not in preset_data:
            preset_data["name"] = name
        
        # 添加时间戳
        now = int(datetime.now().timestamp())
        if "createdAt" not in preset_data:
            preset_data["createdAt"] = now
        if "updatedAt" not in preset_data:
            preset_data["updatedAt"] = now
        
        PresetService._save_preset(name, preset_data)
        return preset_data
    
    @staticmethod
    def update_preset(name: str, update_data: Dict[str, Any]) -> Dict[str, Any]:
        """
        更新预设
        
        Args:
            name: 预设名称
            update_data: 要更新的数据
            
        Returns:
            更新后的预设数据
        """
        data = PresetService._load_preset(name)
        if not data:
            raise FileNotFoundError(f"Preset '{name}' not found")
        
        # 更新字段
        for key, value in update_data.items():
            if key not in ["name", "createdAt"]:  # 不允许修改名称和创建时间
                data[key] = value
        
        # 更新时间戳
        data["updatedAt"] = int(datetime.now().timestamp())
        
        PresetService._save_preset(name, data)
        return data
    
    @staticmethod
    def delete_preset(name: str) -> bool:
        """
        删除预设
        
        Args:
            name: 预设名称
            
        Returns:
            是否删除成功
        """
        path = PresetService._get_preset_path(name)
        if not path.exists():
            raise FileNotFoundError(f"Preset '{name}' not found")
        
        path.unlink()
        return True
    
    @staticmethod
    def rename_preset(old_name: str, new_name: str) -> Dict[str, Any]:
        """
        重命名预设（同时修改文件名和内部 name 字段）
        
        Args:
            old_name: 原预设名称
            new_name: 新预设名称
            
        Returns:
            更新后的预设数据
        """
        # 检查原预设是否存在
        old_path = PresetService._get_preset_path(old_name)
        if not old_path.exists():
            raise FileNotFoundError(f"Preset '{old_name}' not found")
        
        # 检查新名称是否已存在
        new_path = PresetService._get_preset_path(new_name)
        if new_path.exists() and old_name != new_name:
            raise ValueError(f"Preset '{new_name}' already exists")
        
        # 加载原预设数据
        data = PresetService._load_preset(old_name)
        if not data:
            raise FileNotFoundError(f"Preset '{old_name}' not found")
        
        # 更新内部的 name 字段
        data["name"] = new_name
        
        # 更新时间戳
        data["updatedAt"] = int(datetime.now().timestamp())
        
        # 保存到新文件
        PresetService._save_preset(new_name, data)
        
        # 删除旧文件（如果名称不同）
        if old_name != new_name:
            old_path.unlink()
        
        return data
    
    @staticmethod
    def reorder_components(name: str, component_order: List[str]) -> Dict[str, Any]:
        """
        重新排序预设组件 - 支持 SillyTavern 标准格式
        
        Args:
            name: 预设名称
            component_order: 组件 identifier 列表，按新顺序排列
            
        Returns:
            更新后的预设数据
        """
        data = PresetService._load_preset(name)
        if not data:
            raise FileNotFoundError(f"Preset '{name}' not found")
        
        # 支持 SillyTavern 格式的 prompts
        if "prompts" in data and isinstance(data["prompts"], list):
            # 创建 identifier 到 prompt 的映射
            prompt_map = {prompt["identifier"]: prompt for prompt in data["prompts"]}
            
            # 按新顺序重新排列
            reordered_prompts = []
            for identifier in component_order:
                if identifier in prompt_map:
                    reordered_prompts.append(prompt_map[identifier])
            
            data["prompts"] = reordered_prompts
            
            # 更新 prompt_order
            if "prompt_order" in data and isinstance(data["prompt_order"], list) and len(data["prompt_order"]) > 0:
                data["prompt_order"][0]["order"] = [
                    {"identifier": identifier, "enabled": True}
                    for identifier in component_order
                    if identifier in prompt_map
                ]
        
        # 也支持内部格式的 entries（向后兼容）
        elif "entries" in data and isinstance(data["entries"], list):
            # 创建 identifier 到 entry 的映射
            entry_map = {entry["identifier"]: entry for entry in data["entries"]}
            
            # 按新顺序重新排列
            reordered_entries = []
            for identifier in component_order:
                if identifier in entry_map:
                    reordered_entries.append(entry_map[identifier])
            
            # 更新 order 字段
            for index, entry in enumerate(reordered_entries):
                entry["order"] = index
            
            data["entries"] = reordered_entries
        
        # 更新时间戳
        data["updatedAt"] = int(datetime.now().timestamp())
        
        PresetService._save_preset(name, data)
        return data
