from django.contrib import messages
from django.contrib.auth import login
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.views import LoginView, LogoutView
from django.db import models
from django.db.models import Case, When, F, FloatField, Q
from django.db.models.functions import NullIf, Coalesce
from django.shortcuts import render, redirect, get_object_or_404
from django.urls import reverse_lazy
from django.views.generic import TemplateView, DetailView, CreateView, UpdateView, ListView
from django.views.generic.edit import ProcessFormView

from groceries.forms import CreateShoppingListForm, AddItemToShoppingListForm, EditShoppingListItemForm, ItemCategoryForm, ItemForm
from groceries.models import ShoppingList, ShoppingListItem, ItemCategory, Item


# Create your views here.

class CustomLoginView(LoginView):
    template_name = 'groceries/login.html'
    
    def dispatch(self, request, *args, **kwargs):
        # Pokud je uživatel už přihlášen, přesměruj ho na hlavní stránku
        if request.user.is_authenticated:
            return redirect('grocery_index')
        return super().dispatch(request, *args, **kwargs)
    
    def form_valid(self, form):
        messages.add_message(self.request, messages.SUCCESS, "Byli jste úspěšně přihlášeni.")
        return super().form_valid(form)


class CustomLogoutView(LogoutView):
    def dispatch(self, request, *args, **kwargs):
        messages.add_message(request, messages.INFO, "Byli jste úspěšně odhlášeni.")
        return super().dispatch(request, *args, **kwargs)


class GroceryIndex(LoginRequiredMixin, TemplateView):
    template_name = "groceries/index.html"

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        total_items_count = models.Count('items')
        checked_items_count = models.Count('items', filter=models.Q(items__checked=True))
        
        shopping_list = ShoppingList.objects.filter(is_template=False, is_archived=False).annotate(
            total_items_count=total_items_count,
            checked_items_count=checked_items_count
        ).annotate(
            pct_done=Case(
                When(total_items_count=0, then=0.0),
                default=Coalesce(
                    F('checked_items_count') * 100.0 / NullIf(F('total_items_count'), 0),
                    0.0
                ),
                output_field=FloatField()
            )
        ).order_by('-created_at')
        template_list = ShoppingList.objects.filter(is_template=True).order_by('-created_at')
        total_items = 0
        for sl in shopping_list:
            total_items += sl.items.count()

        context.update(
            shopping_list=shopping_list,
            total_items=total_items,
            template_list=template_list,
            create_form=CreateShoppingListForm(),
        )
        return context


class GroceryIndexV2(LoginRequiredMixin, TemplateView):
    template_name = "groceries/index_v2.html"

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        total_items_count = models.Count('items')
        checked_items_count = models.Count('items', filter=models.Q(items__checked=True))
        
        shopping_list = ShoppingList.objects.filter(is_template=False, is_archived=False).annotate(
            total_items_count=total_items_count,
            checked_items_count=checked_items_count
        ).annotate(
            pct_done=Case(
                When(total_items_count=0, then=0.0),
                default=Coalesce(
                    F('checked_items_count') * 100.0 / NullIf(F('total_items_count'), 0),
                    0.0
                ),
                output_field=FloatField()
            )
        ).order_by('-created_at')
        template_list = ShoppingList.objects.filter(is_template=True).order_by('-created_at')
        total_items = 0
        for sl in shopping_list:
            total_items += sl.items.count()

        context.update(
            shopping_list=shopping_list,
            total_items=total_items,
            template_list=template_list,
            create_form=CreateShoppingListForm(),
        )
        return context

class ArchivedGroceryIndex(LoginRequiredMixin, TemplateView):
    template_name = "groceries/archived_index.html"

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        archived_shopping_list = ShoppingList.objects.filter(is_template=False, is_archived=True).order_by('-created_at')
        context.update(
            archived_shopping_list=archived_shopping_list,
        )
        return context


class ShoppingListDetailView(LoginRequiredMixin, DetailView):
    model = ShoppingList
    template_name = "groceries/shopping_list_detail.html"
    context_object_name = "shopping_list"
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['add_item_form'] = AddItemToShoppingListForm()
        # Vytvoříme formuláře pro editaci každé položky
        edit_forms = {}
        for item in self.object.items.all():
            edit_forms[item.id] = EditShoppingListItemForm(instance=item)
        context['edit_forms'] = edit_forms
        return context


