from django.conf import settings
from django.contrib import messages
from django.contrib.auth import login
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.contrib.auth.models import User
from django.core.mail import send_mail
from django.db.models import Q, Avg, Exists, OuterRef
from django.http import HttpResponse
from django.shortcuts import render, get_object_or_404, redirect
from django.urls import reverse
from django.utils import timezone
from django.utils.http import urlencode
from django.views.generic import TemplateView, DetailView, ListView
from django.views.generic.edit import FormView, UpdateView, CreateView
from registration.backends.simple.views import RegistrationView

from apps.carers.forms import SetUpFlowOneForm, CarerSearchForm, ReviewForm, FileUploadForm, ActivationPasswordForm
from apps.carers.lib.emails import send_staff_welcome_email, send_admin_welcome_email, send_organisation_welcome_email
from apps.carers.lib.process_excel import process_excel_file
from apps.carers.models import Profile, Review, UserActivationCode
from apps.orgs.models import Organisation
from faker import Faker
import random

from apps.quiz.models import Quiz, CompletedQuiz


# Create your views here.

# @check_setup_completion
# def dashboard(request):
#     return render(request, 'carers/dashboard_layout.html')


# @method_decorator(check_setup_completion, name='dispatch')
class UserProfileDetailView(LoginRequiredMixin, DetailView):
    """This is a logged in user profile page, to see their own profile page"""
    template_name = 'carers/profile_detail.html'
    model = Profile

    def get_object(self):
        # This method is used to retrieve the object that the view will display.
        # Here, we override this method to return the profile of the current logged-in user.
        return get_object_or_404(Profile, user=self.request.user)

    def get_context_data(self, **kwargs):
        # This a helper method to pass extra data over to a template
        context = super(UserProfileDetailView, self).get_context_data(**kwargs)
        context['visitor'] = False
        # Add the base URL to the context
        context['base_url'] = self.request.build_absolute_uri('/')[:-1]  # Remove the trailing slash
        context['staff_link_request'] = self.object.stafflinkrequest_set.first()
        context['reviews'] = Review.objects.filter(user=self.object.user, is_flagged_for_review=False).order_by('-created_at')
        # Annotate each quiz with is_complete
        quizzes = Quiz.objects.filter(is_published=True).annotate(
            is_complete=Exists(
                CompletedQuiz.objects.filter(profile=self.object, quiz=OuterRef('pk'))
            )
        )
        total_quizzes = quizzes.count()
        # Count completed quizzes
        completed_quizzes_count = quizzes.filter(is_complete=True).count()

        context['quizzes'] = quizzes
        context['total_quizzes_count'] = total_quizzes
        context['completed_quizzes_count'] = completed_quizzes_count

        # Calculate percentage (avoid division by zero)
        completed_percentage = (
            (completed_quizzes_count / total_quizzes * 100) if total_quizzes > 0 else 0
        )
        context['completed_percentage'] = round(completed_percentage, 2)
        return context


class UserProfileVisitorDetailView(DetailView):
    """This is a user profile page for a user to see other people profiles"""
    template_name = 'carers/profile_detail.html'
    model = Profile

    def get_object(self):
        # Retrieve the PIN from the URL kwargs
        pin = self.kwargs.get('pin', None)
        return get_object_or_404(Profile, pin=pin)

    def get_context_data(self, **kwargs):
        context = super(UserProfileVisitorDetailView, self).get_context_data(**kwargs)
        context['visitor'] = True
        context['reviews'] = Review.objects.filter(user=self.object.user, is_flagged_for_review=False).order_by('-created_at')
        return context



