# -*- coding: utf-8 -*-

# Copyright (c) 2016-2026 by University of Kassel and Fraunhofer Institute for Energy Economics
# and Energy System Technology (IEE), Kassel. All rights reserved.

from __future__ import annotations

import logging

from numpy import nan, bool_

from pandapower.auxiliary import pandapowerNet
from pandapower.pp_types import Int
from pandapower.create._utils import (
    _check_element,
    _get_index_with_check,
    _set_entries,
    _set_value_if_not_nan,
)

logger = logging.getLogger(__name__)


def create_ext_grid(
    net: pandapowerNet,
    bus: Int,
    vm_pu: float = 1.0,
    va_degree: float = 0.0,
    name: str | None = None,
    in_service: bool = True,
    s_sc_max_mva: float = nan,
    s_sc_min_mva: float = nan,
    rx_max: float = nan,
    rx_min: float = nan,
    max_p_mw: float = nan,
    min_p_mw: float = nan,
    max_q_mvar: float = nan,
    min_q_mvar: float = nan,
    index: Int | None = None,
    r0x0_max: float = nan,
    x0x_max: float = nan,
    controllable: bool | float = nan,
    slack_weight: float = 1.0,
    **kwargs,
) -> Int:
    """
    Creates an external grid connection.

    External grids represent the higher level power grid connection and are modelled as the slack
    bus in the power flow calculation.

    Parameters:
        net: pandapower network
        bus: bus where the slack is connected
        vm_pu: voltage at the slack node in per unit
        va_degree: voltage angle at the slack node in degrees*
        name: name of the external grid
        in_service: True for in_service or False for out of service
        s_sc_max_mva: maximum short circuit apparent power to calculate internal impedance of ext_grid for short circuit
            calculations
        s_sc_min_mva: minimum short circuit apparent power to calculate internal impedance of ext_grid for short circuit
            calculations
        rx_max: maximum R/X-ratio to calculate internal impedance of ext_grid for short circuit calculations
        rx_min: minimum R/X-ratio to calculate internal impedance of ext_grid for short circuit calculations
        max_p_mw: Maximum active power injection. Only respected for OPF
        min_p_mw: Minimum active power injection. Only respected for OPF
        max_q_mvar: Maximum reactive power injection. Only respected for OPF
        min_q_mvar: Minimum reactive power injection. Only respected for OPF
        index: The index to use if available
        r0x0_max: maximum R/X-ratio to calculate Zero sequence internal impedance of ext_grid
        x0x_max: maximum X0/X-ratio to calculate Zero sequence internal impedance of ext_grid
        slack_weight: Contribution factor for distributed slack power flow calculation (active power balancing)
        controllable: Control of value limits
        
            - True: p_mw, q_mvar and vm_pu limits are enforced for the ext_grid in OPF. The voltage limits set in the \
            ext_grid bus are enforced.
            - False: p_mw and vm_pu set points are enforced and *limits are ignored*. The vm_pu set point is enforced \
            and limits of the bus table are ignored. Defaults to False if "controllable" column exists in DataFrame

            \\* considered in load flow if calculate_voltage_angles = True
        
        **kwargs: Additional keyword arguments

    Example:
        >>> create_ext_grid(net, 1, voltage=1.03)
        
        For three phase load flow

        >>> create_ext_grid(net, 1, voltage=1.03, s_sc_max_mva=1000, rx_max=0.1, r0x0_max=0.1, x0x_max=1.0)
    """
    _check_element(net, bus)

    index = _get_index_with_check(net, "ext_grid", index, name="external grid")

    entries = {
        "name": name,
        "bus": bus,
        "vm_pu": vm_pu,
        "va_degree": va_degree,
        "in_service": in_service,
        "slack_weight": slack_weight,
        **kwargs,
    }
    _set_entries(net, "ext_grid", index, entries=entries)

    # OPF limits
    _set_value_if_not_nan(net, index, min_p_mw, "min_p_mw", "ext_grid")
    _set_value_if_not_nan(net, index, max_p_mw, "max_p_mw", "ext_grid")
    _set_value_if_not_nan(net, index, min_q_mvar, "min_q_mvar", "ext_grid")
    _set_value_if_not_nan(net, index, max_q_mvar, "max_q_mvar", "ext_grid")
    _set_value_if_not_nan(net, index, controllable, "controllable", "ext_grid", dtype=bool_, default_val=False)
    # others
    _set_value_if_not_nan(net, index, x0x_max, "x0x_max", "ext_grid")
    _set_value_if_not_nan(net, index, r0x0_max, "r0x0_max", "ext_grid")
    _set_value_if_not_nan(net, index, s_sc_max_mva, "s_sc_max_mva", "ext_grid")
    _set_value_if_not_nan(net, index, s_sc_min_mva, "s_sc_min_mva", "ext_grid")
    _set_value_if_not_nan(net, index, rx_min, "rx_min", "ext_grid")
    _set_value_if_not_nan(net, index, rx_max, "rx_max", "ext_grid")

    return index
