import datetime

from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.contrib.auth.views import LoginView, LogoutView
from django.http import HttpResponseRedirect, JsonResponse
from django.shortcuts import render, get_object_or_404
from django.db.models import Q, Sum
from django.urls import reverse_lazy
from django.utils.decorators import method_decorator
from django.views import View
from django.views.decorators.cache import never_cache
from django.views.decorators.csrf import csrf_protect
from django.views.decorators.debug import sensitive_post_parameters
from django.views.generic import CreateView, ListView, DetailView, UpdateView, \
    DeleteView, TemplateView
from django_datatables_view.base_datatable_view import BaseDatatableView
from django.contrib.auth import logout as auth_logout

from crm_accounting.models import Invoice, status_invoice
from crm_accounting import views as account_views
from crm_home.models import TariffService
from houses.models import House, Flat, Section, Floor
from users.forms import LoginUserForm, CustomUserForm, \
    OwnerUserForm, RequestForm, MessageForm, RequestUserForm, RegisterUserForm
from users.models import CustomUser, Role, Request, Message, MessageUsers
from users.utilites import send_activation_notification, signer

def handler403(request, exception):
    response = render(request, 'error403.html', context={}, status=403)
    return response

def handlers404(request, exception):
    response = render(request, 'error404.html', context={}, status=404)
    print(response)

    return response

class CabinetPermissionMixin(LoginRequiredMixin, UserPassesTestMixin):
    login_url = reverse_lazy('users:login')
    redirect_field_name = 'redirect_to'

    def test_func(self):
        if self.request.user.is_anonymous:
            return False
        elif not self.request.user.role:
            return True

    def handle_no_permission(self):
        if not self.request.user.is_authenticated:
            return super().handle_no_permission()
        elif self.request.user.role:
            return HttpResponseRedirect(reverse_lazy('houses:statistics'))

def check_remember_me_answer(self, form):
    remember_me = form.cleaned_data.get('remember_me')
    if not remember_me:
        self.request.session.set_expiry(0)
        self.request.session.modified = True

class LoginUser(LoginView):
    form_class = LoginUserForm
    template_name = 'users/login_user.html'

    @method_decorator(sensitive_post_parameters())
    @method_decorator(csrf_protect)
    @method_decorator(never_cache)
    def dispatch(self, request, *args, **kwargs):
        if self.request.user.is_authenticated and self.request.user.is_staff:
            return HttpResponseRedirect(reverse_lazy('users:message_list'))
        elif self.request.user.is_authenticated and not self.request.user.is_staff:
            return HttpResponseRedirect(reverse_lazy('users:user_profile'))
        return super().dispatch(request, *args, **kwargs)

    def get_success_url(self):
        return reverse_lazy('users:user_profile')

    def form_valid(self, form):
        ''' Check remember me checkbox from form'''
        check_remember_me_answer(self, form)
        return super(LoginUser, self).form_valid(form)

class RegisterUserView(CreateView):
    model = CustomUser
    form_class = RegisterUserForm
    template_name = 'users/registration_user.html'
    success_url = reverse_lazy('users:register_done')

    def get_context_data(self, **kwargs):
        context = super(RegisterUserView, self).get_context_data()
        confirmation = self.request.GET.get('notconfirm')
        if confirmation:
            context['confirm'] = 'Почта не подтверждена, поскольку ' \
                                 'использован нерпавильный ключ. ' \
                                 'Попробуйте еще раз'
        return context

    def post(self, request):
        form_class = self.form_class(request.POST)
        if form_class.is_valid():
            form_class.save()
            return HttpResponseRedirect(self.success_url)
        else:
            return render(request, self.template_name,
                          context={'form': form_class})

class RegisterDoneView(TemplateView):
    template_name = 'users/register_done.html'

class LoginAdminUser(LoginView):
    form_class = LoginUserForm
    template_name = 'users/login_admin_user.html'

    # redirect_authenticated_user = reverse_lazy('users:layout')

    @method_decorator(sensitive_post_parameters())
    @method_decorator(csrf_protect)
    @method_decorator(never_cache)
    def dispatch(self, request, *args, **kwargs):
        if self.request.user.is_authenticated and self.request.user.is_staff:
            return HttpResponseRedirect(reverse_lazy('users:message_list'))
        elif self.request.user.is_authenticated and not self.request.user. \
                is_staff:
            return HttpResponseRedirect(reverse_lazy('users:user_profile'))
        return super().dispatch(request, *args, **kwargs)

    def get_success_url(self):
        return reverse_lazy('users:users')

    def form_valid(self, form):
        ''' Check remember me checkbox from form'''
        check_remember_me_answer(self, form)
        return super(LoginAdminUser, self).form_valid(form)

class LogoutUser(LogoutView):

    def get_success_url(self):
        return reverse_lazy('content:main')

    @method_decorator(csrf_protect)
    def post(self, request, *args, **kwargs):
        """Logout may be done via POST."""
        auth_logout(request)
        return HttpResponseRedirect(reverse_lazy('content:main'))

class UsersListView(account_views.AdminPermissionMixin, ListView):
    model = CustomUser
    queryset = CustomUser.objects.filter(~Q(role=None)).order_by('id'). \
        select_related('role')
    context_object_name = 'users'
    check_permission_name = 'users'

    def get_context_data(self, *, object_list=None, **kwargs):
        context = super().get_context_data()
        context['roles'] = Role.objects.all()
        return context

class AjaxUsersListView(BaseDatatableView):
    model = CustomUser
    columns = ['id', 'first_name', 'last_name',
               'role', 'phone', 'email', 'status']

    def get_initial_queryset(self):
        return self.model.objects.filter(~Q(role=None))

    def filter_queryset(self, qs):
        user_names = self.request.GET.get('user')
        role = self.request.GET.get('role')
        phone = self.request.GET.get('phone')
        email = self.request.GET.get('email')
        status = self.request.GET.get('status')
        if role:
            qs = qs.filter(role_id=role)
        if phone:
            qs = qs.filter(phone__icontains=phone)
        if email:
            qs = qs.filter(email__icontains=email)
        if status:
            qs = qs.filter(status=status)
        if user_names:
            qs = qs.filter(
                Q(first_name__icontains=user_names)|Q(
                    last_name__icontains=user_names))
        return qs

class UserCreateView(account_views.AdminPermissionMixin, CreateView):
    model = CustomUser
    form_class = CustomUserForm
    context_object_name = 'users'
    success_url = reverse_lazy('users:users')
    check_permission_name = 'users'

    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs['label_suffix'] = ''
        return kwargs

    def get_context_data(self, **kwargs):
        context = super(UserCreateView, self).get_context_data()
        user_id = self.request.GET.get('user_id')
        if user_id:
            user = get_object_or_404(CustomUser, id=user_id)
            initial = {
                'first_name': user.first_name,
                'last_name': user.last_name,
                'role': user.role,
                'phone': user.phone
            }
            context['form'] = self.form_class(initial=initial)
        return context

class UserDetailView(account_views.AdminPermissionMixin, DetailView):
    model = CustomUser
    check_permission_name = 'users'

class UserUpdateView(account_views.AdminPermissionMixin, UpdateView):
    model = CustomUser
    form_class = CustomUserForm
    context_object_name = 'users'
    success_url = reverse_lazy('users:users')
    template_name = 'users/customuser_update_form.html'
    check_permission_name = 'users'

    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs['label_suffix'] = ''
        return kwargs

    def post(self, request, *args, **kwargs):
        form_class = self.form_class(request.POST, instance=self.get_object())
        if form_class.is_valid():
            form_class.save(commit=False)

            form_class.save()
            return HttpResponseRedirect(reverse_lazy('users:users'))
        return render(request, self.template_name, self.get_context_data())

def delete_user(request, pk):
    user = CustomUser.objects.get(pk=pk)
    if not user.is_superuser:
        user.delete()
    else:
        messages.error(request, 'Вы не можете удалть суперпользователя')
    return HttpResponseRedirect(reverse_lazy('users:users'))

class OwnerListView(account_views.AdminPermissionMixin, ListView):
    model = CustomUser
    context_object_name = 'users'
    queryset = CustomUser.objects.filter(role=None).prefetch_related(
        'house_set',
        'flat_set__house__personalaccount_set',
        'flat_set__personal_account').order_by('date_joined')
    template_name = 'users/owners_list.html'
    check_permission_name = 'owner'

    def get_context_data(self, *, object_list=None, **kwargs):
        context = super().get_context_data()
        context['houses'] = House.objects.all()
        return context

