"""Решение задачи про классы и наследование"""

from csv import reader
from functools import reduce
from os.path import splitext
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from typing import List


class CarBase:
    """Базовый класс для автомобилей и спецтехники"""

    def __init__(
        self,
        brand: "str",
        photo_file_name: "str",
        carrying: "float",
        car_type: "str" = "car",
    ):
        """Конструктор базового класса"""

        self.brand: "str" = brand
        self.photo_file_name: "str" = photo_file_name
        self.carrying: "float" = carrying
        self.__car_type: "str" = car_type

    def __repr__(self) -> "str":
        """Строковое представления объекта"""

        return f"{self.car_type}: {self.brand} {self.carrying}"

    @property
    def car_type(self) -> "str":
        """Тип автомобиля или спецтехники"""

        return self.__car_type

    def get_photo_file_ext(self) -> "str":
        """Предоставляет расширение файла с фото"""

        return splitext(self.photo_file_name)[1]


class Car(CarBase):
    """Класс легковых автомобилей"""

    def __init__(
        self,
        brand: "str",
        photo_file_name: "str",
        carrying: "float",
        passenger_seats_count: "int",
    ):
        """Конструктор класса легковых автомобилей"""

        super().__init__(brand, photo_file_name, carrying)
        self.passenger_seats_count: "int" = passenger_seats_count


class Truck(CarBase):
    """Класс грузовых автомобилей"""

    def __init__(
        self,
        brand: "str",
        photo_file_name: "str",
        carrying: "float",
        body_whl: "str",
    ):
        """Конструктор класса грузовых автомобилей"""

        super().__init__(brand, photo_file_name, carrying, "truck")

        self.body_width: "float" = 0.0
        self.body_height: "float" = 0.0
        self.body_length: "float" = 0.0

        if body_whl:
            try:
                self.body_width, self.body_height, self.body_length = tuple(
                    map(float, body_whl.split("x", maxsplit=2))
                )

            except ValueError as error:
                raise ValueError(
                    "Invalid format argument body_whl."
                ) from error

    def get_body_volume(self) -> "float":
        """Возвращает объем кузова в метрах кубических"""

        return reduce(
            lambda x, y: x * y,
            (self.body_width, self.body_height, self.body_length),
        )


class SpecMachine(CarBase):
    """Класс спецтехники"""

    def __init__(
        self,
        brand: "str",
        photo_file_name: "str",
        carrying: "float",
        extra: "str",
    ):
        """Конструктор класса спецтехники"""

        super().__init__(brand, photo_file_name, carrying, "spec_machine")
        self.extra: "str" = extra


def get_car_list(csv_filename: "str") -> "List[CarBase]":
    """Чтение данных из csv файла и представление их в виде списка объектов"""

    car_list: "List[CarBase]" = []

    with open(csv_filename, encoding="UTF-8") as csv_fd:
        for i, row in enumerate(reader(csv_fd, delimiter=";")):
            if i and len(row) == 7:
                try:
                    if row[0] == "car":
                        car_list.append(
                            Car(row[1], row[3], float(row[5]), int(row[2]))
                        )

                    elif row[0] == "truck":
                        car_list.append(
                            Truck(row[1], row[3], float(row[5]), row[4])
                        )

                    elif row[0] == "spec_machine":
                        car_list.append(
                            SpecMachine(row[1], row[3], float(row[5]), row[6])
                        )
                except ValueError:
                    continue

    return car_list
