import datetime
import openpyxl
from rest_framework import status
from rest_framework.views import APIView
from django.views.generic import TemplateView
from rest_framework.response import Response
from gauth.models import Location, LocationManager
from django.http import Http404
from django.shortcuts import render, redirect
from django.views.generic import View
from django.contrib import messages
from user.forms import StaffRegistrationForm, StaffSheetDateForm, GoogleReviewsFilter, FacebookReviewsFilter
from review.models import Review
from yelp.models import YelpReview
from facebook_app.models import FacebookReview
from name_extractor.models import Staff
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.shortcuts import get_object_or_404
from .analytics import weekly_positive_review_count, get_weeks, weekly_negative_review_count
from name_extractor.utils import extract_names_from_reviews, make_all_staffs_point_zero

from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
from user.utils import (
    get_google_review_report,
    get_facebook_report,
    get_yelp_review_report,
    date_str2datetime
)
from .forms import ImportStaffSpreadSheet

LOC_SYN = {
    'cypress-1960': 'cypress',
    'collegestation': 'college station'
}


class LocationListView(View, PermissionRequiredMixin):
    permission_required = 'is_staff'

    def post(self, request, *args, **kwargs):
        form = ImportStaffSpreadSheet(request.POST, request.FILES)
        if form.is_valid():
            staff_file = form.cleaned_data.get('staff_file')
            wb = openpyxl.load_workbook(staff_file)
            worksheet = wb.worksheets[0]

            rows = worksheet.values
            col_names = next(rows)

            try:
                name_idx, loc_idx, dept_idx = col_names.index('Name'), col_names.index('Location'), col_names.index('Job Title')
            except ValueError:
                messages.warning(request, "Columns in missing. Check columns ['Name', 'Location', 'Job Title'] again.")
                return redirect('location-list')

            # Clear all previously registered staffs
            staffs = Staff.objects.all()
            staffs.delete()
            for row in rows:
                try:
                    name, loc, dept = row[name_idx], row[loc_idx], row[dept_idx]
                except IndexError:
                    pass
                if loc.lower() in ['alllocations', '#n/a']:
                    continue
                if loc.lower() in LOC_SYN.keys():
                    loc = LOC_SYN[loc.lower()]

                location = Location.objects.filter(care_name__icontains=loc).first()
                if location:
                    Staff.objects.create(
                        name=name,
                        location=location,
                        department=dept
                    )
            messages.success(request, 'Staff file upload successfully.')
        return redirect('location-list')

    def get(self, request, *args, **kwargs):
        locations = Location.objects.all()
        form = ImportStaffSpreadSheet()
        context = {
            'all_locations': locations,
            'file_upload_form': form
        }
        return render(request, 'locations.html', context=context)


class LocationAnalytics(LoginRequiredMixin, View):
    def get(self, request, location_id, *args, **kwargs):
        location = Location.objects.get(pk=location_id)
        google_report = get_google_review_report(location_id)
        facebook_report = get_facebook_report(location_id)
        yelp_report = get_yelp_review_report(location_id)
        context = {
            'location': location,
            'google_this_month_pos': google_report.get('this_month_pos'),
            'google_last_month_pos': google_report.get('last_month_pos'),
            'facebook_this_month_pos': facebook_report.get('this_month_pos'),
            'facebook_last_month_pos': facebook_report.get('last_month_pos'),
            'google_this_month_neg': google_report.get('this_month_neg'),
            'google_last_month_neg': google_report.get('last_month_neg'),
            'facebook_this_month_neg': facebook_report.get('this_month_neg'),
            'facebook_last_month_neg': facebook_report.get('last_month_neg'),
            'yelp': yelp_report
        }
        return render(request, 'manager-dashboard.html', context=context)


