import shutil
import glob
import subprocess
import pydantic
import pathlib
import ctypes
import os
import sys
import logging
import dataclasses

logger = logging.getLogger(__name__)

from typing import (
	overload,
	Optional,
	Literal,
	Any,
	Annotated,
)

from .cli_bootstrap import PyProject


@overload
def shutil_which(
	name: str,
	raise_on_failure: Literal[True],
) -> str: ...


@overload
def shutil_which(
	name: str,
	raise_on_failure: bool,
) -> Optional[str]: ...


def shutil_which(
	name: str,
	raise_on_failure: bool,
) -> Optional[str]:
	res = shutil.which(name)
	if res is None and raise_on_failure:
		raise NotImplementedError
	else:
		return res


def runtime_libdirs_init(
	project: PyProject,
) -> None:
	if sys.platform == 'linux':
		ld_library_path: list[pathlib.Path] = [
			o
			for o in [
				*[o.absolute() for o in (project.runtime_libdirs if project.runtime_libdirs else [])],
				*[pathlib.Path(o) for o in os.environ.get('LD_LIBRARY_PATH', '').split(os.path.pathsep) if o != ''],
			]
		]

		ld_library_path_present: list[pathlib.Path] = []

		for o in ld_library_path:
			if not o.exists():
				logger.warning(
					dict(
						ld_library_path=o,
						msg='not found',
					)
				)

			ld_library_path_present.append(o)

		os.environ.update(LD_LIBRARY_PATH=os.path.pathsep.join([str(o) for o in ld_library_path_present]))

		for preload_path in project.runtime_preload or []:
			for preload_found in glob.glob(str(preload_path.parent / ('lib%s.so' % preload_path.name))):
				logger.info(
					dict(
						preload_path=preload_path,
						preload_found=preload_found,
						# lib_path=o,
						msg='load_library',
					)
				)

				ctypes.cdll.LoadLibrary(preload_found)
	else:
		raise NotImplementedError


class interfaces_index_t:
	@dataclasses.dataclass
	class Interface:
		@dataclasses.dataclass
		class AddrInfo:
			family: str
			local: str

		name: Annotated[
			str,
			pydantic.Field(
				alias='ifname',
			),
		]
		addr_info: list[AddrInfo]


def interfaces_index() -> list[interfaces_index_t.Interface]:
	res = (
		pydantic.RootModel[list[interfaces_index_t.Interface]]
		.model_validate_json(
			subprocess.check_output(
				[
					'ip',
					'-j',
					'addr',
				]
			).decode('utf-8')
		)
		.root
	)

	return res


def shutil_rmtree(
	path: pathlib.Path,
	preserve_top_path: bool = False,
) -> None:
	if preserve_top_path:
		for p in path.iterdir():
			if p.is_dir():
				shutil.rmtree(str(p))
			else:
				p.unlink()
	else:
		shutil.rmtree(str(path))
