import csv
import os
import pprint
import subprocess

from base import Write

SCRIPT = os.path.relpath(__file__, os.getcwd()).replace("\\", "/")


def match_filter(filter: str, name: str) -> bool:
    if filter == "UART":
        return name.startswith("UART") or name.startswith("USART")
    return name.startswith(filter)


FUNC_TABLE = {
    "TX": "Tx",
    "RX": "Rx",
}


TEMPLATE = """impl DmaBind{func}<pac::{peri}> for {dma}::{ch} {{}}
"""


def write_item(dma: str, ch: str, func: str, w: Write) -> None:
    ch = ch.replace("ch", "C")
    (peri, func) = func.split("_", 1)
    func = FUNC_TABLE.get(func, "")
    w.write(TEMPLATE.format(func=func, peri=peri, dma=dma, ch=ch))


def write_table(d: dict, filter: str, w: Write) -> None:
    w.write("\n")
    for dma, ch_table in sorted(d.items()):
        for ch, func_list in sorted(ch_table.items()):
            for func in sorted(func_list):
                if match_filter(filter, func):
                    write_item(dma, ch, func, w)


def parse_dma_info(row: list[str], ret_d: dict) -> None:
    dma = row[0]
    channel = row[1]
    func_list: list[str] = []
    for func in row[2:]:
        if func:
            func_list.append(func)

    p = ret_d.setdefault(dma, {})
    p[channel] = func_list


def csv_to_code(csv_file: str, show: bool = False) -> None:
    print(csv_file)
    d: dict = {}
    with open(csv_file, newline="", encoding="utf-8") as f:
        reader = csv.reader(f, delimiter=",", quotechar='"')
        for row in reader:
            if row[0]:
                parse_dma_info(row, d)

    if show:
        pprint.pprint(d)

    target_file = "src/dma.rs"
    with open(target_file, "r", encoding="utf-8") as f:
        code = f.read()
        i = code.find("// table") + len("// table")
        before = code[:i]
        code = code[i:]

    w = Write(target_file)
    w.write(before)
    w.write("\n// Do NOT manually modify the code.\n")
    w.write(
        f"// It's generated by {SCRIPT} from {csv_file}\n",
    )

    write_table(d, "UART", w)
    write_table(d, "SPI", w)
    write_table(d, "I2C", w)

    w.close()
    subprocess.run(["rustfmt", target_file])


if __name__ == "__main__":
    csv_to_code("scripts/table/stm32f1_dma_table.csv")
