#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
Output Manager
输出管理器 - 重构版本，支持配置化的文件命名和路径管理
"""

import os
import json
import gzip
from pathlib import Path
from datetime import datetime
from typing import Dict, Any, Optional, Union
import logging

from ..config import OutputConfig
from ..exceptions import AlgorithmError

logger = logging.getLogger(__name__)


class OutputManager:
    """
    输出管理器 - 重构版本，移除硬编码的文件名和路径
    """

    def __init__(self, config: OutputConfig, run_id: Optional[str] = None):
        """
        初始化输出管理器

        Args:
            config: 输出配置
            run_id: 运行ID（用于目录命名）
        """
        self.config = config
        self.run_id = run_id or self._generate_run_id()
        
        # 创建输出目录
        self.base_output_dir = Path(self.config.base_output_directory)
        self.run_output_dir = self._create_run_directory()
        
        logger.info(f"输出管理器初始化完成，输出目录: {self.run_output_dir}")

    def _generate_run_id(self) -> str:
        """生成运行ID"""
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        return f"run_{timestamp}"

    def _create_run_directory(self) -> Path:
        """创建运行目录"""
        if self.config.enable_timestamped_folders:
            # 使用时间戳文件夹
            folder_name = self.config.folder_name_pattern.format(
                timestamp=datetime.now().strftime("%Y%m%d_%H%M%S"),
                run_id=self.run_id
            )
            output_dir = self.base_output_dir / folder_name
        else:
            # 直接使用基础目录
            output_dir = self.base_output_dir
        
        # 创建目录
        output_dir.mkdir(parents=True, exist_ok=True)
        return output_dir

    def get_file_path(self, filename_key: str, stage: str = "", subfolder: str = "") -> Path:
        """
        获取文件路径

        Args:
            filename_key: 文件名配置键
            stage: 阶段名称（用于文件名模板）
            subfolder: 子文件夹

        Returns:
            完整的文件路径
        """
        # 从配置获取文件名模板
        filename_template = self.config.file_naming.get(filename_key, f"{filename_key}.txt")
        
        # 格式化文件名
        filename = filename_template.format(stage=stage, run_id=self.run_id)
        
        # 构建完整路径
        if subfolder:
            file_path = self.run_output_dir / subfolder / filename
            file_path.parent.mkdir(parents=True, exist_ok=True)
        else:
            file_path = self.run_output_dir / filename
        
        return file_path

    def save_text(self, content: str, filename_key: str, stage: str = "", subfolder: str = "") -> str:
        """
        保存文本内容

        Args:
            content: 要保存的文本内容
            filename_key: 文件名配置键
            stage: 阶段名称
            subfolder: 子文件夹

        Returns:
            保存的文件路径
        """
        try:
            file_path = self.get_file_path(filename_key, stage, subfolder)
            
            with open(file_path, 'w', encoding='utf-8') as f:
                f.write(content)
            
            logger.debug(f"文本已保存: {file_path}")
            return str(file_path)
            
        except Exception as e:
            error_msg = f"保存文本失败: {e}"
            logger.error(error_msg)
            raise AlgorithmError(error_msg)

    def save_json(self, data: Dict[str, Any], filename_key: str, stage: str = "", subfolder: str = "") -> str:
        """
        保存JSON数据

        Args:
            data: 要保存的数据
            filename_key: 文件名配置键
            stage: 阶段名称
            subfolder: 子文件夹

        Returns:
            保存的文件路径
        """
        try:
            file_path = self.get_file_path(filename_key, stage, subfolder)
            
            with open(file_path, 'w', encoding='utf-8') as f:
                json.dump(data, f, ensure_ascii=False, indent=2)
            
            logger.debug(f"JSON已保存: {file_path}")
            return str(file_path)
            
        except Exception as e:
            error_msg = f"保存JSON失败: {e}"
            logger.error(error_msg)
            raise AlgorithmError(error_msg)

    def save_binary(self, data: bytes, filename: str, subfolder: str = "") -> str:
        """
        保存二进制数据

        Args:
            data: 二进制数据
            filename: 文件名
            subfolder: 子文件夹

        Returns:
            保存的文件路径
        """
        try:
            if subfolder:
                file_path = self.run_output_dir / subfolder / filename
                file_path.parent.mkdir(parents=True, exist_ok=True)
            else:
                file_path = self.run_output_dir / filename
            
            with open(file_path, 'wb') as f:
                f.write(data)
            
            logger.debug(f"二进制文件已保存: {file_path}")
            return str(file_path)
            
        except Exception as e:
            error_msg = f"保存二进制文件失败: {e}"
            logger.error(error_msg)
            raise AlgorithmError(error_msg)

    def save_metadata(self, metadata: Dict[str, Any], stage: str = "", subfolder: str = "") -> str:
        """
        保存元数据

        Args:
            metadata: 元数据
            stage: 阶段名称
            subfolder: 子文件夹

        Returns:
            保存的文件路径
        """
        if not self.config.save_metadata:
            return ""
        
        # 添加运行信息到元数据
        enhanced_metadata = {
            "run_id": self.run_id,
            "timestamp": datetime.now().isoformat(),
            "stage": stage,
            **metadata
        }
        
        return self.save_json(enhanced_metadata, "metadata", stage, subfolder)

    def save_with_compression(self, content: str, filename_key: str, stage: str = "", subfolder: str = "") -> str:
        """
        压缩保存文本内容

        Args:
            content: 要保存的文本内容
            filename_key: 文件名配置键
            stage: 阶段名称
            subfolder: 子文件夹

        Returns:
            保存的文件路径
        """
        try:
            file_path = self.get_file_path(filename_key, stage, subfolder)
            compressed_path = file_path.with_suffix(file_path.suffix + '.gz')
            
            with gzip.open(compressed_path, 'wt', encoding='utf-8') as f:
                f.write(content)
            
            logger.debug(f"压缩文件已保存: {compressed_path}")
            return str(compressed_path)
            
        except Exception as e:
            error_msg = f"压缩保存失败: {e}"
            logger.error(error_msg)
            raise AlgorithmError(error_msg)

    def create_subfolder(self, subfolder_name: str) -> Path:
        """
        创建子文件夹

        Args:
            subfolder_name: 子文件夹名称

        Returns:
            子文件夹路径
        """
        subfolder_path = self.run_output_dir / subfolder_name
        subfolder_path.mkdir(parents=True, exist_ok=True)
        return subfolder_path

    def list_files(self, pattern: str = "*", subfolder: str = "") -> list:
        """
        列出文件

        Args:
            pattern: 文件模式
            subfolder: 子文件夹

        Returns:
            文件路径列表
        """
        if subfolder:
            search_dir = self.run_output_dir / subfolder
        else:
            search_dir = self.run_output_dir
        
        if search_dir.exists():
            return list(search_dir.glob(pattern))
        return []

    def cleanup_old_runs(self) -> None:
        """清理旧的运行目录"""
        if not self.config.backup_count or self.config.backup_count <= 0:
            return
        
        try:
            # 获取所有运行目录
            run_dirs = []
            for item in self.base_output_dir.iterdir():
                if item.is_dir() and item.name.startswith('run_'):
                    run_dirs.append(item)
            
            # 按修改时间排序，保留最新的N个
            run_dirs.sort(key=lambda x: x.stat().st_mtime, reverse=True)
            
            # 删除超出保留数量的目录
            for old_dir in run_dirs[self.config.backup_count:]:
                try:
                    import shutil
                    shutil.rmtree(old_dir)
                    logger.info(f"已清理旧运行目录: {old_dir}")
                except Exception as e:
                    logger.warning(f"清理目录失败 {old_dir}: {e}")
                    
        except Exception as e:
            logger.warning(f"清理旧运行目录失败: {e}")

    def get_output_summary(self) -> Dict[str, Any]:
        """
        获取输出摘要

        Returns:
            输出摘要信息
        """
        files = self.list_files()
        
        return {
            "run_id": self.run_id,
            "output_directory": str(self.run_output_dir),
            "file_count": len(files),
            "files": [str(f.relative_to(self.run_output_dir)) for f in files],
            "total_size": sum(f.stat().st_size for f in files if f.is_file()),
            "created_at": datetime.now().isoformat()
        }

    def __str__(self) -> str:
        return f"OutputManager(run_id={self.run_id}, output_dir={self.run_output_dir})" 