class MarkShoppingListCheckedView(LoginRequiredMixin, ProcessFormView):
    def post(self, request, *args, **kwargs):
        shopping_list_id = kwargs.get('shopping_list_id')
        shopping_list = ShoppingList.objects.get(id=shopping_list_id)
        shopping_list.items.update(checked=True)
        messages.add_message(request, messages.INFO,
                             f"Všechny položky v seznamu '{shopping_list.name}' byly zaškrtnuty.")
        # redirect to ShoppingListDetailView
        return redirect('shopping_list_detail', pk=shopping_list_id)

    def get(self, request, *args, **kwargs):
        return redirect('shopping_list_detail', pk=kwargs.get('shopping_list_id'))


class MarkShoppingListUnCheckedView(LoginRequiredMixin, ProcessFormView):
    def post(self, request, *args, **kwargs):
        shopping_list_id = kwargs.get('shopping_list_id')
        shopping_list = ShoppingList.objects.get(id=shopping_list_id)
        shopping_list.items.update(checked=False)
        messages.add_message(request, messages.INFO,
                             f"Všechny položky v seznamu '{shopping_list.name}' byly odškrtnuty.")
        # redirect to ShoppingListDetailView
        return redirect('shopping_list_detail', pk=shopping_list_id)

    def get(self, request, *args, **kwargs):
        return redirect('shopping_list_detail', pk=kwargs.get('shopping_list_id'))

class MarkShoppingListArchivedView(LoginRequiredMixin, ProcessFormView):
    def post(self, request, *args, **kwargs):
        shopping_list_id = kwargs.get('shopping_list_id')
        shopping_list = ShoppingList.objects.get(id=shopping_list_id)
        shopping_list.is_archived = True
        shopping_list.save()
        messages.add_message(request, messages.INFO,
                             f"Nákupní seznam '{shopping_list.name}' byl archivován.")
        # redirect to GroceryIndex
        return redirect('grocery_index')

    def get(self, request, *args, **kwargs):
        return redirect('grocery_index')

class MarkShoppingListUnArchivedView(LoginRequiredMixin, ProcessFormView):
    def post(self, request, *args, **kwargs):
        shopping_list_id = kwargs.get('shopping_list_id')
        shopping_list = ShoppingList.objects.get(id=shopping_list_id)
        shopping_list.is_archived = False
        shopping_list.save()
        messages.add_message(request, messages.INFO,
                             f"Nákupní seznam '{shopping_list.name}' byl znovu aktivován.")
        # redirect to ArchivedGroceryIndex
        return redirect('archived_index')

    def get(self, request, *args, **kwargs):
        return redirect('archived_index')

class DuplicateShoppingListView(LoginRequiredMixin, ProcessFormView):
    def post(self, request, *args, **kwargs):
        shopping_list_id = kwargs.get('shopping_list_id')
        shopping_list = ShoppingList.objects.get(id=shopping_list_id)
        # Create a duplicate of the shopping list
        shopping_list.pk = None  # This will create a new instance when saved
        shopping_list.name = f"{shopping_list.name} (kopie)"
        shopping_list.is_archived = False
        shopping_list.save()
        # Duplicate items
        for item in ShoppingList.objects.get(id=shopping_list_id).items.all():
            item.pk = None
            item.shopping_list = shopping_list
            item.checked = False
            item.save()
        messages.add_message(request, messages.INFO,
                             f"Nákupní seznam '{shopping_list.name}' byl duplikován.")
        # redirect to GroceryIndex
        return redirect('grocery_index')

    def get(self, request, *args, **kwargs):
        return redirect('grocery_index')

