import csv
import os
from harnice import fileio

list_type = None
COLUMNS = []

# Signals list column headers to match source of truth + compatibility change
DEVICE_COLUMNS = [
    "channel_id",  # Unique identifier for the channel.
    "signal", # Name of the electrical function of that signal, as it pertains to its channel type defition. i.e. "positive"
    "connector_name", # Unique identifier for the connector that this signal and channel is a part of.
    "cavity", # Identifier of the pin, socket, stud, etc, that this signal is internally electrically routed to within its connector.
    "connector_mpn", #MPN of the connector in this device (NOT the mating connector).
    "channel_type",  #The channel type of this signal. \n{% include-markdown "fragments/channel_type_reference.md" %}
    "config_variable", #Change header or add more headers as needed. Blank: row is true across all values of this field. Otherwise, row is only true when configuration matches the value of this field.
]

DISCONNECT_COLUMNS = [
    "channel_id",  # Unique identifier for the channel.
    "signal",# Name of the electrical function of that signal, as it pertains to its channel type defition. i.e. "positive"
    "A_cavity", #Identifier of the pin, socket, stud, etc, that this signal is internally electrically routed to within that side of the connector.\n??? question "Why are A and B different here?"\n    Sometimes it's possible to have connectors that have cavities that may mate electrically, but have different names. For example, suppose two connectors physically mate, but are made by different manufacturers. One manufacturer used lowercase (a, b, c) to reference the cavities but the other used uppercase (A, B, C), or numbers (1, 2, 3), or colors (red, green, blue), etc.
    "B_cavity" #Identifier of the pin, socket, stud, etc, that this signal is internally electrically routed to within that side of the connector.\n??? question "Why are A and B different here?"\n    Sometimes it's possible to have connectors that have cavities that may mate electrically, but have different names. For example, suppose two connectors physically mate, but are made by different manufacturers. One manufacturer used lowercase (a, b, c) to reference the cavities but the other used uppercase (A, B, C), or numbers (1, 2, 3), or colors (red, green, blue), etc.
    "A_connector_mpn", #MPN of the connector of the harness on this side of the disconnect
    "A_channel_type", #The channel type of this side of the discconect.\n??? question "Why are A and B different here?"\n    It's important to keep track of which side has which channel type so that you cannot accidentally flip pins and sockets, for example, by mapping the wrong channel type to the wrong pin gender. Careful validation should be done when mapping channels through disconnects to ensure the disconnects have channels that pass through them in the correct direction.
    "B_connector_mpn",#MPN of the connector of the harness on this side of the disconnect
    "B_channel_type", #The channel type of this side of the discconect.\n??? question "Why are A and B different here?"\n    It's important to keep track of which side has which channel type so that you cannot accidentally flip pins and sockets, for example, by mapping the wrong channel type to the wrong pin gender. Careful validation should be done when mapping channels through disconnects to ensure the disconnects have channels that pass through them in the correct direction.
]


def set_list_type(x):
    global list_type
    list_type = x

    global COLUMNS
    if list_type == "device":
        COLUMNS = DEVICE_COLUMNS
    elif list_type == "disconnect":
        COLUMNS = DISCONNECT_COLUMNS


def new():
    """
    Creates a new signals TSV file at fileio.path("signals list") with only the header row.
    Overwrites any existing file.
    """
    signals_path = fileio.path("signals list")
    os.makedirs(os.path.dirname(signals_path), exist_ok=True)

    if os.path.exists(signals_path):
        os.remove(signals_path)

    with open(signals_path, "w", newline="", encoding="utf-8") as f:
        writer = csv.writer(f, delimiter="\t")
        writer.writerow(COLUMNS)


def append(**kwargs):
    """
    Appends a new row to the signals TSV file.
    Missing optional fields will be written as empty strings.
    Raises ValueError if required fields are missing.

    Required kwargs:
        For 'device':
            channel_id, signal, connector_name, cavity, connector_mpn, channel_type
        For 'disconnect':
            A_channel_id, A_signal, A_connector_name, A_cavity, A_connector_mpn, A_channel_type,
            B_channel_id, B_signal, B_connector_name, B_cavity, B_connector_mpn, B_channel_type
    """
    signals_path = fileio.path("signals list")

    # Create the signals list file if it doesn't exist
    if not os.path.exists(signals_path):
        new()

    # --- Define required fields based on product type ---
    if list_type == "device":
        required = [
            "channel_id",
            "signal",
            "connector_name",
            "cavity",
            "connector_mpn",
            "channel_type",
        ]
    elif list_type == "disconnect":
        required = [
            "channel_id",
            "signal",
            "A_cavity",
            "A_connector_mpn",
            "A_channel_type",
            "B_cavity",
            "B_connector_mpn",
            "B_channel_type",
        ]
    else:
        required = []

    # --- Check for missing required fields ---
    missing = [key for key in required if not kwargs.get(key)]
    if missing:
        raise ValueError(
            f"Missing required signal fields for '{list_type}': {', '.join(missing)}"
        )

    # --- Fill row in header order ---
    row = [kwargs.get(col, "") for col in COLUMNS]

    # --- Append to the signals list ---
    with open(signals_path, "a", newline="", encoding="utf-8") as f:
        writer = csv.writer(f, delimiter="\t", lineterminator="\n")
        writer.writerow(row)


def cavity_of_signal(channel_id, signal, path_to_signals_list):
    for row in fileio.read_tsv(path_to_signals_list):
        if row.get("signal", "").strip() == signal.strip():
            if row.get("channel_id", "").strip() == channel_id.strip():
                return row.get("cavity", "").strip()
    raise ValueError(
        f"Signal {signal} of channel_id {channel_id} not found in {path_to_signals_list}"
    )


def connector_name_of_channel(channel_id, path_to_signals_list):
    if not os.path.exists(path_to_signals_list):
        raise FileNotFoundError(f"Signals list file not found: {path_to_signals_list}")

    with open(path_to_signals_list, newline="", encoding="utf-8") as f:
        reader = csv.DictReader(f, delimiter="\t")
        for row in reader:
            if row.get("channel_id", "").strip() == channel_id.strip():
                return row.get("connector_name", "").strip()