class OwnerCreateView(account_views.AdminPermissionMixin, CreateView):
    model = CustomUser
    form_class = OwnerUserForm
    context_object_name = 'users'
    success_url = reverse_lazy('users:owner_list')
    template_name = 'users/owner_create_form.html'
    check_permission_name = 'owner'

    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs['label_suffix'] = ''
        return kwargs

    def post(self, request, *args, **kwargs):
        form_class = self.form_class(request.POST, request.FILES)
        if form_class.is_valid():
            messages.success(request, 'Владелец успешно добавлен')
        return super().post(self, request, *args, **kwargs)

class OwnerUpdateView(account_views.AdminPermissionMixin, UpdateView):
    model = CustomUser
    form_class = OwnerUserForm
    context_object_name = 'users'
    success_url = reverse_lazy('users:owner_list')
    template_name = 'users/owner_update_form.html'
    check_permission_name = 'owner'

    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs['label_suffix'] = ''
        return kwargs

    def post(self, request, *args, **kwargs):
        form_class = self.form_class(request.POST, request.FILES,
                                     instance=self.get_object())
        if form_class.is_valid():
            form_class.save(commit=False)
            form_class.save()
            messages.success(request, 'Владелец успешно обновлен')
            return HttpResponseRedirect(reverse_lazy('users:owner_list'))
        return render(request, self.template_name,
                      context={'form': form_class})

class OwnerDetailView(account_views.AdminPermissionMixin, DetailView):
    model = CustomUser
    template_name = 'users/owner_detail.html'
    check_permission_name = 'owner'
    queryset = CustomUser.objects.all(). \
        prefetch_related('flat_set__house__personalaccount_set')

class RequestsCreateView(account_views.AdminPermissionMixin, CreateView):
    model = Request
    success_url = reverse_lazy('users:requests_list')
    form_class = RequestForm
    check_permission_name = 'application'

    def get_context_data(self, **kwargs):
        context = super().get_context_data()
        context['masters'] = CustomUser.objects.filter(~Q(role=None))
        return context

class AjaxUserFlatsList(View):

    @staticmethod
    def get(request, *args, **kwargs):
        owner_id = request.GET.get('owner_id')
        query_flats = Flat.objects.filter(owner=owner_id)
        flat_list = list()
        for flat in query_flats:
            item = {
                'id': flat.id,
                'number': flat.number,
                'house': flat.house.title
            }
            flat_list.append(item)
        return JsonResponse({'flats': flat_list})

class RequestListView(account_views.AdminPermissionMixin, ListView):
    model = Request
    queryset = model.objects.all().select_related('flat__house', 'owner')
    check_permission_name = 'application'

    def get_context_data(self, *, object_list=None, **kwargs):
        context = super().get_context_data()
        context['owners'] = CustomUser.objects.filter(role=None)
        context['masters'] = CustomUser.objects.filter(~Q(role=None)). \
            select_related('role')
        return context

class RequestGetViewAjax(BaseDatatableView):
    model = Request
    columns = ['id', 'date', 'time', 'type_master',
               'description', 'flat', 'flat.house', 'flat.id',
               'owner', 'owner.id', 'owner.phone', 'master',
               'master.id', 'status']
    order_columns = ['id', 'date', 'type_master']

    def get_initial_queryset(self):
        return self.model.objects.all().select_related('flat__house',
                                                       'owner')

    def filter_queryset(self, qs):
        id = self.request.GET.get('id')
        date_range = self.request.GET.get('date_range')
        type_master = self.request.GET['type_master']
        description = self.request.GET.get('description')
        flat = self.request.GET.get('flat')
        owner = self.request.GET.get('owner')
        phone = self.request.GET.get('phone')
        master = self.request.GET.get('master')
        status = self.request.GET.get('status')
        if date_range:
            date_start = datetime.datetime.strptime(date_range.split(' - ')[0],
                                                    '%m/%d/%Y')
            date_end = datetime.datetime.strptime(date_range.split(' - ')[1],
                                                  '%m/%d/%Y')
            qs = qs.filter(Q(date__gt=date_start), Q(date__lt=date_end))
        if id:
            qs = qs.filter(id=id)
        if type_master:
            qs = qs.filter(type_master=type_master)
        if description:
            qs = qs.filter(description__contains=description)
        if flat:
            qs = qs.filter(
                Q(flat__contains=flat) | Q(flat__house__contains=flat))
        if owner:
            qs = qs.filter(owner=owner)
        if phone:
            qs = qs.filter(flat__owner__phone__contains=phone)
        if master:
            qs = qs.filter(master=master)
        if status:
            qs = qs.filter(status=status)
        return qs

class RequestDeleteAjax(DeleteView):

    def post(self, request, *args, **kwargs):
        if request.user.is_superuser or request.user.is_staff:
            request_id = request.POST.get('id')
            request_instance = get_object_or_404(Request, id=request_id)
            request_instance.delete()
            return JsonResponse({'success': 'success'})
        else:
            return JsonResponse(
                {'success': "У Вас недостаточно прав для удаления."}
            )

class RequestDetailView(account_views.AdminPermissionMixin, DetailView):
    model = Request
    check_permission_name = 'application'
    queryset = model.objects.all().select_related('flat__house',
                                                  'owner', 'master')

class RequestUpdateView(account_views.AdminPermissionMixin, UpdateView):
    model = Request
    template_name = 'users/request_update_form.html'
    success_url = reverse_lazy('users:requests_list')
    form_class = RequestForm
    check_permission_name = 'application'

    def get_context_data(self, **kwargs):
        context = super().get_context_data()
        context['masters'] = CustomUser.objects.filter(~Q(role=None))
        return context

class MessageListView(account_views.AdminPermissionMixin, ListView):
    model = Message
    check_permission_name = 'message'

    def get_context_data(self, *, object_list=None, **kwargs):
        return {}

class MessageAjaxList(BaseDatatableView):
    model = Message
    columns = ['id', 'title', 'text', 'date',
               'message_address_house_id',
               'message_address_section_id', 'message_address_floor_id',
               'message_address_flat_id']

    def get_initial_queryset(self):
        return self.model.objects.all().order_by('-date')

    def filter_queryset(self, qs):
        search_field = self.request.GET.get('search')
        if search_field:
            qs = qs.filter(Q(title__icontains=search_field)
                           | Q(text__icontains=search_field))
        return qs

class MessageCreateView(account_views.AdminPermissionMixin, CreateView):
    model = Message
    form_class = MessageForm
    template_name = 'users/message_form.html'
    check_permission_name = 'message'

    def post(self, request, *args, **kwargs):
        form_class = self.form_class(request.POST or None)
        if form_class.is_valid():
            form_class.save(commit=False)
            form_class.instance.sender = request.user
            form_class.save()
            users = CustomUser.objects.all().prefetch_related(
                'owner__personal_account__account_flat')
            message_for_deptors = request.POST.get('message_for_deptors')
            if message_for_deptors:
                users = users.filter(flat__personalaccount__balance__lt=0)
            house = request.POST.get('message_address_house_id')
            if house:
                users = users.filter(flat__house=house)
                section = request.POST.get('message_address_section_id')
                if section:
                    users = users.filter(flat__section=section)
                    floor = request.POST.get('message_address_floor_id')
                    if floor:
                        users = users.filter(flat__floor=floor)
                        flat = request.POST.get('message_address_flat_id')
                        if flat:
                            users = users.filter(flat=flat)
            MessageUsers.objects.bulk_create([MessageUsers(
                user=user, message=form_class.instance) for user in users])
            messages.success(request, 'Сообщение отправлено!')
            return HttpResponseRedirect(reverse_lazy('users:message_list'))
        else:
            return render(request, self.template_name, context={
                'form': form_class
            })

class MessageAjaxHouseInfo(View):
    @staticmethod
    def get(request):
        house = request.GET.get('house')
        sections = Section.objects.filter(house_id=house)
        floors = Floor.objects.filter(house_id=house)
        flats = Flat.objects.filter(house_id=house)
        section_list = list()
        floor_list = list()
        flat_list = list()
        for section in sections:
            instance = {
                'id': section.id,
                'title': section.title
            }
            section_list.append(instance)
        for floor in floors:
            instance = {
                'id': floor.id,
                'title': floor.title
            }
            floor_list.append(instance)
        for flat in flats:
            instance = {
                'id': flat.id,
                'title': flat.number
            }
            flat_list.append(instance)
        return JsonResponse({'section': section_list,
                             'floor': floor_list,
                             'flat': flat_list})