class DuplicateAsTemplateView(LoginRequiredMixin, ProcessFormView):
    def post(self, request, *args, **kwargs):
        shopping_list_id = kwargs.get('shopping_list_id')
        shopping_list = ShoppingList.objects.get(id=shopping_list_id)
        # Create a duplicate of the shopping list as a template
        shopping_list.pk = None  # This will create a new instance when saved
        shopping_list.name = f"{shopping_list.name}"
        shopping_list.is_template = True
        shopping_list.is_archived = False
        shopping_list.save()
        # Duplicate items
        for item in ShoppingList.objects.get(id=shopping_list_id).items.all():
            item.pk = None
            item.shopping_list = shopping_list
            item.checked = False
            item.save()
        messages.add_message(request, messages.INFO,
                             f"Nákupní seznam '{shopping_list.name}' byl uložen jako šablona.")
        # redirect to GroceryIndex
        return redirect('grocery_index')

    def get(self, request, *args, **kwargs):
        return redirect('grocery_index')

class DeleteShoppingListView(LoginRequiredMixin, ProcessFormView):
    def post(self, request, *args, **kwargs):
        shopping_list_id = kwargs.get('shopping_list_id')
        shopping_list = ShoppingList.objects.get(id=shopping_list_id)
        shopping_list_name = shopping_list.name
        shopping_list.delete()
        messages.add_message(request, messages.INFO,
                             f"Nákupní seznam '{shopping_list_name}' byl smazán.")
        # redirect to GroceryIndex
        return redirect('grocery_index')

    def get(self, request, *args, **kwargs):
        return redirect('grocery_index')


class MarkItemCheckedView(LoginRequiredMixin, ProcessFormView):
    def post(self, request, *args, **kwargs):
        item_id = kwargs.get('item_id')
        shopping_list_id = kwargs.get('shopping_list_id')
        shopping_list = ShoppingList.objects.get(id=shopping_list_id)
        item = shopping_list.items.get(id=item_id)
        item.checked = True
        item.save()
        messages.add_message(request, messages.INFO, f"Položka '{item.item}' byla zaškrtnuta.")
        # redirect to ShoppingListDetailView
        return redirect('shopping_list_detail', pk=shopping_list_id)

    def get(self, request, *args, **kwargs):
        return redirect('shopping_list_detail', pk=kwargs.get('shopping_list_id'))


class MarkItemUnCheckedView(LoginRequiredMixin, ProcessFormView):
    def post(self, request, *args, **kwargs):
        item_id = kwargs.get('item_id')
        shopping_list_id = kwargs.get('shopping_list_id')
        shopping_list = ShoppingList.objects.get(id=shopping_list_id)
        item = shopping_list.items.get(id=item_id)
        item.checked = False
        item.save()
        messages.add_message(request, messages.INFO, f"Položka '{item.item}' byla odškrtnuta.")
        # redirect to ShoppingListDetailView
        return redirect('shopping_list_detail', pk=shopping_list_id)

    def get(self, request, *args, **kwargs):
        return redirect('shopping_list_detail', pk=kwargs.get('shopping_list_id'))


class DeleteShoppingItemView(LoginRequiredMixin, ProcessFormView):
    def post(self, request, *args, **kwargs):
        item_id = kwargs.get('item_id')
        shopping_list_id = kwargs.get('shopping_list_id')
        shopping_list = ShoppingList.objects.get(id=shopping_list_id)
        item = shopping_list.items.get(id=item_id)
        item_name = item.item.name
        item.delete()
        messages.add_message(request, messages.INFO, f"Položka '{item_name}' byla smazána ze seznamu.")
        # redirect to ShoppingListDetailView
        return redirect('shopping_list_detail', pk=shopping_list_id)

    def get(self, request, *args, **kwargs):
        return redirect('shopping_list_detail', pk=kwargs.get('shopping_list_id'))


class CreateShoppingListView(LoginRequiredMixin, CreateView):
    form_class = CreateShoppingListForm
    template_name = "groceries/create_shopping_list.html"
    success_url = reverse_lazy("grocery_index")

    def form_valid(self, form):
        messages.add_message(self.request, messages.INFO, "Nákupní seznam byl vytvořen.")
        return super().form_valid(form)


class AddItemToShoppingListView(LoginRequiredMixin, ProcessFormView):
    def post(self, request, *args, **kwargs):
        shopping_list_id = kwargs.get('shopping_list_id')
        shopping_list = ShoppingList.objects.get(id=shopping_list_id)
        form = AddItemToShoppingListForm(request.POST)
        
        if form.is_valid():
            item = form.save(commit=False)
            item.shopping_list = shopping_list
            item.save()
            messages.add_message(
                request, 
                messages.SUCCESS, 
                f"Položka '{item.item.name}' byla přidána do seznamu."
            )
        else:
            messages.add_message(
                request, 
                messages.ERROR, 
                "Chyba při přidávání položky. Zkontrolujte prosím formulář."
            )
        
        return redirect('shopping_list_detail', pk=shopping_list_id)

    def get(self, request, *args, **kwargs):
        return redirect('shopping_list_detail', pk=kwargs.get('shopping_list_id'))


