"""
_____________________________________________________________________.

:PROJECT: LARAsuite

*lara_django_store views *

:details: lara_django_store views module.
         - add app specific urls here
         -
:authors: mark doerr <mark.doerr@uni-greifswald.de>

.. note:: -
.. todo:: -
________________________________________________________________________
"""
from typing import Any
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import HttpResponse
from django.shortcuts import get_object_or_404, redirect
from django.views.generic import CreateView, DeleteView, DetailView, TemplateView, UpdateView, View
from django_tables2 import RequestConfig


class BaseStoreView:
    """Base mixin for all material store views."""

    @property
    def item_type(self) -> str:
        """Override in subclasses: 'device', 'part', 'labware'."""
        raise NotImplementedError("Subclasses must define item_type")

    @property
    def model_class(self) -> type:
        """Override in subclasses to return the main model class."""
        raise NotImplementedError("Subclasses must define model_class")

    @property
    def basket_class(self) -> type:
        """Override in subclasses to return the basket model class."""
        raise NotImplementedError("Subclasses must define basket_class")

    @property
    def order_class(self) -> type:
        """Override in subclasses to return the order model class."""
        raise NotImplementedError("Subclasses must define order_class")

    @property
    def order_item_class(self) -> type:
        """Override in subclasses to return the order item model class."""
        raise NotImplementedError("Subclasses must define order_item_class")

    def get_base_context(self, **kwargs: Any) -> dict[str, Any]:
        """Get common context data for all views."""
        context: dict[str, Any] = super().get_context_data(**kwargs) if hasattr(super(), "get_context_data") else {}  # type: ignore[misc]
        context["menu_items"] = []  # StoreMenu.menu_items
        context["list_url"] = f"lara_django_material_store:{self.item_type}-list"
        context["create_url"] = f"lara_django_material_store:{self.item_type}-create"
        context["baskets_url"] = f"lara_django_material_store:{self.item_type}-baskets"
        context["orders_url"] = f"lara_django_material_store:{self.item_type}-orders"
        return context


class BaseListView(BaseStoreView, TemplateView):
    """Generic list view for all item types."""

    template_name = "lara_django_material_store/list.html"

    def get_context_data(self, **kwargs: Any) -> dict[str, Any]:  # noqa: D102
        context = self.get_base_context(**kwargs)
        context["section_title"] = f"{self.item_type.title()} Store - List"

        # Get baskets for current user
        context["baskets"] = self.basket_class.objects.filter(entity=self.request.user.entity).order_by("name_display")  # type: ignore[attr-defined]

        # Set current basket
        basket_id = self.kwargs.get("basket_id")
        if basket_id and self.basket_class.objects.filter(entity=self.request.user.entity, pk=basket_id).exists():  # type: ignore[attr-defined]
            context["current_basket"] = self.basket_class.objects.get(pk=basket_id)  # type: ignore[attr-defined]
        else:
            context["current_basket"] = (
                self.basket_class.objects.filter(entity=self.request.user.entity)  # type: ignore[attr-defined]
                .order_by("datetime_last_modified")
                .last()
            )

        # Get items and create table pairs
        items = self.get_items_for_list()
        context[f"{self.item_type}_table_pairs"] = self.create_table_pairs(items)

        return context

    def get_items_for_list(self) -> list[Any]:
        """Override in subclasses to define how to get items."""
        raise NotImplementedError("Subclasses must implement get_items_for_list")

    def create_table_pairs(self, items: Any) -> list[Any]:
        """Override in subclasses to create table pairs."""
        raise NotImplementedError("Subclasses must implement create_table_pairs")


class BaseDetailView(BaseStoreView, DetailView):
    """Generic detail view for all item types."""

    template_name = "lara_django_material_store/detail.html"

    def get_context_data(self, **kwargs: Any) -> dict[str, Any]:  # noqa: D102
        context = self.get_base_context(**kwargs)
        context["section_title"] = f"{self.item_type.title()} Store - Details"
        context["update_link"] = f"lara_django_material_store:{self.item_type}-update"
        return context