class MessageAjaxSectionInfo(View):
    @staticmethod
    def get(request):
        section = request.GET.get('section')
        floor = request.GET.get('floor')
        flats = Flat.objects.filter(section=section)
        if floor:
            flats = flats.filter(floor=floor)
        flat_list = list()
        for flat in flats:
            instance = {
                'id': flat.id,
                'title': flat.number
            }
            flat_list.append(instance)
        return JsonResponse({'flat': flat_list})

class MessageDetailView(account_views.AdminPermissionMixin, DetailView):
    model = Message
    check_permission_name = 'message'

    def get_queryset(self):
        return self.model.objects.filter(sender=self.request.user)

class MessageAjaxDelete(DeleteView):
    model = Message

    def post(self, request, *args, **kwargs):
        if request.user.is_superuser or request.user.is_staff:
            if request.POST.get('id'):
                message = get_object_or_404(Message, id=request.POST.get('id'))
                message.delete()
                return JsonResponse({'success': 'success'})
            messages_id = request.POST.get('deleted_list').split(',')
            messages = self.model.objects.filter(id__in=messages_id)
            messages.delete()
            return JsonResponse({'success': 'success'})
        else:
            return JsonResponse(
                {'success': "У Вас недостаточно прав для удаления."}
            )

class CabinetStatisticView(CabinetPermissionMixin, TemplateView):
    template_name = 'users/cabinet/statistics_for_flat.html'

    def get_context_data(self, **kwargs):
        context = dict()
        flat = get_object_or_404(Flat.objects.filter(owner=self.request.user).
                                 select_related('personal_account'),
                                 id=self.request.GET.get('flat_id'))
        context['personal_account'] = flat.personal_account
        context['flat'] = flat
        month_list = [number for number in range(1, 13)]
        payed_per_month = [Invoice.objects.
                           filter(flat=flat,
                                  date__month=number,
                                  status='Оплачена').
                           aggregate(Sum('amount'))
                           for number in month_list]
        payed_per_month_value = []
        for month in payed_per_month:
            if month.get('amount__sum'):
                payed_per_month_value.append(int(month.get('amount__sum')))
        if payed_per_month_value:
            context['average_per_month'] = sum(payed_per_month_value) / \
                                           len(payed_per_month_value)
        return context

class CabinetInvoicesListView(CabinetPermissionMixin, ListView):
    model = Invoice
    template_name = 'users/cabinet/invoice_users.html'

    def get_queryset(self):
        return self.model.objects.filter(flat__owner=self.request.user)

    def get_context_data(self, *, object_list=None, **kwargs):
        context = dict()
        context['status'] = status_invoice
        if self.request.GET.get('flat_id'):
            context['flat_id'] = self.request.GET.get('flat_id')
        return context

class CabinetInvoicesAjaxList(BaseDatatableView):
    model = Invoice
    columns = ['id', 'number', 'date', 'status', 'amount']
    order_columns = ['date']

    def get_initial_queryset(self):
        flat_id = self.request.GET.get('flat')
        user_id = self.request.GET.get('user')
        qs = self.model.objects.filter(flat__owner=self.request.user)
        if flat_id:
            qs = qs.filter(flat_id=flat_id)
        if user_id:
            qs = qs.filter(flat__owner__id=user_id)
        return qs

    def filter_queryset(self, qs):
        date = self.request.GET.get('date')
        status = self.request.GET.get('status')
        if status:
            qs = qs.filter(status=status)
        if date:
            date_formatting = datetime.datetime.strptime(date, '%m/%d/%Y')
            qs = qs.filter(date=date_formatting)
        return qs

class CabinetInvoicesDetail(CabinetPermissionMixin, DetailView):
    model = Invoice
    template_name = 'users/cabinet/invoice_users_detail.html'

    def get_queryset(self):
        return Invoice.objects.filter(flat__owner=self.request.user). \
            prefetch_related('invoiceservice_set__service__unit')

class CabinetTariffForFlatView(CabinetPermissionMixin, TemplateView):
    model = TariffService
    template_name = 'users/cabinet/tariff_for_flat.html'

    def get_queryset(self):
        qs = get_object_or_404(
            TariffService.objects
            .filter(tariff__flat__owner=self.request.user)
            .select_related(''),
            tariff=self.request.GET.get('flat_id'))
        return qs

    def get_context_data(self, **kwargs):
        context = dict()
        context['object'] = \
            get_object_or_404(Flat.objects.filter(owner=self.request.user)
                              .select_related('house'),
                              id=self.request.GET.get('flat_id'))
        context['tariff_services'] = \
            self.model.objects. \
                filter(tariff__flat=self.request.GET.get('flat_id')). \
                select_related('service__unit')
        return context

class MessageUserList(CabinetPermissionMixin, TemplateView):
    template_name = 'users/cabinet/message_users_list.html'

class MessageUserAjaxList(BaseDatatableView):
    model = MessageUsers
    columns = ['id', 'message.text', 'message.title', 'message.date',
               'message.sender', 'read']

    def get_initial_queryset(self):
        return self.model.objects.filter(user=self.request.user). \
            select_related('message').order_by('-message_id')

    def filter_queryset(self, qs):
        search_field = self.request.GET.get('search')
        if search_field:
            qs = qs.filter(Q(message__title__icontains=search_field)
                           | Q(message__text__icontains=search_field))
        return qs

class MessageUserAjaxDelete(CabinetPermissionMixin, DeleteView):
    model = MessageUsers

    def post(self, request, *args, **kwargs):
        if request.POST.get('id'):
            message = get_object_or_404(MessageUsers.objects
                                        .filter(user=self.request.user),
                                        id=request.POST.get('id'))
            if message.user is request.user:
                message.delete()
                return JsonResponse({'success': 'success'})
            else:
                return JsonResponse({'success': 'Это не ваше сообщение'})
        messages_id = request.POST.get('deleted_list').split(',')
        messages = self.model.objects.filter(id__in=messages_id)
        for message in messages:
            if message.user is request.user:
                message.delete()
        return JsonResponse({'success': 'success'})

class MessageUserDetailView(CabinetPermissionMixin, DetailView):
    template_name = 'users/cabinet/message_user_detail.html'

    def get_queryset(self):
        qs = MessageUsers.objects.filter(user=self.request.user). \
            select_related('message')
        return qs

    def get_context_data(self, **kwargs):
        message = self.object
        if not message.read:
            message.read = True
            message.save()
        return super().get_context_data()

class RequestUserListView(CabinetPermissionMixin, TemplateView):
    template_name = 'users/cabinet/request_user_list.html'

class RequestUserAjaxListView(BaseDatatableView):
    model = Request
    columns = ['id', 'type_master', 'description', 'date', 'time',
               'status']

    def get_initial_queryset(self):
        return self.model.objects.filter(owner_id=self.request.user.id) \
            .order_by('-id')

class RequestUserAjaxDelete(CabinetPermissionMixin, DeleteView):
    model = Request

    def post(self, request, *args, **kwargs):
        master_request_id = request.POST.get('id')
        master_request = get_object_or_404(Request, id=master_request_id)
        if any([master_request.owner is request.user,
                request.user.is_superuser]):
            master_request.delete()
            return JsonResponse({'success': 'success'})
        else:
            return JsonResponse({'success': 'Это не ваш запрос!'})

class RequestUserCreateView(CabinetPermissionMixin, CreateView):
    model = Request
    template_name = 'users/cabinet/request_user_form.html'
    form_class = RequestUserForm

    def post(self, request, *args, **kwargs):
        form_class = self.form_class(request.POST or None)
        if form_class.is_valid():
            form_class.save(commit=False)
            form_class.instance.owner = request.user
            form_class.save()
            return HttpResponseRedirect(
                reverse_lazy('users:request_user_view'))
        else:
            return render(request, self.template_name,
                          context={'form': form_class})

class ProfileUserView(CabinetPermissionMixin, TemplateView):
    template_name = 'users/cabinet/profile_user_view.html'

    def get_context_data(self, **kwargs):
        context = dict()
        context['flats'] = Flat.objects.filter(owner=self.request.user). \
            select_related('floor', 'house', 'section')
        return context

