# -*- coding: utf-8 -*-
"""应用程序设置管理"""

import json
import os
import sys
from pathlib import Path
from typing import Any, Dict, Optional


class AppSettings:
    """应用程序设置单例"""
    
    _instance: Optional["AppSettings"] = None
    
    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
            cls._instance._initialized = False
        return cls._instance
    
    def __init__(self):
        if self._initialized:
            return
        self._initialized = True
        
        # 配置文件路径
        self._settings_file = self._get_settings_path()
        
        # 默认设置
        self._settings = {
            "etl_project_path": "",  # ETL 项目路径
            "env_file_path": "",     # .env 文件路径
            # 自动更新配置
            "auto_update": {
                "hours": 24,
                "overlap_seconds": 3600,
                "include_dwd": True,
                "auto_verify": False,
                "selected_tasks": [],
            },
            # 数据校验配置
            "integrity_check": {
                "mode": "history",
                "history_start": "",
                "history_end": "",
                "lookback_hours": 24,
                "include_dimensions": True,
                "auto_backfill": False,
                "ods_tasks": "",
            },
            # 高级配置
            "advanced": {
                "pipeline_flow": "FULL",
                "dry_run": False,
                "window_start": "",
                "window_end": "",
                "window_split": "none",
                "window_compensation": 0,
                "ingest_source": "",
                "store_id": "",
                "pg_dsn": "",
                "api_token": "",
            },
        }
        
        # 加载设置
        self._load()
        
        # 如果没有配置，尝试自动检测
        if not self._settings["etl_project_path"]:
            self._auto_detect_paths()
    
    def _get_settings_path(self) -> Path:
        """获取设置文件路径"""
        # 优先使用用户目录
        if sys.platform == "win32":
            app_data = os.environ.get("APPDATA", "")
            if app_data:
                settings_dir = Path(app_data) / "ETL管理系统"
            else:
                settings_dir = Path.home() / ".etl_gui"
        else:
            settings_dir = Path.home() / ".etl_gui"
        
        settings_dir.mkdir(parents=True, exist_ok=True)
        return settings_dir / "settings.json"
    
    def _auto_detect_paths(self):
        """自动检测 ETL 项目路径"""
        # 方法1: 检查是否从源码目录运行
        try:
            source_dir = Path(__file__).resolve().parents[2]
            cli_main = source_dir / "cli" / "main.py"
            if cli_main.exists():
                rel_source = Path(os.path.relpath(source_dir, Path.cwd()))
                self._settings["etl_project_path"] = str(rel_source)
                env_file = rel_source / ".env"
                if env_file.exists():
                    self._settings["env_file_path"] = str(env_file)
                self._save()
                return
        except Exception:
            pass
        
        # 方法2: 检查常见位置
        common_paths = [
            Path("etl_billiards"),
            Path("."),
        ]
        
        for path in common_paths:
            if path.exists() and (path / "cli" / "main.py").exists():
                self._settings["etl_project_path"] = str(path)
                env_file = path / ".env"
                if env_file.exists():
                    self._settings["env_file_path"] = str(env_file)
                self._save()
                return
    
    def _load(self):
        """加载设置"""
        if self._settings_file.exists():
            try:
                data = json.loads(self._settings_file.read_text(encoding="utf-8"))
                self._settings.update(data)
            except Exception:
                pass
    
    def _save(self):
        """保存设置"""
        try:
            self._settings_file.write_text(
                json.dumps(self._settings, ensure_ascii=False, indent=2),
                encoding="utf-8"
            )
        except Exception:
            pass
    
    @property
    def etl_project_path(self) -> str:
        """获取 ETL 项目路径"""
        return self._settings.get("etl_project_path", "")
    
    @etl_project_path.setter
    def etl_project_path(self, value: str):
        """设置 ETL 项目路径"""
        self._settings["etl_project_path"] = value
        # 同时更新 .env 路径
        if value:
            env_path = Path(value) / ".env"
            if env_path.exists():
                self._settings["env_file_path"] = str(env_path)
        self._save()
    
    @property
    def env_file_path(self) -> str:
        """获取 .env 文件路径"""
        path = self._settings.get("env_file_path", "")
        if not path and self.etl_project_path:
            path = str(Path(self.etl_project_path) / ".env")
        return path
    
    @env_file_path.setter
    def env_file_path(self, value: str):
        """设置 .env 文件路径"""
        self._settings["env_file_path"] = value
        self._save()
    
    def is_configured(self) -> bool:
        """检查是否已配置"""
        path = self.etl_project_path
        if not path:
            return False
        return Path(path).exists() and (Path(path) / "cli" / "main.py").exists()
    
    def validate(self) -> tuple[bool, str]:
        """验证配置"""
        path = self.etl_project_path
        if not path:
            return False, "未配置 ETL 项目路径"
        
        project_path = Path(path)
        if not project_path.exists():
            return False, f"ETL 项目路径不存在: {path}"
        
        cli_main = project_path / "cli" / "main.py"
        if not cli_main.exists():
            return False, f"找不到 CLI 入口: {cli_main}"
        
        return True, "配置有效"
    
    # ==================== 自动更新配置 ====================
    
    @property
    def auto_update_hours(self) -> int:
        return self._settings.get("auto_update", {}).get("hours", 24)
    
    @auto_update_hours.setter
    def auto_update_hours(self, value: int):
        self._settings.setdefault("auto_update", {})["hours"] = value
        self._save()
    
    @property
    def auto_update_overlap_seconds(self) -> int:
        return self._settings.get("auto_update", {}).get("overlap_seconds", 3600)
    
    @auto_update_overlap_seconds.setter
    def auto_update_overlap_seconds(self, value: int):
        self._settings.setdefault("auto_update", {})["overlap_seconds"] = value
        self._save()
    
    @property
    def auto_update_include_dwd(self) -> bool:
        return self._settings.get("auto_update", {}).get("include_dwd", True)
    
    @auto_update_include_dwd.setter
    def auto_update_include_dwd(self, value: bool):
        self._settings.setdefault("auto_update", {})["include_dwd"] = value
        self._save()
    
    @property
    def auto_update_auto_verify(self) -> bool:
        return self._settings.get("auto_update", {}).get("auto_verify", False)
    
    @auto_update_auto_verify.setter
    def auto_update_auto_verify(self, value: bool):
        self._settings.setdefault("auto_update", {})["auto_verify"] = value
        self._save()
    
    @property
    def auto_update_selected_tasks(self) -> list:
        return self._settings.get("auto_update", {}).get("selected_tasks", [])
    
    @auto_update_selected_tasks.setter
    def auto_update_selected_tasks(self, value: list):
        self._settings.setdefault("auto_update", {})["selected_tasks"] = value
        self._save()
    
    # ==================== 数据校验配置 ====================
    
    @property
    def integrity_mode(self) -> str:
        return self._settings.get("integrity_check", {}).get("mode", "history")
    
    @integrity_mode.setter
    def integrity_mode(self, value: str):
        self._settings.setdefault("integrity_check", {})["mode"] = value
        self._save()
    
    @property
    def integrity_history_start(self) -> str:
        return self._settings.get("integrity_check", {}).get("history_start", "")
    
    @integrity_history_start.setter
    def integrity_history_start(self, value: str):
        self._settings.setdefault("integrity_check", {})["history_start"] = value
        self._save()
    
    @property
    def integrity_history_end(self) -> str:
        return self._settings.get("integrity_check", {}).get("history_end", "")
    
    @integrity_history_end.setter
    def integrity_history_end(self, value: str):
        self._settings.setdefault("integrity_check", {})["history_end"] = value
        self._save()
    
    @property
    def integrity_lookback_hours(self) -> int:
        return self._settings.get("integrity_check", {}).get("lookback_hours", 24)
    
    @integrity_lookback_hours.setter
    def integrity_lookback_hours(self, value: int):
        self._settings.setdefault("integrity_check", {})["lookback_hours"] = value
        self._save()
    
    @property
    def integrity_include_dimensions(self) -> bool:
        return self._settings.get("integrity_check", {}).get("include_dimensions", True)
    
    @integrity_include_dimensions.setter
    def integrity_include_dimensions(self, value: bool):
        self._settings.setdefault("integrity_check", {})["include_dimensions"] = value
        self._save()
    
    @property
    def integrity_auto_backfill(self) -> bool:
        return self._settings.get("integrity_check", {}).get("auto_backfill", False)
    
    @integrity_auto_backfill.setter
    def integrity_auto_backfill(self, value: bool):
        self._settings.setdefault("integrity_check", {})["auto_backfill"] = value
        self._save()
    
    @property
    def integrity_ods_tasks(self) -> str:
        return self._settings.get("integrity_check", {}).get("ods_tasks", "")
    
    @integrity_ods_tasks.setter
    def integrity_ods_tasks(self, value: str):
        self._settings.setdefault("integrity_check", {})["ods_tasks"] = value
        self._save()
    
    # ==================== 高级配置 ====================
    
    @property
    def advanced_pipeline_flow(self) -> str:
        return self._settings.get("advanced", {}).get("pipeline_flow", "FULL")
    
    @advanced_pipeline_flow.setter
    def advanced_pipeline_flow(self, value: str):
        self._settings.setdefault("advanced", {})["pipeline_flow"] = value
        self._save()
    
    @property
    def advanced_dry_run(self) -> bool:
        return self._settings.get("advanced", {}).get("dry_run", False)
    
    @advanced_dry_run.setter
    def advanced_dry_run(self, value: bool):
        self._settings.setdefault("advanced", {})["dry_run"] = value
        self._save()
    
    @property
    def advanced_window_start(self) -> str:
        return self._settings.get("advanced", {}).get("window_start", "")
    
    @advanced_window_start.setter
    def advanced_window_start(self, value: str):
        self._settings.setdefault("advanced", {})["window_start"] = value
        self._save()
    
    @property
    def advanced_window_end(self) -> str:
        return self._settings.get("advanced", {}).get("window_end", "")
    
    @advanced_window_end.setter
    def advanced_window_end(self, value: str):
        self._settings.setdefault("advanced", {})["window_end"] = value
        self._save()
    
    @property
    def advanced_ingest_source(self) -> str:
        return self._settings.get("advanced", {}).get("ingest_source", "")
    
    @advanced_ingest_source.setter
    def advanced_ingest_source(self, value: str):
        self._settings.setdefault("advanced", {})["ingest_source"] = value
        self._save()
    
    @property
    def advanced_window_split(self) -> str:
        return self._settings.get("advanced", {}).get("window_split", "none")
    
    @advanced_window_split.setter
    def advanced_window_split(self, value: str):
        self._settings.setdefault("advanced", {})["window_split"] = value
        self._save()
    
    @property
    def advanced_window_compensation(self) -> int:
        return self._settings.get("advanced", {}).get("window_compensation", 0)
    
    @advanced_window_compensation.setter
    def advanced_window_compensation(self, value: int):
        self._settings.setdefault("advanced", {})["window_compensation"] = value
        self._save()
    
    def get_all_settings(self) -> Dict[str, Any]:
        """获取所有设置（用于调试）"""
        return self._settings.copy()
    
    def save_all(self):
        """强制保存所有设置"""
        self._save()
    
    # ==================== 任务历史存储 ====================
    
    def _get_history_path(self) -> Path:
        """获取任务历史文件路径"""
        return self._settings_file.parent / "task_history.json"
    
    def save_task_history(self, history_list: list):
        """保存任务历史到文件"""
        try:
            history_path = self._get_history_path()
            
            # 序列化任务历史
            serialized = []
            for task in history_list[:100]:  # 最多保存100条
                try:
                    task_data = {
                        "id": task.id,
                        "tasks": task.config.tasks if hasattr(task, 'config') else [],
                        "status": task.status.value if hasattr(task.status, 'value') else str(task.status),
                        "created_at": task.created_at.isoformat() if task.created_at else None,
                        "started_at": task.started_at.isoformat() if task.started_at else None,
                        "finished_at": task.finished_at.isoformat() if task.finished_at else None,
                        "exit_code": task.exit_code,
                        "error": task.error[:500] if task.error else "",  # 限制长度
                        "output_preview": task.output[:1000] if task.output else "",  # 输出预览
                        # 保存配置信息
                        "pipeline_flow": task.config.pipeline_flow if hasattr(task, 'config') else "FULL",
                        "window_start": task.config.window_start if hasattr(task, 'config') else None,
                        "window_end": task.config.window_end if hasattr(task, 'config') else None,
                    }
                    serialized.append(task_data)
                except Exception:
                    continue
            
            history_path.write_text(
                json.dumps(serialized, ensure_ascii=False, indent=2),
                encoding="utf-8"
            )
        except Exception as e:
            print(f"保存任务历史失败: {e}")
    
    def load_task_history(self) -> list:
        """从文件加载任务历史"""
        try:
            history_path = self._get_history_path()
            if not history_path.exists():
                return []
            
            data = json.loads(history_path.read_text(encoding="utf-8"))
            return data
        except Exception as e:
            print(f"加载任务历史失败: {e}")
            return []


# 全局单例
app_settings = AppSettings()
