import logging
from datetime import datetime

from django.contrib import messages
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.forms import PasswordResetForm
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.views import (LoginView, LogoutView,
                                       PasswordResetCompleteView,
                                       PasswordResetConfirmView,
                                       PasswordResetDoneView,
                                       PasswordResetView)
from django.db.models import Prefetch, Q
from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse_lazy
from django.views import generic
from django_datatables_view.base_datatable_view import BaseDatatableView

from module_activity.models import (Bowel, ChronicCondition, Intolerance, MealRecord, MealSymptomRecord, Medication,
                                    PastTreatment, PrincipalHealthData,
                                    Symptoms)
from module_iam import iam_constant, permission
from module_iam.models import IAmPrincipal, IAmPrincipalType
from module_project import constants
from module_project.mixins import ActionMixin
from module_project.utils import JsonResponseUtil

from .forms import LoginForm, UserForm

logger = logging.getLogger(__name__)

class AdminLoginView(generic.View):
    template_name = "module_auth/login.html"
    form_class = LoginForm
    success_url = reverse_lazy("module_iam:dashboard")
    error_url = reverse_lazy("module_auth:login")
    success_message = constants.LOGIN_SUCCESS
    error_message = constants.INVALID_EMAIL_PASSWORD

    def get(self, request):
        form = self.form_class()

        return render(request, self.template_name, context={"form": form})

    def post(self, request):
        form = self.form_class(data=request.POST)
        context = {"form": form}
        if not form.is_valid():
            messages.error(request, constants.INVALID_EMAIL_PASSWORD)
            return render(request, self.template_name, context=context)

        email = form.cleaned_data['email']
        password = form.cleaned_data['password']

        user = authenticate(request, email=email, password=password)
        if user is None:
            messages.error(request, constants.INVALID_EMAIL_PASSWORD)
            return render(request, self.template_name, context=context)

        login(request, user)
        messages.success(request, constants.LOGIN_SUCCESS)
        logging.info(f"User {user.email} logged in.")

        return redirect(self.success_url)


class AdminLogoutView(LogoutView):
    next_page = reverse_lazy("module_auth:login")
    
class CustomPasswordResetView(PasswordResetView):
    form_class = PasswordResetForm
    template_name = "module_auth/password_reset_form.html"
    email_template_name = "module_auth/password_reset_email_template.html"
    success_url = reverse_lazy("module_auth:password_reset_done")


class CustomPasswordResetDoneView(PasswordResetDoneView):
    template_name = "module_auth/password_reset_done.html"


class UserDashView(permission.ResourcePermissionRequiredMixin, LoginRequiredMixin, generic.TemplateView):
    page_name = iam_constant.RESOURCE_MANAGE_USER
    resource = iam_constant.RESOURCE_MANAGE_USER
    action = None
    template_name = "module_auth/users_list.html"
    model = IAmPrincipal
    context_objext_name = "obj"

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context["page_name"] = self.page_name
        return context

class UserCreateOrUpdateView(permission.ResourcePermissionRequiredMixin, LoginRequiredMixin, generic.View):
    page_name = iam_constant.RESOURCE_MANAGE_USER
    resource = iam_constant.RESOURCE_MANAGE_USER
    model = IAmPrincipal
    form_class = UserForm
    template_name = "module_auth/user_add.html"
    success_url = reverse_lazy("module_auth:users")
    success_message = "Saved Successfully"
    error_message = "An error occurred while saving the data."

    def get_object(self):
        pk = self.kwargs.get("pk")
        return get_object_or_404(self.model, pk=pk) if pk else None

    def get_context_data(self, **kwargs):
        context = {
            "page_name": self.page_name,
            "operation": "Edit" if self.object else "Add",
        }
        context.update(kwargs)  # Include any additional context data passed to the view
        return context

    def get(self, request, *args, **kwargs):
        self.object = self.get_object()
        form = self.form_class(instance=self.object)
        context = self.get_context_data(form=form)
        return render(request, self.template_name, context=context)

    # @transaction.atomic
    def post(self, request, *args, **kwargs):
        print(request.POST)
        self.object = self.get_object()
        form = self.form_class(request.POST, instance=self.object)
        try:
            if form.is_valid():
                principal = form.save(commit=False)

                # Check if it's a new object (create action) or an existing one (update action)
                if not principal.pk:  # pk is None for new objects
                    principal.created_by = request.user
                principal.principal_type = IAmPrincipalType.objects.filter(name=iam_constant.PRINCIPAL_TYPE_USER).first()
                principal.modified_by = request.user
                principal.modified_on = datetime.now()

                # Save the object
                principal.save()

                messages.success(request, "Form submitted successfully")
                return redirect(self.success_url)
        except Exception as e:
            self.error_message = constants.ERROR_OCCURR.format(str(e))
            print(self.error_message)
            messages.error(request, self.error_message)

        context = self.get_context_data(form=form)
        return render(request, template_name=self.template_name, context=context)