class ProfileUserUpdate(CabinetPermissionMixin, UpdateView):
    template_name = 'users/cabinet/profile_user_update_form.html'
    form_class = OwnerUserForm
    success_url = reverse_lazy('users:user_profile')

    def get_object(self, queryset=None):
        return self.request.user

def confirm_register(request, sign):
    email = signer.unsign((sign))
    user = CustomUser.objects.filter(email=email)
    if user.exists():
        user = user.first()
        user.is_active = True
        user.status = 'Новый'
        user.save()
        return HttpResponseRedirect(reverse_lazy('users:login'))
    else:
        return HttpResponseRedirect(
            f"{reverse_lazy('users:register')}?notconfirm=True")


import requests
import os
import sys
script_dir = os.path.dirname(os.path.abspath(__file__))
sys.path.append(os.path.dirname(script_dir))
from print_response import print_response

# https://pokeapi.co/api/v2

def main():
    count = 1
    url = 'http://pokeapi.co/api/v2/pokemon'
    headers = {'Accept': 'application/json'}
    params = {
        "limit": 200
    }
    resp = requests.get(url, headers=headers,params=params)
    resp.raise_for_status()

    data = resp.json()
    breakpoint()
    while data['next']:
        resp = requests.get(data['next'], headers=headers)
        resp.raise_for_status()
        count +=1
        print_response(resp, filename=f"pokemon/get_all_pokemon_{count}")
        data = resp.json()

    # for pokemon in resp.json()['results']:
    #     resp = requests.get(pokemon['url'], headers=headers)
    #     breakpoint()
    #     if resp.ok:
    #         print_response(
    #             resp, filename=f"/python_extra/req/pokemon/get_{pokemon['name']}")
    #     else:
    #         print(f"could not load {pokemon['name']} details")

if __name__ == '__main__':
    main()


import speech_recognition as sr
r=sr.Recognizer()
with sr.Microphone() as source:
	print("calibrating , wait")
	r.adjust_for_ambient_noise(source,duration=5)
	print("ok, speak now")
	audio=r.listen(source)
	print('done')

strin=r.recognize_sphinx(audio)
print(strin)


from flask import Flask
import compiler

app = Flask(__name__)

@app.route('/translate', methods=['POST'])
def index():
    try:
        code = compiler.compile(request.form['program'])
        return code
    except compiler.BrainfuckCompilerError:
        return '', 400

if __name__ == '__main__':
    print('Serving on :3000')
    app.run(port=3000)


import asyncio
import http.server
import json
import os
import socketserver
import threading
import time

import pyautogui
import websockets

PORT = 8000
WS_PORT = 8001

LIVE2D_FULL_PATH = ''
SERVER_ROOT = ''
LIVE2D_MODEL = ''

file_server = None

stop_event = threading.Event()

initialized = False
should_reload_page = False

def update_path(path, level):
    global SERVER_ROOT, LIVE2D_MODEL

    root = path

    while level > 0:
        root = os.path.dirname(root)
        level -= 1

    SERVER_ROOT = root
    LIVE2D_MODEL = path[len(root):]

    if LIVE2D_MODEL.startswith('/'):
        LIVE2D_MODEL = LIVE2D_MODEL[1:]

    # print('update_path ', SERVER_ROOT, '|', LIVE2D_MODEL)

try:
    import obspython as obs
except ModuleNotFoundError:
    with open(os.path.dirname(__file__) + '/private.json', 'r') as p_file:
        p_json = json.load(p_file)
        update_path(p_json['live2dModel'], p_json['rootLevel'])

def script_description():
    return 'Displays a cursor-focusing Live2D model'

def script_load(settings):
    pass

def prop_modified(props, prop, settings):
    # print('prop_modified ', obs.obs_property_name(prop))

    status = 'Invalid Path' if not SERVER_ROOT else 'Invalid Port' if PORT == WS_PORT else 'OK'

    obs.obs_data_set_string(settings, 'info', '''Server Root:
%s

Page URL:
http://127.0.0.1:%d

Status:
%s
''' % (SERVER_ROOT or '<empty>', PORT, status))

    level_p = obs.obs_properties_get(props, 'root_level')

    obs.obs_property_int_set_limits(level_p, 1, total_levels(LIVE2D_FULL_PATH), 1)

    return True

def total_levels(path):
    level = 1

    while 1:
        if os.path.dirname(path) == path:
            return level

        path = os.path.dirname(path)
        level += 1

def script_properties():
    # print('script_properties')

    props = obs.obs_properties_create()

    model_p = obs.obs_properties_add_path(props, 'live2d_model', 'Live2D Model',
                                          obs.OBS_PATH_FILE, 'Live2D Model(*.json)', '')

    level_p = obs.obs_properties_add_int(props, 'root_level', 'Server Root Level', 1, total_levels(LIVE2D_FULL_PATH), 1)

    port_p = obs.obs_properties_add_int(props, 'port', 'Server Port', 1024, 65535, 1)
    ws_port_p = obs.obs_properties_add_int(props, 'ws_port', 'Websocket Port', 1024, 65535, 1)

    info_p = obs.obs_properties_add_text(props, 'info', 'Info', obs.OBS_TEXT_MULTILINE)
    obs.obs_property_set_enabled(info_p, False)

    obs.obs_properties_add_button(props, 'start', 'Apply Settings', apply_settings)

    obs.obs_property_set_modified_callback(model_p, prop_modified)
    obs.obs_property_set_modified_callback(level_p, prop_modified)
    obs.obs_property_set_modified_callback(port_p, prop_modified)
    obs.obs_property_set_modified_callback(ws_port_p, prop_modified)

    return props

def script_defaults(settings):
    obs.obs_data_set_default_int(settings, 'root_level', 1)
    obs.obs_data_set_default_int(settings, 'port', PORT)
    obs.obs_data_set_default_int(settings, 'ws_port', WS_PORT)

def script_update(settings):
    global initialized, PORT, WS_PORT, LIVE2D_FULL_PATH

    # print('script_update')

    PORT = obs.obs_data_get_int(settings, "port")
    WS_PORT = obs.obs_data_get_int(settings, "ws_port")
    LIVE2D_FULL_PATH = obs.obs_data_get_string(settings, "live2d_model")
    level = obs.obs_data_get_int(settings, "root_level")

    update_path(LIVE2D_FULL_PATH, level)

    if not initialized:
        initialized = True
        start_server()

def script_unload():
    shutdown_server()

# Static file server

class RequestHandler(http.server.SimpleHTTPRequestHandler):

    def log_request(self, code='-', size='-'):
        pass

    def log_error(self, _format, *args):
        self.log_message('%s ' + _format, self.path, *args)

    def do_GET(self):
        if self.path == '/setup':
            res_json = json.dumps({
                'model': LIVE2D_MODEL,
                'wsPort': WS_PORT
            }).encode('utf-8')

            self.send_response(http.HTTPStatus.OK)
            self.send_header("Content-type", "application/json; charset=utf-8")
            self.send_header("Content-Length", str(len(res_json)))
            self.end_headers()

            self.wfile.write(res_json)
        else:
            super().do_GET()

    def translate_path(self, path):
        if path == '/index.html':
            return os.path.normpath(os.path.dirname(__file__) + '/index.html')

        result = super().translate_path(path)

        rel_path = os.path.relpath(result, os.getcwd())

        return os.path.join(SERVER_ROOT, rel_path)

def run_file_server():
    global file_server

    with socketserver.TCPServer(("", PORT), RequestHandler) as httpd:
        file_server = httpd
        httpd.serve_forever()

# Socket server

def run_ws_server():
    async def ws_handler(websocket, path):
        global should_reload_page

        try:
            if should_reload_page:
                should_reload_page = False
                await websocket.send('reload')

            while 1:
                await asyncio.sleep(0.02)
                await websocket.send(','.join(map(str, pyautogui.position())))
        except websockets.exceptions.ConnectionClosedOK:
            pass

    asyncio.set_event_loop(asyncio.new_event_loop())

    async def run_server(_stop):
        async with websockets.serve(ws_handler, 'localhost', WS_PORT):
            await _stop

    stop = asyncio.get_event_loop().run_in_executor(None, stop_event.wait)

    asyncio.get_event_loop().run_until_complete(run_server(stop))
    asyncio.get_event_loop().run_forever()

def apply_settings(*args):
    global should_reload_page

    should_reload_page = True
    start_server()