class ReviewListLocationWise(View):
    def get(self, request, platform, location_id,  *args, **kwargs):
        location = Location.objects.get(pk=location_id)
        if platform == 'google':
            form = GoogleReviewsFilter()
            reviews = Review.objects.filter(location_id=location_id).order_by('-update_time')
        elif platform == 'facebook':
            form = FacebookReviewsFilter()
            reviews = FacebookReview.objects.filter(page__location_id=location_id).order_by('-create_time')
        elif platform == 'yelp':
            form = GoogleReviewsFilter()
            reviews = YelpReview.objects.filter(location__location_id=location_id).order_by('-date_posted')
        else:
            raise Http404()

        page = request.GET.get('page', 1)
        paginator = Paginator(reviews, 50)
        try:
            reviews = paginator.page(page)
        except PageNotAnInteger:
            reviews = paginator.page(1)
        except EmptyPage:
            reviews = paginator.page(paginator.num_pages)
        context = {'reviews': reviews, 'platform': platform, 'location': location, 'form': form}
        return render(request, 'review-list-man.html', context=context)

    def post(self, request, platform, location_id,  *args, **kwargs):
        location = Location.objects.get(pk=location_id)
        if platform == 'google':
            form = GoogleReviewsFilter(data=request.POST)
            start_date = date_str2datetime(request.POST.get('start_date'))
            end_date = date_str2datetime(request.POST.get('end_date'))
            if end_date < start_date:
                start_date, end_date = end_date, start_date
            star_rating = int(request.POST.get('star_ratings'))
            reviews = Review.objects.filter(location_id=location_id).order_by('-update_time')
            if start_date and end_date:
                if star_rating > 5:
                    reviews = reviews.filter(create_time__range=(start_date, end_date))
                else:
                    reviews = reviews.filter(create_time__range=(start_date, end_date), star_rating=star_rating)
        elif platform == 'yelp':
            form = GoogleReviewsFilter(data=request.POST)
            start_date = date_str2datetime(request.POST.get('start_date'))
            end_date = date_str2datetime(request.POST.get('end_date'))
            if end_date < start_date:
                start_date, end_date = end_date, start_date
            star_rating = int(request.POST.get('star_ratings'))
            reviews = YelpReview.objects.filter(location__location_id=location_id).order_by('-date_posted')
            if start_date and end_date:
                if star_rating > 5:
                    reviews = reviews.filter(date_posted__range=(start_date, end_date))
                else:
                    reviews = reviews.filter(date_posted__range=(start_date, end_date), rating=star_rating)

        elif platform == 'facebook':
            form = FacebookReviewsFilter(request.POST)
            start_date = date_str2datetime(request.POST.get('start_date'))
            end_date = date_str2datetime(request.POST.get('end_date'))
            star_rating = int(request.POST.get('star_ratings'))

            reviews = FacebookReview.objects.filter(page__location_id=location_id).order_by('-create_time')
            if start_date and end_date:
                if star_rating > 5:
                    reviews = reviews.filter(create_time__range=(start_date, end_date))
                else:
                    reviews = reviews.filter(create_time__range=(start_date, end_date), recommendation_type=bool(star_rating))
        else:
            raise Http404()

        page = request.GET.get('page', 1)
        paginator = Paginator(reviews, 50)
        try:
            reviews = paginator.page(page)
        except PageNotAnInteger:
            reviews = paginator.page(1)
        except EmptyPage:
            reviews = paginator.page(paginator.num_pages)
        context = {'reviews': reviews, 'platform': platform, 'location': location, 'form': form}
        return render(request, 'review-list-man.html', context=context)


class ReviewAnalyticsGraph(View):

    def get(self, request, location_id, *args, **kwargs):
        location = Location.objects.get(pk=location_id)
        return render(request, 'location-wise-reviews-man.html', context={'location': location})


class StaffLeaderBoard(View):

    def get(self, request, location_id, *args, **kwargs):
        location = Location.objects.get(pk=location_id)
        staffs = Staff.objects.filter(location=location).order_by('-total_units')
        form = StaffRegistrationForm()
        date_form = StaffSheetDateForm()

        context = {
            'location': location,
            'staffs': staffs,
            'date_form': date_form,
            'form': form
        }
        return render(request, 'staff_list_man.html', context)

    def post(self, request, location_id, *args, **kwargs):
        form = StaffRegistrationForm(request.POST)
        if form.is_valid():
            name = form.cleaned_data.get('name')
            department = form.cleaned_data.get('department')
            nick_names = form.cleaned_data.get('nick_names')
            staff = Staff.objects.create(
                name=name,
                location_id=location_id,
                department=department,
                nick_names=nick_names
            )
            messages.success(request, f'A new staff {staff} has been created!')
        return redirect('staff-leaderboard-man', location_id=location_id)


class SyncStaffLeaderBoard(View):

    def post(self, request, location_id, *args, **kwargs):
        start_date = date_str2datetime(request.POST.get('start_date'))
        end_date = date_str2datetime(request.POST.get('end_date'))

        extract_names_from_reviews(
            start_date=start_date,
            end_date=end_date,
            location_id=location_id
        )
        return redirect('staff-leaderboard-man', location_id=location_id)


class StaffDelete(View):

    def get(self, request, staff_id, *args, **kwargs):
        staff = get_object_or_404(Staff, id=staff_id)
        staff.delete()
        return redirect('staff-leaderboard-man', location_id=staff.location_id)


class AllLocationSummary(APIView):
    def get(self, request, *args, **kwargs):
        days = request.GET['days']
        if not days:
            return Response({'error': 'No location Found'}, status=status.HTTP_400_BAD_REQUEST)
        locations = Location.objects.all()
        review_counts = []
        for location in locations:
            loc_json = {
                'name': location.care_name,
                'positive': [
                    location.last_week_pos_google_review_count,
                    location.last_week_pos_facebook_review_count,
                    location.last_week_pos_yelp_review_count
                ],
                'negative': [
                    location.last_week_neg_google_review_count,
                    location.last_week_neg_facebook_review_count,
                    location.last_week_neg_yelp_review_count
                ]
            }
            review_counts.append(loc_json)
        response = {
            'labels': ['Google', 'Facebook', 'Yelp'],
            'review_counts': review_counts,
        }
        return Response(response)


class ReviewAnalysis(APIView):
    def get(self, request, *args, **kwargs):
        now = datetime.datetime.now()
        pos_ratings, labels = weekly_positive_review_count()
        neg_ratings = weekly_negative_review_count()
        weeks = get_weeks(now.year, now.isocalendar()[1])
        weeks = [datetime.date.fromisocalendar(w[1], w[0], 7) for w in weeks]
        response = {
            "weeks": weeks,
            "pos_data": pos_ratings,
            "neg_data": neg_ratings,
            "labels": labels
        }
        return Response(response)


class ReviewAnalysisAllPlatformView(LoginRequiredMixin, TemplateView):
    template_name = 'review-analysis.html'