class UserListJson(BaseDatatableView):
    model = IAmPrincipal
    columns = ["id", "first_name", "email", "phone_no", "date_of_birth", "is_active"]
    order_columns = ["id", "first_name", "email", "phone_no", "date_of_birth", "is_active"]
    FILTER_ICONTAINS = "icontains"

    def get_filter_method(self):
        """Returns preferred filter method"""
        return self.FILTER_ICONTAINS

    def get_initial_queryset(self):
        deleted_flag = self.request.GET.get('deleted_flag', False)
        return self.model.objects.filter(principal_type=IAmPrincipalType.get_principal_user(), deleted=deleted_flag)

    def filter_queryset(self, qs):
        print(f"request is {self.request.GET}")
        search_value = self.request.GET.get("search[value]", None)
        if search_value:
            qs = super().filter_queryset(qs)  # Call the built-in filtering first

        for column in self.columns:
            print(f" columen index pattern {self.request.GET.get(f'columns[{self.columns.index(column)+2}][search][value]', None)}")
            search_value = self.request.GET.get(f'columns[{self.columns.index(column)+2}][search][value]', None)
            if search_value:
                column_data = self.request.GET.get(f'columns[{self.columns.index(column)+2}][data]')
                if column_data == "is_active":
                    qs = qs.filter(**{f"{column}": search_value})
                else:
                    qs = qs.filter(**{f"{column}__icontains": search_value})

        return qs

    def ordering(self, qs):
        order = self.request.GET.get('order[0][dir]', None)
        if order:
            column_index = int(self.request.GET.get('order[0][column]', None)) - 2
            order_column = self.order_columns[column_index]

            if order == "asc":
                qs = qs.order_by(order_column)
            elif order == "desc":
                qs = qs.order_by("-" + order_column)

        return qs

class UserActionView(ActionMixin):
    model = IAmPrincipal

    def post(self, request, *args, **kwargs):

        action = request.POST.get('action')  # 'archive', 'active', or 'unarchive'
        ids = request.POST.getlist('ids[]')  # List of IDs to perform action on
        active = request.POST.get('active')
        print(f"arhive action {action} and id is {ids} and active data is {active}")
        if action == 'archive':
            # Update 'deleted' field to True for the selected users
            self.model.objects.filter(id__in=ids).update(deleted=True, is_active=False)
            message = 'Record archived successfully.'
        elif action == 'active':
            # Update 'active' field to True for the selected users
            self.model.objects.filter(id__in=ids).update(is_active=active.capitalize())
            message = 'Record updated successfully.'
        elif action == 'unarchive':
            # Update 'deleted' field to False for the selected users
            self.model.objects.filter(id__in=ids).update(deleted=False)
            message = 'Record unarchived successfully.'
        else:
            return JsonResponseUtil.error(message="Invalid Action")

        return JsonResponseUtil.success(message=message)