def start_server():
    if PORT == WS_PORT:
        print('Tow ports must not be the same (%s)' % PORT)
        return

    shutdown_server()

    time.sleep(0.5)

    server_thread = threading.Thread(target=run_file_server)
    server_thread.setDaemon(True)
    server_thread.start()

    ws_server_thread = threading.Thread(target=run_ws_server)
    ws_server_thread.setDaemon(True)
    ws_server_thread.start()

    print("Serving at port %d and %d" % (PORT, WS_PORT))

def shutdown_server():
    if file_server:
        file_server.shutdown()

    stop_event.set()
    stop_event.clear()

    print('Shutdown')

try:
    obs
except NameError:
    start_server()

    while 1:
        pass


from imutils.video import VideoStream, FPS
import MNR_Net
import time
import cv2
from argparse import ArgumentParser
from os import system

if __name__ == '__main__':
    system('clear')
    parser = ArgumentParser()
    parser.add_argument("-p", "--prototxt", required=False,type=str, default='MobileNetSSD_deploy.prototxt', help="path to Caffe 'deploy' prototxt file", metavar="FILE")
    parser.add_argument("-m", "--model", required=False,type=str, default = 'MobileNetSSD_deploy.caffemodel', help="path to Caffe pre-trained model", metavar="FILE")
    parser.add_argument("-co", "--confidence", required=False,type=float, default=0.7, help="minimum probability to filter weak detections")
    parser.add_argument("-g", "--gpu", required=False,type=bool, default=True, help="Enable GPU boost")
    parser.add_argument("-ca", "--caffe", required=False,type=bool, default=False, help="Enable Caffe transformInput")
    parser.add_argument("-he", "--height", required=False,type=int, default=300, help="Height of transformInput")
    parser.add_argument("-w", "--width", required=False,type=int, default=300, help="Width of transformInput")

    args = vars(parser.parse_args())
    mNet = MNR_Net.MNET(args['prototxt'], args['model'], args['gpu'], args['caffe'], args['height'], args['width'], args['confidence'])
    print("[INFO] starting video stream...")
    vs = VideoStream(src=0).start()
    time.sleep(0.1)
    fps = FPS().start()
    frameCount=0
    times = [0,0,0,0,0]

    while True:
        time1 = time.time()

        frame = vs.read()
        time2 = time.time()
        preFrame = mNet.transformInput(frame)
        time3 = time.time()
        netOut = mNet.MNetForward(preFrame)
        time4 = time.time()

        postFrame = mNet.getBoxedImage(frame, netOut)
        time5 = time.time()

        cv2.imshow("SSD", postFrame)
        time6 = time.time()

        times[0] = times[0]+time2-time1
        times[1] = times[1]+time3-time2
        times[2] = times[2]+time4-time3
        times[3] = times[3]+time5-time4
        times[4] = times[4]+time6-time5

        key = cv2.waitKey(1) & 0xFF
        # if the `q` key was pressed, break from the loop
        if key == ord("q"):
            break
        # update the FPS counter
        fps.update()
        frameCount = frameCount+1

    fps.stop()
    vs.stop()
    print("[INFO] elapsed time: {:.2f}".format(fps.elapsed())+" frame counter = "+str(frameCount))
    times[0] = (times[0]/frameCount)*1000000
    times[1] = (times[1]/frameCount)*1000000
    times[2] = (times[2]/frameCount)*1000000
    times[3] = (times[3]/frameCount)*1000000
    times[4] = (times[4]/frameCount)*1000000
    print("[INFO] elapsed time part: "+str(times))
    print("[INFO] approx. FPS: {:.2f}".format(fps.fps()))

    # do a bit of cleanup
    cv2.destroyAllWindows()


"""CLI providing some useful derivation-related utilities."""

import argparse
import os
import sys

from pynix import __version__
from pynix.derivation import Derivation
from pynix.binary_cache.client import NixCacheClient

def get_args():
    """Parse command-line arguments."""
    p_root = argparse.ArgumentParser(description="Derivation Utilities")
    p_root.add_argument("--version", action="version", version=__version__)
    subparsers = p_root.add_subparsers(title="Command", dest="command")
    subparsers.required = True

    # 'show' command
    p_show = subparsers.add_parser("show", help="Show a derivation.")
    p_show.add_argument("derivation_path", help="Path to the derivation.")
    p_show.add_argument("--json", action="store_const", const="json",
                        dest="format", help="JSON format.")
    p_show.add_argument("--yaml", action="store_const", const="yaml",
                        dest="format", help="YAML format.")
    p_show.add_argument("--string", action="store_const", const="string",
                        dest="format", help="Raw derivation format.")
    p_show.add_argument("-p", "--pretty", action="store_true", default=False,
                        help="Pretty-print.")
    p_show.add_argument("-A", "--attribute", help="Attribute to show.")
    p_show.add_argument("-e", "--env-vars", nargs="+",
                        help="Environmant variable to show.")
    p_show.add_argument("-o", "--output",
                        help="Show the path of the given output.")

    # 'diff' command
    p_diff = subparsers.add_parser("diff", help="Diff two derivations.")
    p_diff.add_argument("first", help="Path to the first derivation.")
    p_diff.add_argument("second", help="Path to the second derivation.")

    # 'preview' command
    p_preview = subparsers.add_parser("preview",
        help="Show paths needed to build a derivation.")
    p_preview.add_argument("derivation_paths", nargs="*",
                          help="Paths to derivations.")
    p_preview.add_argument("-c", "--binary-cache",
                           default=os.environ.get("NIX_REPO_HTTP"),
                           help="URL of a binary cache to query for paths.")
    p_preview.add_argument("--show-existing", action="store_true",
                           default=False, help="Show paths already existing.")
    p_preview.add_argument("--show-outputs", action="store_true",
                           default=False,
                           help="Show output names that will be built, "
                                "rather than paths.")
    p_preview.add_argument("--count", action="store_true", default=False,
                           help="Only show path count, don't print paths")
    return p_root.parse_args()

def main():
    """Main entry point."""
    args = get_args()
    if args.command == "show":
        path = args.derivation_path
        if "!" in path:
            path = path.split("!")[0]
        deriv = Derivation.parse_derivation_file(path)
        print(deriv.display(
            attribute=args.attribute,
            env_vars=args.env_vars,
            output=args.output,
            format=args.format,
            pretty=args.pretty))
    elif args.command == "diff":
        first = Derivation.parse_derivation_file(args.first)
        second = Derivation.parse_derivation_file(args.second)
        print(first.diff(second))
    elif args.command == "preview":
        if len(args.derivation_paths) > 0:
            paths = args.derivation_paths
        elif not sys.stdin.isatty():
            paths = (p.strip() for p in sys.stdin)
        else:
            sys.exit("No path arguments given")
        print_preview(paths, binary_cache=args.binary_cache,
                      show_existing=args.show_existing,
                      show_outputs=args.show_outputs,
                      numbers_only=args.count)
    else:
        sys.exit("Command {} not implemented".format(repr(args.command)))

if __name__ == "__main__":
    main()


#
# PET CEMETARY
# A Virtual Pet Game
# With Python 2.7 / Pygame
# Marshall Ehlinger
# 10-30-15
#

import sys, pygame, time, random
import ghost, food, house

def getLinesFromFile(sourceFile):
	with open(sourceFile) as doc:
		lines = []
		for line in doc:
			lines.append(line.rstrip('\r\n'))
		return lines

