"""
VNA Simulator Module

This module provides a simulator mode that loads sweep data from a JSON file
and adds configurable Gaussian noise to simulate real device behavior.
"""

import json
import logging
import time
from pathlib import Path
from typing import List, Tuple, Optional
import numpy as np

from vna_system.core import config

logger = logging.getLogger(__name__)


class VNASimulator:
    """
    Simulator for VNA device that loads sweep data from file and adds noise.

    This simulator reads a reference sweep from a JSON file and adds Gaussian
    noise to the real and imaginary components to simulate measurement variations.
    """

    def __init__(
        self,
        sweep_file: Optional[Path] = None,
        noise_level: Optional[float] = None
    ):
        """
        Initialize the VNA simulator.

        Args:
            sweep_file: Path to JSON file containing sweep data.
                       If None, uses config.SIMULATOR_SWEEP_FILE
            noise_level: Standard deviation of Gaussian noise to add.
                        If None, uses config.SIMULATOR_NOISE_LEVEL
        """
        self.sweep_file = sweep_file or config.SIMULATOR_SWEEP_FILE
        self.noise_level = noise_level if noise_level is not None else config.SIMULATOR_NOISE_LEVEL

        self._reference_points: List[Tuple[float, float]] = []
        self._sweep_counter = 0
        self._load_reference_sweep()

        logger.info(
            f"VNA Simulator initialized with file: {self.sweep_file}, "
            f"noise level: {self.noise_level}"
        )

    def _load_reference_sweep(self) -> None:
        """Load reference sweep data from JSON file."""
        try:
            with open(self.sweep_file, 'r') as f:
                data = json.load(f)

            # Extract points from JSON structure
            # Expected format: {"sweep_number": N, "timestamp": T, "points": [[real, imag], ...]}
            if 'points' not in data:
                raise ValueError(f"JSON file missing 'points' field: {self.sweep_file}")

            self._reference_points = [
                (float(point[0]), float(point[1]))
                for point in data['points']
            ]

            logger.info(
                f"Loaded {len(self._reference_points)} points from reference sweep "
                f"(sweep_number: {data.get('sweep_number', 'N/A')})"
            )

        except FileNotFoundError:
            logger.error(f"Simulator sweep file not found: {self.sweep_file}")
            raise
        except json.JSONDecodeError as e:
            logger.error(f"Failed to parse JSON file {self.sweep_file}: {e}")
            raise
        except Exception as e:
            logger.error(f"Failed to load reference sweep: {e}")
            raise

    def get_sweep(self) -> Tuple[List[Tuple[float, float]], float]:
        """
        Generate a simulated sweep with added noise.

        Returns:
            Tuple of (points, timestamp) where:
                - points: List of (real, imag) tuples with added noise
                - timestamp: Current Unix timestamp
        """
        time.sleep(1)
        timestamp = time.time()
        self._sweep_counter += 1

        # Add Gaussian noise to each point
        noisy_points = []
        for real, imag in self._reference_points:
            # Add independent noise to real and imaginary parts
            noise_real = np.random.normal(0, self.noise_level)
            noise_imag = np.random.normal(0, self.noise_level)
            noisy_real = real + noise_real
            noisy_imag = imag + noise_imag
            noisy_points.append((noisy_real, noisy_imag))

        # Log statistics about the noise added
        if len(noisy_points) > 0:
            first_orig = self._reference_points[0]
            first_noisy = noisy_points[0]
            logger.debug(
                f"Simulated sweep #{self._sweep_counter}: "
                f"noise_level={self.noise_level:.2e}, "
                f"first_point: orig=({first_orig[0]:.6e}, {first_orig[1]:.6e}), "
                f"noisy=({first_noisy[0]:.6e}, {first_noisy[1]:.6e})"
            )

        logger.debug(
            f"Generated simulated sweep #{self._sweep_counter} with "
            f"{len(noisy_points)} points at timestamp {timestamp:.6f}"
        )

        return noisy_points, timestamp

    def get_point_count(self) -> int:
        """
        Get the number of points in the reference sweep.

        Returns:
            Number of points in each simulated sweep
        """
        return len(self._reference_points)

    def reset_counter(self) -> None:
        """Reset the internal sweep counter."""
        self._sweep_counter = 0
        logger.debug("Simulator sweep counter reset")


def create_simulator() -> VNASimulator:
    """
    Factory function to create a VNA simulator instance.

    Uses configuration from config module.

    Returns:
        Configured VNASimulator instance
    """
    return VNASimulator()
