"""
Quantum field theory effects in curved spacetime.

Implements Hawking radiation, Unruh effect, Casimir energy,
and vacuum fluctuation computations.

References:
    [1] Birrell & Davies, "QFT in Curved Spacetime" (1982)
    [2] Hawking, Commun. Math. Phys. 43:199 (1975)
    [3] Unruh, Phys. Rev. D14:870 (1976)
"""

import numpy as np
from scipy.special import gamma


class QuantumFieldTheoryEffects:
    """QFT effects in curved spacetime relevant for navigation."""

    def __init__(self, dimensions: int = 4):
        self.dimensions = dimensions
        self.planck_length = 1.616e-35
        self.planck_energy = 1.956e9  # Joules

    def hawking_temperature(self, mass: float, dimensions: int = None) -> float:
        """
        Hawking temperature of black hole.

        4D: T_H = 1 / (8 pi M)
        dD: T_H = (d-3) / (4 pi r_s)

        Args:
            mass: Black hole mass
            dimensions: Spacetime dimensions

        Returns:
            Hawking temperature
        """
        d = dimensions or self.dimensions
        r_s = 2 * mass
        if d == 4:
            return 1.0 / (8 * np.pi * mass)
        return (d - 3) / (4 * np.pi * r_s)

    def unruh_temperature(self, acceleration: float) -> float:
        """
        Unruh temperature: T_U = a / (2 pi).

        Args:
            acceleration: Proper acceleration

        Returns:
            Unruh temperature (natural units)
        """
        return acceleration / (2 * np.pi)

    def casimir_energy(self, plate_separation: float, dimensions: int = None) -> float:
        """
        Casimir energy density between parallel plates.

        4D: E = -pi^2 / (240 d^4)
        dD: E ~ -Gamma(d/2) zeta(d) / (2 (4pi)^(d/2) L^d)

        Args:
            plate_separation: Distance between plates
            dimensions: Spacetime dimensions

        Returns:
            Casimir energy density
        """
        d = dimensions or self.dimensions
        if d == 4:
            return -np.pi ** 2 / (240 * plate_separation ** 4)
        zeta_d = 1.0  # Simplified
        return (
            -gamma(d / 2) * zeta_d
            / (2 * (4 * np.pi) ** (d / 2) * plate_separation ** d)
        )

    def vacuum_fluctuation_spectrum(self, frequency_range: np.ndarray) -> np.ndarray:
        """
        Vacuum fluctuation spectrum: <|E(w)|^2> = hw / 2.

        Args:
            frequency_range: Array of frequencies

        Returns:
            Vacuum fluctuation spectrum
        """
        spectrum = frequency_range / 2.0
        if self.dimensions > 1:
            spectrum = spectrum * frequency_range ** (self.dimensions - 1)
        return spectrum

    def quantum_stress_energy_tensor(
        self, metric: np.ndarray, quantum_state: np.ndarray = None
    ) -> np.ndarray:
        """
        Quantum stress-energy tensor <T_mu_nu>.

        Includes vacuum contribution and trace anomaly.

        Args:
            metric: Spacetime metric g_mu_nu
            quantum_state: Optional quantum field state

        Returns:
            Stress-energy tensor
        """
        dim = metric.shape[0]
        T = np.zeros_like(metric, dtype=complex)

        # Vacuum contribution
        rho_vac = 1e-120  # Observed cosmological constant in Planck units
        T += -rho_vac * metric

        # Trace anomaly
        anomaly_coeff = 1.0 / (2880 * np.pi ** 2)
        det_metric = np.linalg.det(metric)
        trace_anomaly = anomaly_coeff * (1 - det_metric)
        T += trace_anomaly * np.eye(dim) / dim

        # Quantum state contribution
        if quantum_state is not None:
            energy_density = np.abs(quantum_state) ** 2
            T[0, 0] += np.sum(energy_density)

        return T