def main():

	FRAMERATE = 60
	DEBOUNCE = 0.05
	BLACK = 0, 0, 0
	WHITE = 255, 255, 255
	GRAY = 131, 131, 131
	QUIP_SOURCE = "pet_cemetary/quips.txt"

	pygame.init()

	font = pygame.font.SysFont("monospace", 14)
	quips = getLinesFromFile(QUIP_SOURCE)
	quipRendered = False

	clock = pygame.time.Clock()
	timer = 0
	size = width, height = 320, 240

	RUNNING = True	#'constant' to keep loops running

	ghostPet = ghost.Ghost()
	eatableFood = food.Food(width/2, (height/4)*3)
	hauntableHouse = house.House(width/5, (height/4)*3)

	speed = [1,1]

	screen = pygame.display.set_mode(size)

	# Ghost images
	neutralNeutral = pygame.image.load("pet_cemetary/assets/neutralneutral.bmp")
	neutralSad = pygame.image.load("pet_cemetary/assets/neutralsad.bmp")
	neutralHappy = pygame.image.load("pet_cemetary/assets/neutralhappy.bmp")
	skinnySad = pygame.image.load("pet_cemetary/assets/skinnysad.bmp")
	skinnyHappy = pygame.image.load("pet_cemetary/assets/skinnyhappy.bmp")
	fatSad = pygame.image.load("pet_cemetary/assets/fatsad.bmp")
	fatHappy = pygame.image.load("pet_cemetary/assets/fathappy.bmp")

	foodImg = pygame.image.load("pet_cemetary/assets/food.bmp")
	houseImg = pygame.image.load("pet_cemetary/assets/house.bmp")

	ghostRect = neutralNeutral.get_rect()
	foodRect = foodImg.get_rect()
	houseRect = houseImg.get_rect()

	houseRect.x = hauntableHouse.getX()
	houseRect.y = hauntableHouse.getY()
	foodRect.x = eatableFood.getX()
	foodRect.y = eatableFood.getY()

	while RUNNING:
		clock.tick(FRAMERATE)

		timer += 1
		if (timer >= FRAMERATE * 20):
			ghostPet.depleteDrives()
			quipRendered = False
			timer = 0

		if ghostRect.colliderect(foodRect) and not eatableFood.isEaten():
			ghostPet.adjustNourishment(10)
			eatableFood.setEaten(True)
			if not quipRendered:
				label = font.render(random.choice(quips), 1, BLACK)
				quipRendered = True

		if ghostRect.colliderect(houseRect) and not hauntableHouse.isHaunted():
			ghostPet.adjustHappiness(10)
			hauntableHouse.setHaunted(True)
			if not quipRendered:
				label = font.render(random.choice(quips), 1, BLACK)
				quipRendered = True

		for event in pygame.event.get():
				if event.type == pygame.QUIT: sys.exit()
				elif event.type == pygame.KEYDOWN:
					if event.key == pygame.K_ESCAPE:
						sys.exit()
					# DEBUGGING CONTROLS FOR DEVELOPMENT
					elif event.key == pygame.K_DOWN:
					 	eatableFood.setEaten(False)
					elif event.key == pygame.K_UP:
					 	hauntableHouse.setHaunted(False)
					elif event.key == pygame.K_q:
						return

		ghostRect = ghostRect.move(speed)

		if ghostRect.left < 0 or ghostRect.right > width:
			speed[0] = -speed[0]
		if ghostRect.top < 0 or ghostRect.bottom > height:
			speed[1] = -speed[1]

		screen.fill(GRAY)

		happy = ghostPet.getHappiness()
		nourish = ghostPet.getNourishment()

		# Replace this godawful block with a function, maybe switch
		if happy > 50 and nourish > 60:
			currentGhostImg = fatHappy
		elif happy > 50 and nourish <= 60 and nourish >= 40:
			currentGhostImg = neutralHappy
		elif happy > 50 and nourish < 40:
			currentGhostImg = skinnyHappy
		elif happy < 60 and happy > 40 and nourish <= 60 and nourish >= 40:
			currentGhostImg = neutralNeutral
		elif happy < 50 and nourish > 60:
			currentGhostImg = fatSad
		elif happy < 50 and nourish < 40:
			currentGhostImg = skinnySad
		elif happy <= 60 and nourish <= 60 and nourish >= 40:
			currentGhostImg = neutralSad

		screen.blit(currentGhostImg, ghostRect)

		if not eatableFood.isEaten():
			screen.blit(foodImg, foodRect)
		if not hauntableHouse.isHaunted():
			screen.blit(houseImg, houseRect)

		if quipRendered:
			screen.blit(label, (50, 50))

		pygame.display.flip()

if __name__ == "__main__":
	main()


import flask
import os
import werkzeug

app = flask.Flask(__name__)
app.debug = True

@app.route("/", methods=['GET', 'POST'])
def Galerey():
    if flask.request.method == 'GET':
        directory = 'static'
        files = os.listdir(directory)
        return flask.render_template('Galerey.html', fileslist=files)
    try:
        fs = flask.request.files['image']
        fs.save('static/' + werkzeug.secure_filename(fs.filename))
    except ValueError:
        return flask.render_template('Galerey.html', error="Ошибки!")
    return flask.redirect('/')

app.run()


from lib.data_worker import DataWorker

import time
import requests
import re
from urllib import parse as urllib_parse

req_headers = {
    'Connection':'keep-alive',
    'Cache-Control': 'max-age=0',
    'Upgrade-Insecure-Requests': '1',
    'User-Agent': 'hcmc.io.bot.v1',
    'Accept-Encoding': 'gzip, deflate',
    'Accept-Language': 'en-US,en;q=0.9',
}

REDDIT_REQUEST_TEMPLATE = "https://www.reddit.com/r/%s/about.json"
REDDIT_ID_REGEX = re.compile(r"\/r\/([\d\w\-\_\.]+)/?")

class RedditMembersRawDataWorker(DataWorker):
    update_frequency = 60 * 10

    def __init__(self):
        pass

    def fetch_data(self):
        r = requests.get("http://db.xyz.hcmc.io/data/coins.json")
        data = r.json()

        for row in data:
            if not row:
                continue

            if not ('community' in row and 'reddit' in row['community']):
                # There is not reddit links for current row item
                continue

            links = row['community']['reddit']

            if not links:
                # There is not reddit links for current row item
                continue

            data = dict(
                ts=int(time.time()),
                members=0,
                members_active=0,
            )

            for link in links:
                url = urllib_parse.urlparse(link)
                matches = REDDIT_ID_REGEX.findall(url.path)

                if not matches:
                    continue

                page_id = matches[0]

                # slow down to prevent ip ban
                time.sleep(0.5)
                r = requests.get(REDDIT_REQUEST_TEMPLATE % page_id, headers=req_headers)

                resp = r.json()

                if 'error' in resp:
                    if resp['error'] == 403:
                        # private community
                        continue

                    elif resp['error'] == 404:
                        # doesn't exists or banned
                        continue

                if 'kind' in resp and resp['kind'] == 'Listing':
                    # this is not sub reddit (skipping)
                    continue

                resp = resp['data']

                data['members'] += resp['subscribers']
                data['members_active'] += resp['active_user_count']

            self.save(row['id'], data)

    def save(self, coin_id, data):
        if data is None:
            return

        # In real parser we will get last entry from db and check if current data differs
        # from latest saved and if not we will skip it.

        print(coin_id, data)


from os import path
import re

import telebot
from telebot.types import InlineKeyboardMarkup, InlineKeyboardButton,\
ReplyKeyboardMarkup, KeyboardButton

from bot_config import CONFIG
from utils import *
from classes import Sound, Album, Author

sound = None
album = None
author = None

bot = telebot.TeleBot(CONFIG.get('TOKEN'))

keyboard = ReplyKeyboardMarkup()
keyboard.add(
    KeyboardButton('/start')
)

@bot.message_handler(commands=['start'])
def handle_start(message):
    keyboard = InlineKeyboardMarkup()
    keyboard.add(
        InlineKeyboardButton('Search sound', callback_data='search_sound')
    )
    keyboard.add(
        InlineKeyboardButton('Get 10 random sounds', callback_data='rand_sounds')
    )

    keyboard.add(
        InlineKeyboardButton('Search author', callback_data='search_author')
    )
    keyboard.add(
        InlineKeyboardButton('Search album', callback_data='search_album')
    )

    keyboard.add(
        InlineKeyboardButton('Wanna upload something?', callback_data='upload_request')
    )
    keyboard.add(
        InlineKeyboardButton('About', callback_data='about')
    )

    bot.send_message(
        message.chat.id,
        f'Welcome',
        reply_markup=keyboard
    )

@bot.callback_query_handler(func=lambda cb: 'about' == cb.data)
def handle_about(query):
    bot.send_message(
        query.message.chat.id,
        'This bot allows you to store music in telegram.\nBot created by rogulik, github is https://github.com/rogulikAFC/sound-storage-bot-DRF-telebot'
    )

@bot.callback_query_handler(func=lambda cb: 'search_sound' == cb.data)
def handle_search_sound_cb(query):
    keyboard = InlineKeyboardMarkup()
    keyboard.add(
        InlineKeyboardButton('Back', callback_data='back')    # Not working
    )

    message = bot.send_message(
        query.message.chat.id,
        'Say me name of sound',
        reply_markup=keyboard
    )

    bot.register_next_step_handler(message, process_sound_title_step)