class SetUpFlowOneFormView(LoginRequiredMixin, UpdateView):
    """Initial redirect after sign up, allows user to add basic detail to their carer profile, name, etc"""
    model = Profile
    template_name = "carers/set-up-flow-1.html"
    form_class = SetUpFlowOneForm

    def get_object(self, queryset=None):
        # Override the method to get the profile for the current user without requiring a pk or slug
        obj, created = Profile.objects.get_or_create(user=self.request.user)
        return obj

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['page_title'] = 'Set up your carer profile'
        return context


    def form_valid(self, form):
        # This is a method to do something with the form data after it has been successfully validated, in this case
        # we take the form and extract first_name and last_name fields, and save them to the user instance.

        # Update the User object
        user = self.request.user
        user.first_name = form.cleaned_data['first_name']
        user.last_name = form.cleaned_data['last_name']
        user.save()

        # link user/profile to organisation is if sign up in form
        unique_organisation_code = form.data.get('signup', None)
        if unique_organisation_code:
            try:
                organisation = Organisation.objects.get(unique_code=unique_organisation_code)
                organisation.staff.add(self.object)
                self.object.employer_name = organisation.name
                self.object.save()
                # TODO: could also send an email here
            except Organisation.DoesNotExist as e:
                print(e)


        return super().form_valid(form)

    def get_success_url(self):
        # This is where to redirect the user to after a successful form submission
        return reverse('profile')


class EditProfileFormView(LoginRequiredMixin, UpdateView):
    """Initial redirect after sign up, allows user to add basic detail to their carer profile, name, etc"""
    model = Profile
    template_name = "carers/set-up-flow-1.html"
    form_class = SetUpFlowOneForm

    def get_object(self, queryset=None):
        # Override the method to get the profile for the current user without requiring a pk or slug
        obj, created = Profile.objects.get_or_create(user=self.request.user)
        return obj

    def get_initial(self):
        # This method is called when the form is being initialized.
        # Here, we get the current user's first name and last name and set it as the initial data for the form.

        initial = super().get_initial()
        user = self.request.user
        initial['first_name'] = user.first_name
        initial['last_name'] = user.last_name
        return initial

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['edit'] = True
        context['page_title'] = 'Edit Profile'
        return context


    def form_valid(self, form):
        # This is a method to do something with the form data after it has been successfully validated, in this case
        # we take the form and extract first_name and last_name fields, and save them to the user instance.

        # Update the User object
        user = self.request.user
        user.first_name = form.cleaned_data['first_name']
        user.last_name = form.cleaned_data['last_name']
        user.save()

        return super().form_valid(form)

    def get_success_url(self):
        # This is where to redirect the user to after a successful form submission
        return reverse('profile')


def set_up_flow_dummy(request):
    return HttpResponse('It works')


