from __future__ import annotations

import threading
import time
from typing import Any, Callable, Optional

from pymulator.core.bus import CANBusEmulation

from .adapter import Adapter, AdapterOutputWriter, CommandSetHandler, ELM327, STN22xx
from .tcp import TCPServer


class DummyOutputWriter(AdapterOutputWriter):
    def write(self, output: str) -> None:
        return


def _load_startup_file(adapter: Adapter, path: str) -> None:
    try:
        with open(path, "r", encoding="utf-8") as handle:
            lines = handle.read().splitlines()
    except OSError:
        return

    def _run() -> None:
        adapter.output = DummyOutputWriter()
        time.sleep(0.001)
        for line in lines:
            if not line:
                continue
            adapter.feed_command(line)

    thread = threading.Thread(target=_run, daemon=True)
    thread.start()


class ELMService:
    def __init__(
        self,
        bus: CANBusEmulation,
        host: str,
        port: int,
        adapter_name: str = "ELM327/STN2xxx",
        startup_file: str = "",
        ati_version: str = "ELM327 1.4a",
        at1_descriptor: str = "OBDII to RS232 Interpreter",
        at2_name: str = "ELMpythonator",
        atign_state: str = "ON",
        atrv_voltage: str = "12.1V",
        sti_version: str = "STN2200 2.2.0",
        stix_version: str = "STN2200 2.2.0 [26.12.1971]",
        stsn_serial: str = "123456789012",
        stmfr_manufacturer: str = "OBD Solutions LLC",
        log_directory: str = "",
        event_sink: Optional[Callable[[dict[str, Any]], None]] = None,
    ) -> None:
        self.bus = bus
        self.adapter = Adapter(name=adapter_name)
        self.adapter.elm_ati_version = ati_version or "ELM327 1.4a"
        self.adapter.elm_at1_descriptor = at1_descriptor or "OBDII to RS232 Interpreter"
        self.adapter.elm_at2_name = at2_name or "ELMpythonator"
        self.adapter.elm_atign_state = _normalize_atign_state(atign_state)
        self.adapter.elm_atrv_voltage = atrv_voltage or "12.1V"
        self.adapter.stn_sti_version = sti_version or "STN2200 2.2.0"
        self.adapter.stn_stix_version = stix_version or "STN2200 2.2.0 [26.12.1971]"
        self.adapter.stn_stsn_serial = stsn_serial or "123456789012"
        self.adapter.stn_stmfr_manufacturer = stmfr_manufacturer or "OBD Solutions LLC"
        self.adapter.install_command_set(CommandSetHandler(ELM327()))
        self.adapter.install_command_set(CommandSetHandler(STN22xx()))
        if startup_file:
            _load_startup_file(self.adapter, startup_file)
        self.bus.attach(self.adapter)
        self.server = TCPServer(
            self.adapter,
            host=host,
            port=port,
            event_sink=event_sink,
            log_directory=log_directory,
        )

    def start(self) -> None:
        self.server.start()

    def stop(self) -> None:
        self.server.stop()

    def ui_snapshot(self) -> dict:
        return self.server.ui_snapshot()


def _normalize_atign_state(value: str) -> str:
    normalized = (value or "").strip().upper()
    return "OFF" if normalized == "OFF" else "ON"
