"""
Реестр обученных моделей нейронных сетей.

Позволяет регистрировать, искать и управлять обученными моделями
для различных тикеров и таймфреймов.

Пример использования:
    registry = ModelRegistry()
    best = registry.get_best_model('SBER')
    registry.register('sber_lstm_v1', 'LSTMPredictor', 'SBER', 'D1', {...}, {...}, 'path')
"""

import json
from datetime import datetime
from pathlib import Path
from typing import Optional


class ModelRegistry:
    """
    Registry for managing trained neural network models.

    Attributes:
        registry_path: путь к файлу registry.json.
    """

    def __init__(self, registry_path: str = 'src/ml/models/saved/registry.json'):
        """
        Инициализация реестра.

        Args:
            registry_path: путь к JSON-файлу реестра.
        """
        self.registry_path = Path(registry_path)
        self.registry_path.parent.mkdir(parents=True, exist_ok=True)
        self.registry = self._load()

    def _load(self) -> list:
        """Загрузить реестр из JSON-файла."""
        if self.registry_path.exists():
            return json.loads(self.registry_path.read_text())
        return []

    def _save(self) -> None:
        """Сохранить реестр в JSON-файл."""
        self.registry_path.write_text(
            json.dumps(self.registry, indent=2, default=str, ensure_ascii=False)
        )

    def register(
        self,
        model_name: str,
        model_type: str,
        ticker: str,
        timeframe: str,
        params: dict,
        metrics: dict,
        model_path: str,
    ) -> None:
        """
        Зарегистрировать новую модель.

        Args:
            model_name: уникальное имя модели (например, 'sber_lstm_v1').
            model_type: тип архитектуры (LSTMPredictor, GRUPredictor, ...).
            ticker: тикер MOEX (SBER, GAZP, ...).
            timeframe: таймфрейм (D1, H1, W1).
            params: гиперпараметры модели.
            metrics: метрики производительности.
            model_path: путь к файлам экспортированной модели.
        """
        entry = {
            'model_name': model_name,
            'model_type': model_type,
            'ticker': ticker,
            'timeframe': timeframe,
            'params': params,
            'metrics': metrics,
            'model_path': model_path,
            'created_at': datetime.now().isoformat(),
            'status': 'active',
        }
        # Проверка дубликатов
        self.registry = [m for m in self.registry if m['model_name'] != model_name]
        self.registry.append(entry)
        self._save()

    def get_best_model(
        self,
        ticker: str,
        timeframe: Optional[str] = None,
        metric: str = 'val_accuracy',
    ) -> Optional[dict]:
        """
        Получить лучшую модель для тикера.

        Args:
            ticker: тикер MOEX.
            timeframe: опциональный фильтр по таймфрейму.
            metric: метрика для сравнения.

        Returns:
            Запись модели или None, если моделей нет.
        """
        models = [
            m for m in self.registry
            if m['ticker'] == ticker and m['status'] == 'active'
        ]
        if timeframe:
            models = [m for m in models if m['timeframe'] == timeframe]

        if not models:
            return None

        return max(models, key=lambda m: m['metrics'].get(metric, 0))

    def archive_model(self, model_name: str) -> None:
        """Архивировать модель (пометить как неактивную)."""
        for entry in self.registry:
            if entry['model_name'] == model_name:
                entry['status'] = 'archived'
        self._save()

    def list_models(
        self,
        ticker: Optional[str] = None,
        status: str = 'active',
    ) -> list:
        """
        Список моделей с опциональной фильтрацией.

        Args:
            ticker: опциональный фильтр по тикеру.
            status: статус ('active', 'archived', 'all').

        Returns:
            Список записей моделей.
        """
        models = self.registry
        if status != 'all':
            models = [m for m in models if m['status'] == status]
        if ticker:
            models = [m for m in models if m['ticker'] == ticker]
        return models

    def get_model(self, model_name: str) -> Optional[dict]:
        """Получить модель по имени."""
        for m in self.registry:
            if m['model_name'] == model_name:
                return m
        return None