# class QualificationFormSetView(TemplateView):
#     template_name = 'carers/set-up-flow-2.html'
#
#     def get_context_data(self, **kwargs):
#         context = super().get_context_data(**kwargs)
#         if 'formset' not in context:
#             context['formset'] = QualificationFormSet(
#                 queryset=Qualification.objects.none(),
#                 form_kwargs={'user': self.request.user}  # Pass the user to the form
#             )
#         return context
#
#     def post(self, request, *args, **kwargs):
#         formset = QualificationFormSet(
#             request.POST,
#             form_kwargs={'user': request.user}  # Pass the user to the form on POST as well
#         )
#         if formset.is_valid():
#             formset.save()  # Each form's save method will now save the user instance
#             return HttpResponseRedirect(self.get_success_url())
#         return self.render_to_response(self.get_context_data(formset=formset))
#
#     def get_success_url(self):
#         return reverse_lazy('setup_flow_3')
#
#
# class WorkExperienceFormSetView(TemplateView):
#     template_name = 'carers/set-up-flow-3.html'
#
#     def get_context_data(self, **kwargs):
#         context = super().get_context_data(**kwargs)
#         if 'formset' not in context:
#             context['formset'] = WorkExperienceFormSet(
#                 queryset=WorkExperience.objects.none(),
#                 form_kwargs={'user': self.request.user}  # Pass the user to the form
#             )
#         return context
#
#     def post(self, request, *args, **kwargs):
#         formset = WorkExperienceFormSet(
#             request.POST,
#             form_kwargs={'user': request.user}  # Pass the user to the form on POST as well
#         )
#         if formset.is_valid():
#             formset.save()  # Each form's save method will now save the user instance
#             return HttpResponseRedirect(self.get_success_url())
#         return self.render_to_response(self.get_context_data(formset=formset))
#
#     def get_success_url(self):
#         return reverse_lazy('setup_flow_4')
#
#
# class HobbiesFormView(LoginRequiredMixin, UpdateView):
#     model = Profile
#     template_name = "carers/set-up-flow-4.html"
#     form_class = HobbiesForm
#
#     def get_object(self, queryset=None):
#         # Override the method to get the profile for the current user without requiring a pk or slug
#         obj, created = Profile.objects.get_or_create(user=self.request.user)
#         return obj
#
#     def get_success_url(self):
#         return reverse('setup_flow_5')
#
#
# class ExtraInfoFormView(LoginRequiredMixin, UpdateView):
#     model = Profile
#     template_name = "carers/set-up-flow-5.html"
#     form_class = ExtraInfoForm
#
#     def get_object(self, queryset=None):
#         # Override the method to get the profile for the current user without requiring a pk or slug
#         obj, created = Profile.objects.get_or_create(user=self.request.user)
#         return obj
#
#     def get_success_url(self):
#         return reverse('setup_flow_6')
#
#
# class AvatarFormView(LoginRequiredMixin, UpdateView):
#     model = Profile
#     template_name = "carers/set-up-flow-6.html"
#     form_class = AvatarForm
#
#     def get_object(self, queryset=None):
#         # Override the method to get the profile for the current user without requiring a pk or slug
#         obj, created = Profile.objects.get_or_create(user=self.request.user)
#         return obj
#
#     def get_success_url(self):
#         return reverse('profile')
#

# @method_decorator(check_setup_completion, name='dispatch')

class HomeView(FormView):
    template_name = 'carers/home.html'
    form_class = CarerSearchForm


class FindACarerView(FormView):
    template_name = 'carers/find_a_carer.html'
    form_class = CarerSearchForm


def carer_search(request):
    term = request.GET.get('search')

    # Adjust the query to search within related User model fields and the employer_name
    if term:
        results = Profile.objects.filter(
            Q(user__first_name__icontains=term) |
            Q(preferred_name__icontains=term) |
            Q(user__last_name__icontains=term) |
            Q(employer_name__icontains=term) |
            Q(pin=term)
        ).exclude(pin__isnull=True).exclude(pin='')
        for res in results:
            print(res.user.username, flush=True)
    else:
        results = None

    return render(request, 'components/carer-search-results.html', context={'results': results})


class CarerReviewView(CreateView):
    model = Review
    form_class = ReviewForm
    template_name = 'carers/review_form.html'

    # include any other fields you want to be part of the form

    def get_form_kwargs(self):
        # Helper method to prepopulate the form with the user's ID
        kwargs = super(CarerReviewView, self).get_form_kwargs()
        user_id = self.kwargs.get('user_id')
        kwargs['initial']['user'] = get_object_or_404(User, pk=user_id)
        return kwargs

    def form_valid(self, form):
        # Set the user before saving the form
        form.instance.user = get_object_or_404(User, pk=self.kwargs.get('user_id'))
        response = super(CarerReviewView, self).form_valid(form)

        # Send an email notification to the user about the new review
        self.send_review_notification_email_to_carer(form.instance.user)
        self.send_review_notification_email_to_organisation(form.instance.user)

        return response

    def form_invalid(self, form):
        print('')

    def send_review_notification_email_to_carer(self, user):
        """Send an email notifying the user that they received a new review."""

        subject = 'You have received a new Special Mention'
        login_url = self.request.build_absolute_uri(reverse('login'))

        message = f'''
        Hello {user.profile},

        You have received a new Special Mention on our platform. To view it, please log in to your account.

        [Click here to log in and view the Special Mention.]({login_url})

        Best regards,
        The Peopleoo Team
        '''

        recipient_list = [user.email]
        send_mail(
            subject,
            message,
            settings.DEFAULT_FROM_EMAIL,
            recipient_list,
            fail_silently=False,
        )
    def send_review_notification_email_to_organisation(self, user):
        """Send an email notifying the user that they received a new review."""

        # get users organisations
        # send email to organiation email
        # could also send to staff
        # set login url to org login
        # send better message
        subject = f'{user.first_name} {user.last_name} received a new Special Mention'
        login_url = self.request.build_absolute_uri(reverse('org_login'))
        organisations  = user.profile.organisations.all()

        for organisation in organisations:




            message = f'''
            Hello {organisation.name},
    
            {user.first_name} {user.last_name} has received a new Special Mention on our platform. To view it, please log in to your account.
    
            [Click here to log in and view the Special Mention.]({login_url})
    
            Best regards,
            The Peopleoo Team
            '''

            recipient_list = [user.email]
            send_mail(
                subject,
                message,
                settings.DEFAULT_FROM_EMAIL,
                recipient_list,
                fail_silently=False,
            )

    def get_context_data(self, **kwargs):
        context = super(CarerReviewView, self).get_context_data(**kwargs)
        # Get the user_id from the URL parameters
        user_id = self.kwargs.get('user_id')
        # Fetch the User object and add it to the context
        user = get_object_or_404(User, pk=user_id)
        context['profile'] = user.profile
        return context

    def get_success_url(self):
        return reverse('thanks')