def process_sound_title_step(message):
    # keyboard = InlineKeyboardMarkup()

    # keyboard.add(
    #     InlineKeyboardButton(
    #         'It isn\'t. Show me next 10, please', callback/start_data=f'send_sounds_list_{search_page + 1}'
    #     )
    # )
    # keyboard.add(
    #     InlineKeyboardButton('Back', callback_data='back')    # Not working
    # )

    for sound in Sound.search_sounds(message.text, ):  # pagination and filters needed
        id = sound.get('id')
        title = sound.get('title')
        authors = ', '.join(author.get('title') for author in sound.get('authors'))

        sound_keyboard = InlineKeyboardMarkup()
        sound_keyboard.add(
            InlineKeyboardButton('That\'s it!', callback_data=f'sound_detail_{id}')
        )

        bot.send_message(
            message.chat.id,
            f'{title} - {authors}',
            reply_markup=sound_keyboard
        )

    bot.send_message(
        message.chat.id,
        'That\'s all',
    )

@bot.callback_query_handler(func=lambda cb: 'sound_detail_' in cb.data)
def sound_detail(query):
    id = query.data.split('_')[-1]
    sound = Sound.get_sound_info(id)

    cover_url = sound.get('cover_url')
    cover = get_cover(cover_url)

    audio_url = sound.get('sound_url')
    audio = Sound.get_sound_file(audio_url)

    authors = ', '.join(author.get('title') for author in sound.get('authors'))

    bot.send_photo(
        query.message.chat.id,
        ('new_image.jpg', cover),
        f'{sound.get("title")} - {authors}'
    )
    bot.send_audio(
        query.message.chat.id,
        audio,
        title=f'{sound.get("title")} - {authors}'
    )

@bot.callback_query_handler(func=lambda cb: 'rand_sounds' == cb.data)
def handle_random_sounds(query):    # need to create endpoint
    for sound in get_random_sounds():
        id = sound.get('id')
        title = sound.get('title')
        authors = ', '.join(author.get('title') for author in sound.get('authors'))

        sound_keyboard = InlineKeyboardMarkup()
        sound_keyboard.add(
            InlineKeyboardButton('Listen to it!', callback_data=f'sound_detail_{id}')
        )

        bot.send_message(
            query.message.chat.id,
            f'{title} - {authors}',
            reply_markup=sound_keyboard
        )

    keyboard = InlineKeyboardMarkup()
    keyboard.add(
        InlineKeyboardButton('Next 10', callback_data='rand_sound')
    )
    keyboard.add(
        InlineKeyboardButton('Back', callback_data='back')
    )

    bot.send_message(
        query.message.chat.id,
        'That\'s all',
        reply_markup=keyboard
    )

@bot.callback_query_handler(func=lambda cb: 'upload_request' == cb.data)
def handle_upload_request(query):
    keyboard = InlineKeyboardMarkup()
    keyboard.add(
        InlineKeyboardButton('Sound', callback_data='upload_sound')
    )
    keyboard.add(
        InlineKeyboardButton('Group album from sounds', callback_data='group_album')
    )
    keyboard.add(
        InlineKeyboardButton('Create new author', callback_data='create_author')
    )
    keyboard.add(
        InlineKeyboardButton('Back', callback_data='back')
    )

    bot.send_message(
        query.message.chat.id,
        'What do you want to upload?',
        reply_markup=keyboard
    )

@bot.callback_query_handler(func=lambda cb: 'upload_sound' == cb.data)
def handle_upload_sound(query):
    message = bot.send_message(
        query.message.chat.id,
        'Write sound name'
    )

    bot.register_next_step_handler(message, process_upload_sound_title_step)

def process_upload_sound_title_step(message):
    global sound
    sound = Sound(message.text)

    msg = bot.send_message(
        message.chat.id,
        'Upload cover image'
    )

    bot.register_next_step_handler(msg, process_upload_sound_cover_step)

def process_upload_sound_cover_step(message):
    global sound

    cover_image_info = None

    try:
        cover_image_info = bot.get_file(message.photo[0].file_id)

    except:
        msg = bot.send_message(
            message.chat.id,
            'You have uploaded not png or jpg file, upload png or jpg file'
        )
        bot.register_next_step_handler(msg, process_upload_sound_cover_step)

    extension_pattern = r'\.[^.]+$'

    extension = re.search(
        extension_pattern, cover_image_info.file_path
    ).group(0)

    file = bot.download_file(cover_image_info.file_path)

    with open(f'new_image{extension}', 'wb') as new_file:
        new_file.write(file)

    file = open(f'new_image{extension}', 'rb')
    sound.cover = file.read()

    msg = bot.send_message(
        message.chat.id,
        'Upload sound file'
    )

    bot.register_next_step_handler(msg, process_upload_sound_file_and_authors_step)

def process_upload_sound_file_and_authors_step(message):
    global sound

    sound_file_info = None

    try:
        sound_file_info = bot.get_file(message.audio.file_id)

    except:
        msg = bot.send_message(
            message.chat.id,
            'You have uploaded not mp3 file, upload mp3 file'
        )
        bot.register_next_step_handler(msg, process_upload_sound_file_and_authors_step)
        return

    file = bot.download_file(sound_file_info.file_path)

    with open('new_file.mp3', 'wb') as new_file:
        new_file.write(file)

    file = open('new_file.mp3', 'rb')
    sound.sound = file.read()

    msg = bot.send_message(
        message.chat.id,
        'Ok, now select authors'
    )

    for author in get_authors_by_title(message.text):
        id = author.get('id')
        title = author.get('title')

        author_keyboard = InlineKeyboardMarkup()
        author_keyboard.add(
            InlineKeyboardButton('That\'s it!', callback_data=f'select_sound_author_{id}')
        )

        bot.send_message(
            message.chat.id,
            title,
            reply_markup=author_keyboard
        )

    keyboard = InlineKeyboardMarkup()
    keyboard.add(
        InlineKeyboardButton('Yes, upload sound to database', callback_data='upload_sound_to_db')
    )
    keyboard.add(
        InlineKeyboardButton('No, exit', callback_data='upload_sound')
    )

    bot.send_message(
        message.chat.id,
        'Upload sound?',
        reply_markup=keyboard
    )

@bot.callback_query_handler(func=lambda cb: cb.data.startswith('select_sound_author_'))
def add_author_to_sound(query):
    id = query.data.split('_')[-1]

    try:
        sound.authors.append(id)

    except:
        bot.send_message(
            query.message.chat.id,
            'Ooops... Somthing went wrong. This error may occur, when you already selected all authors'
        )

    print(sound.title, sound.authors)

@bot.callback_query_handler(func=lambda cb: 'upload_sound_to_db' == cb.data)
def upload_sound_to_db(query):
    global sound

    if sound.upload_to_database():
        bot.send_message(
            query.message.chat.id,
            'Uploaded!'
        )

    else:
        bot.send_message(
            query.message.chat.id,
            'Something went wrong, file not uploaded'
        )

    sound = None

@bot.callback_query_handler(func=lambda cb: 'search_album' == cb.data)
def search_album(query):
    keyboard = InlineKeyboardMarkup()
    keyboard.add(
        InlineKeyboardButton('Back', callback_data='back')    # Not working
    )

    message = bot.send_message(
        query.message.chat.id,
        'Say me name of album',
        reply_markup=keyboard
    )

    bot.register_next_step_handler(message, process_album_title_step)

def process_album_title_step(message):
    for album in Album.search_albums(message.text):
        id = album.get('id')
        title = album.get('title')
        authors = ', '.join(author.get('title') for author in album.get('authors'))

        album_keyboard = InlineKeyboardMarkup()
        album_keyboard.add(
            InlineKeyboardButton('That\'s it!', callback_data=f'album_detail_{id}')
        )

        bot.send_message(
            message.chat.id,
            f'{title} - {authors}',
            reply_markup=album_keyboard
        )

    bot.send_message(
        message.chat.id,
        'That\'s all',
    )