class UserRecordView(permission.ResourcePermissionRequiredMixin, LoginRequiredMixin, generic.View):
    page_name = iam_constant.RESOURCE_MANAGE_USER
    resource = iam_constant.RESOURCE_MANAGE_USER
    action = None
    model = IAmPrincipal
    template_name = "module_auth/user_view.html"

    def get_recent_meal(self, id):
        recent_meal_records = MealRecord.objects.filter(
            principal=id
        ).order_by('-id')[:5]
        return recent_meal_records

    def get_recent_medication(self, id):
        recent_medication_records = Medication.objects.filter(
            principal=id
        ).order_by('-id')[:5]
        return recent_medication_records

    def get_recent_bowel(self, id):
        recent_bowel_records = Bowel.objects.filter(
            principal=id
        ).order_by('-id')[:5]
        return recent_bowel_records

    def get_recent_meal_symptom(self, id):
        recent_meal_symptom_records = MealSymptomRecord.objects.filter(
            principal=id
        ).order_by('-id')[:5]
        return recent_meal_symptom_records

    def get(self, request, id):
        # Retrieve the IAmPrincipal instance
        principal_instance = get_object_or_404(IAmPrincipal, id=id)

        # Prefetch related Intolerance objects for the principal
        intolerance_prefetch = Prefetch(
            "intolerance_principal",
            queryset=Intolerance.objects.filter(principal=principal_instance),
            to_attr="intolerance_data",
        )

        symptom_prefetch = Prefetch(
            "symptoms_principal",
            queryset=Symptoms.objects.filter(principal=principal_instance),
            to_attr="symptoms_data",
        )

        pasttreatment_prefetch = Prefetch(
            "pasttreatment_principal",
            queryset=PastTreatment.objects.filter(principal=principal_instance),
            to_attr="pasttreatment_data",
        )

        chronic_prefetch = Prefetch(
            "chronic_principal",
            queryset=ChronicCondition.objects.filter(principal=principal_instance),
            to_attr="chronic_data",
        )

        # Now fetch the principal instance with prefetches
        obj = IAmPrincipal.objects.prefetch_related(
            intolerance_prefetch,
            symptom_prefetch,
            pasttreatment_prefetch,
            chronic_prefetch
        ).get(id=id)

        for data in obj.chronic_data:
            print(f"data is {data.name, data.duration}")

        context = {
            'page_name': self.page_name,
            'obj': obj,
            "recent_meal": self.get_recent_meal(id),
            "recent_medication": self.get_recent_medication(id),
            "recent_bowel": self.get_recent_bowel(id),
            "recent_meal_symptom": self.get_recent_meal_symptom(id),
        }

        # Render the template with the principal instance and related data
        return render(request, self.template_name, context=context)


class UserArchiveList(permission.ResourcePermissionRequiredMixin, LoginRequiredMixin, generic.TemplateView):
    page_name = iam_constant.RESOURCE_MANAGE_USER
    resource = iam_constant.RESOURCE_MANAGE_USER
    action = None
    template_name = "module_auth/users_archive_list.html"
    model = IAmPrincipal

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context["page_name"] = self.page_name
        return context

class CustomPasswordResetConfirmView(PasswordResetConfirmView):
    template_name = "module_auth/password_reset_confirm.html"
    success_url = reverse_lazy("module_auth:password_reset_complete")


class CustomPasswordResetCompleteView(PasswordResetCompleteView):
    template_name = "module_auth/password_reset_complete.html"


class UsersCountView(generic.View):

    def get(self, request):
        current_year = int(self.request.GET.get("year"))
        user_counts = []

        # Iterate over each month from January to December
        for month in range(1, 13):
            # Calculate the start and end dates for the current month
            start_date = datetime(current_year, month, 1)
            end_date = datetime(current_year, month + 1, 1) if month < 12 else datetime(current_year + 1, 1, 1)
            # Query the User model to count users created within the current month
            user_count = IAmPrincipal.objects.filter(date_joined__range=(start_date, end_date)).count()

            # Append the count to the list
            user_counts.append(user_count)

        return JsonResponseUtil.success(message=constants.SUCCESS, data=user_counts)