class EditShoppingListItemView(LoginRequiredMixin, ProcessFormView):
    def post(self, request, *args, **kwargs):
        shopping_list_id = kwargs.get('shopping_list_id')
        item_id = kwargs.get('item_id')
        shopping_list = get_object_or_404(ShoppingList, id=shopping_list_id)
        item = get_object_or_404(ShoppingListItem, id=item_id, shopping_list=shopping_list)
        
        form = EditShoppingListItemForm(request.POST, instance=item)
        
        if form.is_valid():
            form.save()
            messages.add_message(
                request, 
                messages.SUCCESS, 
                f"Položka '{item.item.name}' byla upravena."
            )
        else:
            messages.add_message(
                request, 
                messages.ERROR, 
                "Chyba při úpravě položky. Zkontrolujte prosím formulář."
            )
        
        return redirect('shopping_list_detail', pk=shopping_list_id)

    def get(self, request, *args, **kwargs):
        return redirect('shopping_list_detail', pk=kwargs.get('shopping_list_id'))


class CategoryListView(LoginRequiredMixin, ListView):
    model = ItemCategory
    template_name = "groceries/category_list.html"
    context_object_name = "categories"


class CategoryCreateView(LoginRequiredMixin, CreateView):
    form_class = ItemCategoryForm
    template_name = "groceries/category_form.html"
    success_url = reverse_lazy("category_list")

    def form_valid(self, form):
        messages.add_message(self.request, messages.SUCCESS, "Kategorie byla vytvořena.")
        return super().form_valid(form)


class CategoryUpdateView(LoginRequiredMixin, UpdateView):
    model = ItemCategory
    form_class = ItemCategoryForm
    template_name = "groceries/category_form.html"
    success_url = reverse_lazy("category_list")

    def form_valid(self, form):
        messages.add_message(self.request, messages.SUCCESS, "Kategorie byla upravena.")
        return super().form_valid(form)


class CategoryDeleteView(LoginRequiredMixin, ProcessFormView):
    def post(self, request, *args, **kwargs):
        category_id = kwargs.get('pk')
        category = get_object_or_404(ItemCategory, id=category_id)
        category_name = category.name
        category.delete()
        messages.add_message(
            request, 
            messages.SUCCESS, 
            f"Kategorie '{category_name}' byla smazána."
        )
        return redirect('category_list')

    def get(self, request, *args, **kwargs):
        return redirect('category_list')


class ItemListView(LoginRequiredMixin, ListView):
    model = Item
    template_name = "groceries/item_list.html"
    context_object_name = "items"

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['item_form'] = ItemForm()
        return context


class ItemCreateView(LoginRequiredMixin, CreateView):
    form_class = ItemForm
    template_name = "groceries/item_form.html"
    success_url = reverse_lazy("item_list")

    def form_valid(self, form):
        messages.add_message(self.request, messages.SUCCESS, "Položka byla vytvořena.")
        return super().form_valid(form)


class ItemUpdateView(LoginRequiredMixin, UpdateView):
    model = Item
    form_class = ItemForm
    template_name = "groceries/item_form.html"
    success_url = reverse_lazy("item_list")

    def form_valid(self, form):
        messages.add_message(self.request, messages.SUCCESS, "Položka byla upravena.")
        return super().form_valid(form)


class ItemDeleteView(LoginRequiredMixin, ProcessFormView):
    def post(self, request, *args, **kwargs):
        item_id = kwargs.get('pk')
        item = get_object_or_404(Item, id=item_id)
        item_name = item.name
        item.delete()
        messages.add_message(
            request,
            messages.SUCCESS,
            f"Položka '{item_name}' byla smazána."
        )
        return redirect('item_list')

    def get(self, request, *args, **kwargs):
        return redirect('item_list')