from __future__ import annotations
from abc import ABC, abstractmethod, abstractproperty
from typing import Any


class Builder(ABC):

    @abstractmethod
    def product(self)->None:
        pass

    def produce_part_a(self)->None:
        pass

    def produce_part_b(self)->None:
        pass

    def produce_part_c(self)->None:
        pass


class ConcreteBuilder1(Builder):

    def __init__(self)->None:
        self.reset()

    def reset(self)->None:
        self._product = Product1()

    @property
    def product(self)->Product1:
        product = self._product
        self.reset()
        return product

    def produce_part_a(self)->None:
        self._product.add("Part A1")

    def produce_part_b(self)->None:
        self._product.add("Part B1")

    def produce_part_c(self)->None:
        self._product.add("Part C1")


class Product1:

    def __init__(self)->None:
        self.parts = []

    def add(self, part:Any)->None:
        self.parts.append(part)

    def list_parts(self)->None:
        print("Product Parts: {}".format(", ".join(self.parts)))


class Director:

    def __init__(self)->None:
        self._builder = None

    @property
    def builder(self)->Builder:
        return self._builder

    @builder.setter
    def builder(self, builder:Builder)->None:
        self._builder = builder

    def build_minimal_viable_product(self)->None:
        self.builder.produce_part_a()

    def build_full_featured_product(self)->None:
        self.builder.produce_part_a()
        self.builder.produce_part_b()
        self.builder.produce_part_c()


if __name__ == "__main__":
    director = Director()
    builder = ConcreteBuilder1()
    director.builder = builder

    print("Standard basic product: ")
    director.build_minimal_viable_product()
    builder.product.list_parts()

    print("\n")

    director.build_full_featured_product()
    builder.product.list_parts()

    print("\n Custom Product: ")

    builder.produce_part_a()
    builder.produce_part_c()
    builder.product.list_parts()
