import re
import json
import os
import unicodedata

from opendbc.car import gen_empty_fingerprint
from opendbc.car.common.basedir import BASEDIR
from opendbc.car.docs import get_all_footnotes
from opendbc.car.structs import CarParams
from opendbc.car.car_helpers import interfaces
from opendbc.car.mock.values import CAR as MOCK
from opendbc.car.values import PLATFORMS

CAR_LIST_JSON_OUT = os.path.join(BASEDIR, "../", "sunnypilot", "car", "car_list.json")


def _get_params_for_docs_sp(platform) -> tuple[CarParams, object]:
  cp_platform = platform if platform in interfaces else MOCK.MOCK
  CP: CarParams = interfaces[cp_platform].get_params(cp_platform, fingerprint=gen_empty_fingerprint(),
                                                     car_fw=[CarParams.CarFw(ecu=CarParams.Ecu.unknown)],
                                                     alpha_long=True, is_release=False, docs=True)
  CP_SP = interfaces[cp_platform].get_params_sp(CP, cp_platform, fingerprint=gen_empty_fingerprint(),
                                                car_fw=[CarParams.CarFw(ecu=CarParams.Ecu.unknown)],
                                                alpha_long=True, is_release_sp=True, docs=True)
  return CP, CP_SP


def get_car_list() -> dict[str, dict[str, list[str] | str]]:
  collected_footnote = get_all_footnotes()
  sorted_list: dict[str, dict[str, list[str] | str]] = build_sorted_car_list(PLATFORMS, collected_footnote)
  return sorted_list


def _natural_sort_key(s):
  # NFKD normalization ensures accented characters sort with their base letter (e.g., Š sorts with S)
  normalized = unicodedata.normalize('NFKD', s)
  return [int(t) if t.isdigit() else t.lower() for t in re.split(r'(\d+)', normalized) if t]


def build_sorted_car_list(platforms, footnotes) -> dict[str, dict[str, list[str] | str]]:
  cars: dict[str, dict[str, list[str] | str]] = {}
  for model, platform in platforms.items():
    car_docs = platform.config.get_all_docs()
    CP, CP_SP = _get_params_for_docs_sp(platform)

    if CP.dashcamOnly or not len(car_docs):
      continue

    # A platform can include multiple car models
    for _car_docs in car_docs:
      if not hasattr(_car_docs, "row"):
        _car_docs.init_make(CP)
        _car_docs.init(CP, footnotes)
      cars[_car_docs.name] = model

      _platform = model
      _name = _car_docs.name
      _make = _car_docs.make
      _brand = _car_docs.brand
      _model = _car_docs.model
      _years = _car_docs.year_list
      _package = _car_docs.package if _car_docs.package else []

      cars[_name] = {
        "platform": _platform,
        "make": _make,
        "brand": _brand,
        "model": _model,
        "year": _years if _years else [],
        "package": _package,
      }

  # Sort cars by make and model + year
  sorted_cars = sorted(cars.keys(), key=lambda car: _natural_sort_key(car))
  sorted_car_list = {car: cars[car] for car in sorted_cars}
  return sorted_car_list


if __name__ == "__main__":
  platform_list = get_car_list()

  with open(CAR_LIST_JSON_OUT, "w") as json_file:
    json.dump(platform_list, json_file, indent=2, ensure_ascii=False)
  print(f"Generated and written to {CAR_LIST_JSON_OUT}")