class BaseCreateView(BaseStoreView, LoginRequiredMixin, CreateView):
    """Generic create view for all item types."""

    template_name = "lara_django_material_store/create_form.html"

    def get_success_url(self) -> str:  # noqa: D102
        return f"/material-store/{self.item_type}/list"

    def get_context_data(self, **kwargs: Any) -> dict[str, Any]:  # noqa: D102
        context = self.get_base_context(**kwargs)
        context["section_title"] = f"{self.item_type.title()} Store - Create"
        return context


class BaseUpdateView(BaseStoreView, LoginRequiredMixin, UpdateView):
    """Generic update view for all item types."""

    template_name = "lara_django_material_store/update_form.html"

    def get_success_url(self) -> str:  # noqa: D102
        return f"/material-store/{self.item_type}/list"

    def get_context_data(self, **kwargs: Any) -> dict[str, Any]:  # noqa: D102
        context = self.get_base_context(**kwargs)
        context["section_title"] = f"{self.item_type.title()} Store - Update"
        context["delete_link"] = f"lara_django_material_store:{self.item_type}-delete"
        return context


class BaseDeleteView(BaseStoreView, LoginRequiredMixin, DeleteView):
    """Generic delete view for all item types."""

    template_name = "lara_django_material_store/delete_form.html"

    def get_success_url(self) -> str:  # noqa: D102
        return f"/material-store/{self.item_type}/list"

    def get_context_data(self, **kwargs: Any) -> dict[str, Any]:  # noqa: D102
        context = self.get_base_context(**kwargs)
        context["section_title"] = f"{self.item_type.title()} Store - Delete"
        return context


class BaseBasketsView(BaseStoreView, LoginRequiredMixin, TemplateView):
    """Generic baskets view for all item types."""

    template_name = "lara_django_material_store/baskets.html"

    def get_context_data(self, **kwargs: Any) -> dict[str, Any]:  # noqa: D102
        context = self.get_base_context(**kwargs)
        context["section_title"] = f"{self.item_type.title()} Store - Baskets"

        baskets = self.basket_class.objects.filter(entity=self.request.user.entity).prefetch_related(  # type: ignore[attr-defined]
            f"{self.item_type}orderitem_set"
        )

        if not baskets.exists():
            return context

        basket_table_pairs = []
        for basket in baskets:
            basket.save()
            table = self.get_basket_table_class()(getattr(basket, f"{self.item_type}orderitem_set").all())
            RequestConfig(self.request).configure(table)
            basket_table_pairs.append({"basket": basket, "table": table})

        context["basket_table_pairs"] = basket_table_pairs
        return context

    def get_basket_table_class(self) -> type:
        """Override in subclasses to return the appropriate table class."""
        raise NotImplementedError("Subclasses must implement get_basket_table_class")


class BaseAddToBasketView(BaseStoreView, LoginRequiredMixin, View):
    """Generic add to basket view for all item types."""

    def get(self, request: Any, pk: Any, basket_id: Any, *args: Any, **kwargs: Any) -> Any:  # noqa: D102
        item = get_object_or_404(self.model_class, pk=pk)
        basket = get_object_or_404(self.basket_class, entity=request.user.entity, pk=basket_id)
        basket.add_item_instance(item)  # This method needs to be standardized
        return redirect(f"lara_django_material_store:{self.item_type}-list")


class BaseBasketAdjustQuantityView(BaseStoreView, LoginRequiredMixin, TemplateView):
    """Generic quantity adjustment view for all item types."""

    def post(self, request: Any) -> HttpResponse:  # noqa: D102
        item_id = request.POST.get(f"{self.item_type}_order_item_id")
        action = request.POST.get("action")

        item = get_object_or_404(
            self.order_item_class, pk=item_id, **{f"{self.item_type}_basket__entity": request.user.entity}
        )
        basket = getattr(item, f"{self.item_type}_basket")

        if action == "increase":
            item.quantity += 1
        elif action == "decrease":
            item.quantity = max(1, item.quantity - 1)
        item.save()

        table = self.get_basket_table_class()(
            self.order_item_class.objects.filter(**{f"{self.item_type}_basket": basket})  # type: ignore[attr-defined]
        )
        RequestConfig(request).configure(table)
        table_html = table.as_html(request)

        response_html = f"""
            <div class="table-container">{table_html}</div>
            <span id='total-price-{basket.pk}' hx-swap-oob='true'>{basket.total_price_net}</span>
        """
        return HttpResponse(response_html)