class ManagementView(UserPassesTestMixin, TemplateView):
    template_name = 'carers/manage.html'

    def test_func(self):
        # This method checks if the user is a superuser
        return self.request.user.is_superuser
#	 return True
    def get_context_data(self, **kwargs):
        context = super(ManagementView, self).get_context_data(**kwargs)

        # Get the total number of users
        context['num_users'] = Profile.objects.count()

        # Get the number of users who have completed onboarding
        context['users_completed_onboarding'] = Profile.objects.filter(has_completed_setup=True).count()

        # Get the total number of reviews
        context['num_reviews'] = Review.objects.count()

        # Get the number of reviews this month
        now = timezone.now()
        start_of_month = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
        context['reviews_this_month'] = Review.objects.filter(created_at__gte=start_of_month).count()

        # Get average score of reviews
        context['average_score'] = Review.objects.aggregate(Avg('rating'))['rating__avg']

        # Get average score of reviews this month
        context['average_score_this_month'] = Review.objects.filter(created_at__gte=start_of_month).aggregate(Avg('rating'))['rating__avg']

        return context


class ManageReportsView(UserPassesTestMixin, TemplateView):
    template_name = 'carers/manage_reports.html'

    def test_func(self):
        # This method checks if the user is a superuser
        return self.request.user.is_superuser

    def get_context_data(self, **kwargs):
        context = super(ManageReportsView, self).get_context_data(**kwargs)
        context['reported_reviews'] = Review.objects.filter(is_flagged_for_review=True)

        return context


class ManageUsersView(UserPassesTestMixin, TemplateView):
    template_name = 'carers/manage_users.html'

    def test_func(self):
        # This method checks if the user is a superuser
        return self.request.user.is_superuser

    def get_context_data(self, **kwargs):
        context = super(ManageUsersView, self).get_context_data(**kwargs)

        context['users_completed_setup'] = Profile.objects.exclude(user__first_name__exact='')
        context['users_not_completed_setup'] = Profile.objects.filter(user__first_name__exact='')

        return context


class ManageOrganisations(UserPassesTestMixin, ListView):
    template_name = 'carers/manage_organisations.html'
    context_object_name = 'organisations'

    model = Organisation

    def test_func(self):
        # This method checks if the user is a superuser
        return self.request.user.is_superuser

    # def get_queryset(self):
    #     return Organisation.objects.filter(parent__isnull=True)


class CreateOrganisation(UserPassesTestMixin, CreateView):
    model = Organisation
    fields = ['name', 'email', 'logo']
    template_name = 'carers/manage_organisations_create.html'

    def test_func(self):
        # This method checks if the user is a superuser
        return self.request.user.is_superuser

    def get_success_url(self):
        return reverse('manage_organisations')