@bot.callback_query_handler(func=lambda cb: 'album_detail_' in cb.data)
def album_detail(query):
    id = query.data.split('_')[-1]
    album_info = Album.get_album_info(id)

    authors = ', '.join(author.get('title') for author in album_info.get('authors'))
    title = album_info.get('title')

    cover = get_cover(album_info.get('cover_url'))

    bot.send_photo(
        query.message.chat.id,
        ('new_image.jpg', cover),
        f'{title} - {authors}'
    )

    sounds = album_info.get('sounds')

    for sound in sounds:
        id = sound.get('id')
        title = sound.get('title')
        authors = ', '.join(author.get('title') for author in sound.get('authors'))

        sound_keyboard = InlineKeyboardMarkup()
        sound_keyboard.add(
            InlineKeyboardButton('Listen it', callback_data=f'sound_detail_{id}')
        )

        bot.send_message(
            query.message.chat.id,
            f'{title} - {authors}',
            reply_markup=sound_keyboard
        )

@bot.callback_query_handler(func=lambda cb: 'group_album' == cb.data)
def group_album(query):
    msg = bot.send_message(
        query.message.chat.id,
        'Write album title'
    )

    bot.register_next_step_handler(msg, group_album_title_step)

def group_album_title_step(message):
    global album
    album = Album(message.text)
    msg = bot.send_message(
        message.chat.id,
        'Upload album cover'
    )

    bot.register_next_step_handler(msg, group_album_cover_step)

def group_album_cover_step(message):
    cover_image_info = None

    try:
        cover_image_info = bot.get_file(message.photo[0].file_id)

    except:
        msg = bot.send_message(
            message.chat.id,
            'You have uploaded not png or jpg file, upload png or jpg file'
        )
        bot.register_next_step_handler(msg, group_album_cover_step)

    extension_pattern = r'\.[^.]+$'

    extension = re.search(
        extension_pattern, cover_image_info.file_path
    ).group(0)

    file = bot.download_file(cover_image_info.file_path)

    with open(f'new_image{extension}', 'wb') as new_file:
        new_file.write(file)

    file = open(f'new_image{extension}', 'rb')
    album.cover = file.read()

    bot.send_message(
        message.chat.id,
        'Select sounds'
    )

    for sound in get_sounds():
        id = sound.get('id')
        title = sound.get('title')
        authors = ', '.join(author.get('title') for author in sound.get('authors'))

        sound_keyboard = InlineKeyboardMarkup()
        sound_keyboard.add(
            InlineKeyboardButton('That\'s it!', callback_data=f'select_album_sound_{id}')
        )

        bot.send_message(
            message.chat.id,
            f'{title} - {authors}',
            reply_markup=sound_keyboard
        )

    keyboard = InlineKeyboardMarkup()
    keyboard.add(
        InlineKeyboardButton('Yes, upload album to database', callback_data='upload_album_to_db')
    )
    keyboard.add(
        InlineKeyboardButton('No, exit', callback_data='group_album')
    )

    bot.send_message(
        message.chat.id,
        'Upload album to database?',
        reply_markup=keyboard
    )

@bot.callback_query_handler(func=lambda cb: 'select_album_sound_' in cb.data)
def select_album_sound(query):
    global album

    id = query.data.split('_')[-1]

    try:
        album.sounds.append(id)

    except:
        bot.send_message(
            query.message.chat.id,
            'Ooops... Somthing went wrong. This error may occur, when you already selected all sounds'
        )

    print(album.title, album.sounds)

@bot.callback_query_handler(func=lambda cb: 'upload_album_to_db' == cb.data)
def upload_album_to_db(query):
    global album

    if album.upload_to_database():
        bot.send_message(
            query.message.chat.id,
            'Uploaded!'
        )

    else:
        bot.send_message(
            query.message.chat.id,
            'Something went wrong, album not uploaded'
        )

    album = None

@bot.callback_query_handler(func=lambda cb: 'create_author' == cb.data)
def upload_author(query):
    msg = bot.send_message(
        query.message.chat.id,
        'Write author title'
    )

    bot.register_next_step_handler(msg, upload_author_title)

def upload_author_title(message):
    global author
    author = Author(message.text)
    msg = bot.send_message(
        message.chat.id,
        'Upload author description'
    )

    bot.register_next_step_handler(msg, upload_author_description)

def upload_author_description(message):
    global author
    author.description = message.text

    if author.upload_to_database():
        bot.send_message(
            message.chat.id,
            'Uploaded!'
        )

    else:
        bot.send_message(
            message.chat.id,
            'Something went wrong, author not created'
        )

@bot.callback_query_handler(func=lambda cb: 'search_author' == cb.data)
def search_author(query):
    msg = bot.send_message(
        query.message.chat.id,
        'Write author title',
    )

    bot.register_next_step_handler(msg, search_author_title_step)

def search_author_title_step(message):
    for author in Author.search_authors(message.text):
        id = author.get('id')
        title = author.get('title')

        author_keyboard = InlineKeyboardMarkup()
        author_keyboard.add(
            InlineKeyboardButton(
                'View this author',
                callback_data=f'author_detail_{id}'
            )
        )

        bot.send_message(
            message.chat.id,
            title,
            reply_markup=author_keyboard
        )

    bot.send_message(
        message.chat.id,
        'That\'s all'
    )

@bot.callback_query_handler(func=lambda cb: 'author_detail_' in cb.data)
def author_detail(query):
    author_id = query.data.split('_')[-1]
    author = Author.get_author_info(author_id)

    bot.send_message(
        query.message.chat.id,
        f'''
        <b> {author.get("title")} </b> \n\n{author.get("description")}
        ''',
        parse_mode='HTML'
    )

    bot.send_message(
        query.message.chat.id,
        '<b> Sounds: </b>',
        parse_mode='HTML'
    )

    for sound in author.get('sounds'):
        id = sound.get('id')
        title = sound.get('title')

        sound_keyboard = InlineKeyboardMarkup()
        sound_keyboard.add(
            InlineKeyboardButton(
                'Listen it', callback_data=f'sound_detail_{id}'
            )
        )

        bot.send_message(
            query.message.chat.id,
            f'{title}',
            reply_markup=sound_keyboard
        )

    bot.send_message(
        query.message.chat.id,
        '<b> Albums: </b>',
        parse_mode='HTML'
    )

    for album in author.get('albums'):
        id = album.get('id')
        title = album.get('title')
        authors = ', '.join(author.get('title') for author in album.get('authors'))

        album_keyboard = InlineKeyboardMarkup()
        album_keyboard.add(
            InlineKeyboardButton(
                'View', callback_data=f'album_detail_{id}'
            )
        )

        bot.send_message(
            query.message.chat.id,
            f'{title} - {authors}',
            reply_markup=album_keyboard
        )

@bot.callback_query_handler(func=lambda cb: 'back' == cb.data)
def back(query):
    handle_start(query.message)

bot.infinity_polling()


from selenium import webdriver
import time
from selenium.webdriver.support.select import Select
#
#implicit wait:
# driver.implicitly_wait(n)
# Global wait for each action;
# maximum wait is n seconds
# if wait is less than n seconds, following actions resume

# alert = driver.switch_to.alert
# alert.accept()
# Java, javascript alert
driver = webdriver.Chrome()
# driver = webdriver.Firefox()
# url = "https://rahulshettyacademy.com/angularpractice/"
# url = "https://www.makemytrip.com/"
# url = "https://rahulshettyacademy.com/AutomationPractice/"

driver.implicitly_wait(1000)
url ="https://rahulshettyacademy.com/seleniumPractise/"

driver.get(url)
print(driver.title)
print(driver.current_url)
# driver.maximize_window()

# @@ 5. wait
css_select = "input[class='search-keyword']"
# or
# css_select = "input.search-keyword"
driver.find_element_by_css_selector(css_select).send_keys("ber")
time.sleep(3)
# //div[@class='products']/div
xpath_sel = "//div[@class='products']/div"
products = driver.find_elements_by_xpath(xpath_sel)

# assert len(products) == 3
print(len(products))

buttons_to_click = driver.find_elements_by_xpath("//div[@class='product-action']/button")

for button in buttons_to_click:
    button.click()
    # break
# time.sleep(29)
shopping_cart = driver.find_element_by_css_selector("img[alt='Cart']")
shopping_cart.click()

checkout = driver.find_element_by_xpath("//button[text()='PROCEED TO CHECKOUT']")
checkout.click()

promo_code = driver.find_element_by_class_name("promoCode")
promo_code.send_keys("rahulshettyacademy")

driver.find_element_by_css_selector(".promoBtn").click()

print(driver.find_element_by_css_selector("span.promoInfo").text)
time.sleep(3)
driver.close()