# This file is part of the faebryk project
# SPDX-License-Identifier: MIT

from enum import Enum, auto

import faebryk.core.node as fabll
import faebryk.library._F as F


class BJT(fabll.Node):
    # ----------------------------------------
    #                 enums
    # ----------------------------------------
    class DopingType(Enum):
        NPN = auto()
        PNP = auto()

    # TODO use this, here is more info: https://en.wikipedia.org/wiki/Bipolar_junction_transistor#Regions_of_operation
    class OperationRegion(Enum):
        ACTIVE = auto()
        INVERTED = auto()
        SATURATION = auto()
        CUT_OFF = auto()

    # ----------------------------------------
    #     modules, interfaces, parameters
    # ----------------------------------------
    emitter = F.Electrical.MakeChild()
    base = F.Electrical.MakeChild()
    collector = F.Electrical.MakeChild()

    doping_type = F.Parameters.EnumParameter.MakeChild(enum_t=DopingType)
    operation_region = F.Parameters.EnumParameter.MakeChild(enum_t=OperationRegion)

    # ----------------------------------------
    #                 traits
    # ----------------------------------------
    _is_module = fabll.Traits.MakeEdge(fabll.is_module.MakeChild())

    _can_attatch_to_footprint = fabll.Traits.MakeEdge(
        F.Footprints.can_attach_to_footprint.MakeChild()
    )

    # Create named lead fields so we can attach can_attach_to_pad_by_name to them
    emitter_lead = F.Lead.is_lead.MakeChild()
    base_lead = F.Lead.is_lead.MakeChild()
    collector_lead = F.Lead.is_lead.MakeChild()

    emitter.add_dependant(fabll.Traits.MakeEdge(emitter_lead, [emitter]))
    base.add_dependant(fabll.Traits.MakeEdge(base_lead, [base]))
    collector.add_dependant(fabll.Traits.MakeEdge(collector_lead, [collector]))

    # Attach pad name matchers to the lead fields (not to the Electrical nodes)
    emitter_lead.add_dependant(
        fabll.Traits.MakeEdge(
            F.Lead.can_attach_to_pad_by_name.MakeChild(regex=r"e|emitter"),
            [emitter_lead],
        )
    )
    base_lead.add_dependant(
        fabll.Traits.MakeEdge(
            F.Lead.can_attach_to_pad_by_name.MakeChild(regex=r"b|base"),
            [base_lead],
        )
    )
    collector_lead.add_dependant(
        fabll.Traits.MakeEdge(
            F.Lead.can_attach_to_pad_by_name.MakeChild(regex=r"c|collector"),
            [collector_lead],
        )
    )

    _can_bridge = fabll.Traits.MakeEdge(
        F.can_bridge.MakeChild(["collector"], ["emitter"])
    )

    designator_prefix = fabll.Traits.MakeEdge(
        F.has_designator_prefix.MakeChild(F.has_designator_prefix.Prefix.Q)
    )

    usage_example = fabll.Traits.MakeEdge(
        F.has_usage_example.MakeChild(
            example="""
        import BJT, Resistor, ElectricPower

        bjt = new BJT
        bjt.doping_type ="NPN"
        bjt.mpn = "C373737

        # Use as amplifier with bias resistors
        base_resistor = new Resistor
        collector_resistor = new Resistor
        power_supply = new ElectricPower

        # Basic amplifier configuration
        power_supply.hv ~> collector_resistor ~> bjt.collector
        bjt.emitter ~ power_supply.lv
        input_signal ~> base_resistor ~> bjt.base
        output_signal ~ bjt.collector
        """,
            language=F.has_usage_example.Language.ato,
        ).put_on_type()
    )