class UpdateOrganisation(UserPassesTestMixin, UpdateView):
    model = Organisation
    fields = ['name', 'email', 'logo']
    template_name = 'carers/manage_organisations_create.html'

    def test_func(self):
        # This method checks if the user is a superuser
        return self.request.user.is_superuser

    def get_success_url(self):
        return reverse('manage_organisations')


class OrganisationUploadStaff(FormView, UserPassesTestMixin):
    template_name = "carers/manage_csv_upload.html"  # Create this template
    form_class = FileUploadForm

    def test_func(self):
        # This method checks if the user is a superuser
        return self.request.user.is_superuser

    def form_valid(self, form):
        organisation_id = self.kwargs.get('pk')
        organisation = get_object_or_404(Organisation, pk=organisation_id)
        file = form.cleaned_data['file']
        num_imported, total_rows = process_excel_file(file, organisation, admins=False)
        messages.add_message(self.request, messages.INFO, f"Staff File processed. Imported {num_imported} rows out of {total_rows}.")
        return super().form_valid(form)

    def get_success_url(self):
        return reverse('manage_organisations')



class OrganisationUploadAdmin(FormView, UserPassesTestMixin):
    template_name = "carers/manage_csv_upload.html"  # Create this template
    form_class = FileUploadForm

    def form_valid(self, form):
        organisation_id = self.kwargs.get('pk')
        organisation = get_object_or_404(Organisation, pk=organisation_id)
        file = form.cleaned_data['file']
        num_imported, total_rows = process_excel_file(file, organisation, admins=True)
        messages.add_message(self.request, messages.INFO, f"Admin File processed. Imported {num_imported} rows out of {total_rows}.")


        return super().form_valid(form)

    def get_success_url(self):
        return reverse('manage_organisations')

    def test_func(self):
        # This method checks if the user is a superuser
        return self.request.user.is_superuser


class CreateChildOrganisation(CreateView, UserPassesTestMixin):
    model = Organisation
    fields = ['parent', 'name', 'email', 'logo']
    template_name = 'carers/manage_organisations_create.html'


    def test_func(self):
        # This method checks if the user is a superuser
        return self.request.user.is_superuser

    def get_initial(self):
        initial = super().get_initial()
        # Get the `pk` from the URL and set the initial value for the `parent` field
        parent_pk = self.kwargs.get('pk')
        parent_organisation = get_object_or_404(Organisation, pk=parent_pk)
        initial['parent'] = parent_organisation

        return initial

    def get_success_url(self):
        return reverse('manage_organisations')


class ReviewThankYouView(TemplateView):
    template_name = 'carers/thanks.html'


def report_review(request, review_pk):
    review = get_object_or_404(Review, pk=review_pk)
    review.is_flagged_for_review = True
    review.save()

    return HttpResponse('Reported!')


def keep_review(request, review_pk):
    review = get_object_or_404(Review, pk=review_pk)
    review.is_flagged_for_review = False
    review.save()

    context = {
        'reported_reviews': Review.objects.filter(is_flagged_for_review=True)
    }

    return render(request, 'components/review_list_table.html', context)



def delete_review(request, review_pk):
    review = get_object_or_404(Review, pk=review_pk)
    review.delete()

    context = {
        'reported_reviews': Review.objects.filter(is_flagged_for_review=True)
    }

    return render(request, 'components/review_list_table.html', context)



class CustomRegistrationView(RegistrationView):
    """
    A custom registration view that extends the original RegistrationView
    to append a query parameter to the success URL.
    """

    def get_success_url(self, user=None):
        """
        Override get_success_url to add query parameters.
        """
        # Call the parent method to get the original success URL
        success_url = getattr(settings, 'SIMPLE_BACKEND_REDIRECT_URL', '/')

        # Get the 'signup' query parameter from the request
        signup_param = self.request.POST.get('signup', None)

        # If the parameter exists, append it to the URL
        if signup_param:
            query_string = urlencode({'signup': signup_param})
            success_url = f"{success_url}?{query_string}"

        return success_url

    # def register(self, form):
    #     """
    #     Optionally override the register method if you need to customize
    #     the registration process further.
    #     """
    #     # You can customize the registration process here if needed
    #     new_user = super().register(form)
    #     # Add any additional processing here
    #     return new_user




