#!/usr/bin/env python
import argparse
import datetime
import json
import os
import pathlib
import sys
import typing


class ThinkfanConfig(typing.TypedDict):
    sensors: list[dict[str, str]]
    fans: list[dict[str, str]]
    levels: list[dict[str, int | list[int]]]


def main(sysargs=sys.argv[:]) -> int:
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "-l",
        "--lower-bound",
        default=int(os.environ.get("THINKFAN_LOWER_BOUND", "30")),
        type=int,
        help="lower bound of sensor value for min fan speed (THINKFAN_LOWER_BOUND)",
    )
    parser.add_argument(
        "-u",
        "--upper-bound",
        default=int(os.environ.get("THINKFAN_UPPER_BOUND", "32767")),
        type=int,
        help="upper bound of sensor value for max fan speed (THINKFAN_UPPER_BOUND)",
    )
    parser.add_argument(
        "-s",
        "--step",
        default=int(os.environ.get("THINKFAN_STEP", "4")),
        type=int,
        help="step size between fan speed levels (THINKFAN_STEP)",
    )
    args = parser.parse_args(sysargs[1:])

    cfg: ThinkfanConfig = {
        "sensors": [],
        "fans": [],
        "levels": [],
    }

    acpi_fan = pathlib.Path("/proc/acpi/ibm/fan")
    if acpi_fan.exists():
        cfg["fans"].append({"tpacpi": str(acpi_fan)})

    acpi_thermal = pathlib.Path("/proc/acpi/ibm/thermal")

    n_sensors: int = 0

    if acpi_thermal.exists():
        cfg["sensors"].append({"tpacpi": str(acpi_thermal)})
        n_sensors = len(
            [
                l
                for l in acpi_thermal.read_text().splitlines()
                if l.startswith("temperatures:")
            ][0]
            .split(":")[1]
            .strip()
            .split()
        )

    else:
        for dirpath, dirnames, filenames in pathlib.Path("/sys/devices").walk(
            on_error=print, follow_symlinks=False
        ):
            if "thinkpad_hwmon" in dirnames:
                dirnames.remove("thinkpad_hwmon")

            for filename in filenames:
                if filename.startswith("temp") and filename.endswith("_input"):
                    cfg["sensors"].append({"hwmon": str(dirpath.joinpath(filename))})

                    n_sensors += 1

    cur: int = args.lower_bound
    step: int = args.step
    halfstep = step // 2

    for level in range(8):
        if level == 0:
            cfg["levels"].append(
                {
                    "speed": 0,
                    "lower_limit": [0] * n_sensors,
                    "upper_limit": [cur] * n_sensors,
                }
            )

            continue

        if level == 7:
            cfg["levels"].append(
                {
                    "speed": 7,
                    "upper_limit": [args.upper_bound] * n_sensors,
                    "lower_limit": [cur - halfstep] * n_sensors,
                }
            )

            continue

        cfg["levels"].append(
            {
                "speed": level,
                "lower_limit": [cur - halfstep] * n_sensors,
                "upper_limit": [cur + step] * n_sensors,
            },
        )

        cur += step

    print(f"# thinkfan_confgen.py created {datetime.datetime.now(datetime.UTC)}")
    print(json.dumps(cfg))

    return 0


if __name__ == "__main__":
    sys.exit(main())