def staging_setup(request):
    # Initialize Faker
    if settings.IS_STAGING:
        faker = Faker('en_GB')  # UK locale

        # Create 10 User instances
        users = []
        for i in range(10):
            first_name = faker.first_name()
            last_name = faker.last_name()
            email = faker.email()

            user = User.objects.create(
                username=f"{first_name.lower()}{last_name.lower()}{i}",
                email=email,
                first_name=first_name,
                last_name=last_name
            )
            users.append(user)

            # Create a Profile instance for each user
            pin = faker.unique.numerify(text="######")

            # Check if the profile already exists for this user
            if not Profile.objects.filter(user=user).exists():
                Profile.objects.create(
                    user=user,
                    middle_names=faker.first_name() if random.choice([True, False]) else "",
                    employer_name=faker.company() if random.choice([True, False]) else "",
                    employer_email=faker.email() if random.choice([True, False]) else "",
                    has_completed_setup=random.choice([True, False]),
                    preferred_name=faker.first_name() if random.choice([True, False]) else "",
                )

        # Create 5 Review instances for each User
        for user in users:
            for _ in range(5):
                Review.objects.create(
                    user=user,
                    rating=random.choice([1, 2, 3, 4, 5]),
                    text=faker.text(max_nb_chars=300),
                    reviewer_name=faker.name(),
                    reviewer_phone=faker.phone_number(),
                    reviewer_email=faker.email(),
                    relationship_to_user=random.choice(["Friend", "Colleague", "Client", "Manager", "Partner"]),
                    is_flagged_for_review=random.choice([True, False])
                )

        HttpResponse("Dummy data creation completed successfully.")



class ViewOrganisationPeople(DetailView, LoginRequiredMixin, UserPassesTestMixin):
    template_name = 'carers/manage_view_staff.html'
    model = Organisation
    def test_func(self):
        # This method checks if the user is a superuser
        return self.request.user.is_superuser


def manage_send_welcome_emails(request, pk):
    organisation = get_object_or_404(Organisation, pk=pk)
    staff = organisation.staff.all()
    admins = organisation.admins.all()
    if not organisation.sent_welcome_email:
        send_organisation_welcome_email(organisation)
        organisation.sent_welcome_email = True
        organisation.save()

    for profile in staff:
        if not profile.sent_welcome_email:
            send_staff_welcome_email(profile.user, organisation)
            profile.sent_welcome_email = True
            profile.save()

    for admin in admins:
        if not admin.sent_welcome_email:

            send_admin_welcome_email(admin.user, organisation)
            admin.sent_welcome_email = True
            admin.save()

    messages.add_message(request, messages.SUCCESS, "Welcome emails sent.")

    return redirect('manage_organisations')


def activate_account(request, uuid):
    activation_object = get_object_or_404(UserActivationCode, uuid=uuid)
    user = activation_object.user
    if user.is_active:
        return redirect('profile')

    if request.POST:
        form = ActivationPasswordForm(request.POST)
        if form.is_valid():
            user.set_password(form.cleaned_data['new_password2'])
            user.is_active = True
            user.save()
            login(request, user)

            # Check if the user has a profile, otherwise redirect to org_dashboard
            profile_exists = hasattr(user, 'profile')
            return redirect('profile' if profile_exists else 'org_dashboard')

        # Form invalid
        return render(request, 'carers/activation_set_password.html', {'form': form})

    # If GET request
    form = ActivationPasswordForm(initial={'uuid': uuid})
    return render(request, 'carers/activation_set_password.html', context={'form': form})


