from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth.decorators import login_required
from allauth.account.forms import LoginForm
from django.core.paginator import Paginator
from django.urls import reverse
from django.db.models import Count, Sum, Prefetch, F, OuterRef, Exists, Subquery, Q
from django.db.models.functions import Round
from django.utils import timezone
from django.http import QueryDict, JsonResponse, HttpResponseBadRequest, HttpResponseForbidden, HttpResponse
from django.template.loader import render_to_string
from django import forms
import datetime
import openpyxl
from openpyxl.utils import get_column_letter
from openpyxl.styles import Font
from farmerapp.models import Farmer, Region, Culture, CatalogLandingFields, CultureableName
from crm.models import Interaction
from contacts.models import ContactPerson, ContactDetail
from .forms import CultureFilterForm, FarmerForm, LandingFieldForm, ContactDetailForm
from common.utils import is_supervisor, is_manager
from contacts.forms import AddExistingContactPersonForm
from dal import autocomplete


def get_filtered_farmers(request, user, region=None, district=None):
    query_params = request.GET.copy()
    if 'page' in query_params:
        del query_params['page']
    query_string = query_params.urlencode()

    if is_supervisor(user):
        farmers = Farmer.objects.all()
    elif is_manager(user):
        farmers = Farmer.objects.filter(
            Q(client_status='unprocessed') |
            Q(interactions__user=user) |
            Q(interactions__assigned_to=user)
        ).distinct()
    else:
        return Farmer.objects.none()

    erdpou = query_params.get('erdpou', None)
    selected_culture = query_params.get('culture', None)
    selected_culture_name = query_params.get('selected_culture_name', None)
    selected_status = query_params.get('status', None)
    filter_landing_area = query_params.get('landing_area_filter', None)
    filter_total_landing_area = query_params.get('total_landing_area_filter', None)
    active_cultures = CultureableName.objects.filter(active=True)

    if erdpou:
        farmers = farmers.filter(erdpou=erdpou)
        active_cultures = CultureableName.objects.none()
    else:
        if region and district:
            farmers = farmers.filter(region__name=region, district__name=district)
        elif region:
            farmers = farmers.filter(region__name=region)
        if selected_culture and selected_culture != 'all':
            farmers = farmers.filter(
                catalog_landing_fields__cultureable_name__in=active_cultures,
                catalog_landing_fields__cultureable_name__cultureable_name=selected_culture
            )
        if selected_culture_name:
            farmers = farmers.filter(cultureable_names__cultureable_name=selected_culture_name)

    if selected_status:
        if selected_status == 'unprocessed':
            farmers = farmers.filter(client_status='unprocessed')
        else:
            farmers = farmers.filter(client_status=selected_status)

    farmers = farmers.annotate(total_landing_area=Sum('catalog_landing_fields__culture_area'))

    if filter_landing_area:
        farmers = apply_landing_area_filter(farmers, filter_landing_area)

    if filter_total_landing_area:
        farmers = apply_total_landing_area_filter(farmers, filter_total_landing_area)

    farmers = farmers.prefetch_related('cultureable_names')

    if is_supervisor(user):
        farmers = farmers.prefetch_related(
            Prefetch(
                'interactions',
                queryset=Interaction.objects.all().order_by('date').prefetch_related('cultures', 'user')
            )
        )
    else:
        farmers = farmers.prefetch_related(
            Prefetch(
                'interactions',
                queryset=Interaction.objects.filter(assigned_to=user).order_by('date').prefetch_related('cultures',
                                                                                                        'user')
            )
        )
    return farmers


@login_required(login_url='accounts/login/')
def home(request, region=None, district=None):
    user = request.user
    farmers = get_filtered_farmers(request, user, region, district)
    regions = Region.objects.all().prefetch_related('district_set')

    query_params = request.GET.copy()
    if 'page' in query_params:
        del query_params['page']
    query_string = query_params.urlencode()

    erdpou = query_params.get('erdpou', None)
    selected_culture = query_params.get('culture', None)
    selected_culture_name = query_params.get('selected_culture_name', None)
    selected_status = query_params.get('status', None)
    filter_landing_area = query_params.get('landing_area_filter', None)
    filter_total_landing_area = query_params.get('total_landing_area_filter', None)
    active_cultures = CultureableName.objects.filter(active=True)

    class CultureFilterForm(forms.Form):
        culture = forms.ModelChoiceField(queryset=active_cultures, empty_label=None, initial=selected_culture)

    culture_filter_form = CultureFilterForm()

    all_culture_names = CultureableName.objects.filter(active=True)

    all_cultures = active_cultures.values_list('cultureable_name', flat=True)

    sort = query_params.get('sort', None)
    direction = query_params.get('direction', 'asc') if sort else 'asc'
    if sort:
        if direction == 'desc':
            sort = '-' + sort
        farmers = farmers.order_by(sort).distinct()

    paginator = Paginator(farmers, 20)
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)

    for farmer in page_obj:
        interactions = list(farmer.interactions.all())
        for i in range(len(interactions)):
            current_interaction = interactions[i]
            if i < len(interactions) - 1:
                next_interaction = interactions[i + 1]
                if current_interaction.next_interaction_date and next_interaction.date:
                    if isinstance(next_interaction.date, datetime.datetime):
                        next_interaction_date_value = next_interaction.date.date()
                    else:
                        next_interaction_date_value = next_interaction.date

                    if isinstance(current_interaction.next_interaction_date, datetime.datetime):
                        current_next_interaction_date_value = current_interaction.next_interaction_date.date()
                    else:
                        current_next_interaction_date_value = current_interaction.next_interaction_date

                    delta = (next_interaction_date_value - current_next_interaction_date_value).days
                    if delta == 0:
                        current_interaction.interaction_status = 'on_time'
                    elif delta > 0:
                        current_interaction.interaction_status = 'late'
                    else:
                        current_interaction.interaction_status = 'early'
                else:
                    current_interaction.interaction_status = 'no_next_interaction_date'
            else:
                if current_interaction.next_interaction_date:
                    if isinstance(current_interaction.next_interaction_date, datetime.datetime):
                        current_next_interaction_date_value = current_interaction.next_interaction_date.date()
                    else:
                        current_next_interaction_date_value = current_interaction.next_interaction_date

                    delta = (timezone.now().date() - current_next_interaction_date_value).days
                    if delta > 0:
                        current_interaction.interaction_status = 'overdue'
                    else:
                        current_interaction.interaction_status = 'pending'
                else:
                    current_interaction.interaction_status = 'no_next_interaction_date'

    context = {
        'page_obj': page_obj,
        'regions': regions,
        'selected_region': region,
        'selected_district': district,
        'all_cultures': all_cultures,
        'selected_culture': selected_culture,
        'all_culture_names': all_culture_names,
        'selected_culture_name': selected_culture_name,
        'sort_direction': direction,
        'culture_filter_form': culture_filter_form,
        'query_string': query_string,
        'erdpou': erdpou,
        'selected_status': selected_status,
        'filter_landing_area': filter_landing_area,
        'filter_total_landing_area': filter_total_landing_area,
        'today': timezone.now().date(),
    }

    return render(request, 'home.html', context)


def apply_landing_area_filter(farmers, filter_value):
    if filter_value == '0-100':
        return farmers.filter(landing_area__gte=0, landing_area__lt=100)
    elif filter_value == '100-300':
        return farmers.filter(landing_area__gte=100, landing_area__lt=300)
    elif filter_value == '300-500':
        return farmers.filter(landing_area__gte=300, landing_area__lt=500)
    elif filter_value == '500-1000':
        return farmers.filter(landing_area__gte=500, landing_area__lt=1000)
    elif filter_value == '1000-3000':
        return farmers.filter(landing_area__gte=1000, landing_area__lt=3000)
    elif filter_value == '3000-5000':
        return farmers.filter(landing_area__gte=3000, landing_area__lt=5000)
    elif filter_value == '5000+':
        return farmers.filter(landing_area__gte=5000)
    else:
        return farmers


def apply_total_landing_area_filter(farmers, filter_value):
    if filter_value == '0-100':
        return farmers.filter(total_landing_area__gte=0, total_landing_area__lt=100)
    elif filter_value == '100-300':
        return farmers.filter(total_landing_area__gte=100, total_landing_area__lt=300)
    elif filter_value == '300-500':
        return farmers.filter(total_landing_area__gte=300, total_landing_area__lt=500)
    elif filter_value == '500-1000':
        return farmers.filter(total_landing_area__gte=500, total_landing_area__lt=1000)
    elif filter_value == '1000-3000':
        return farmers.filter(total_landing_area__gte=1000, total_landing_area__lt=3000)
    elif filter_value == '3000-5000':
        return farmers.filter(total_landing_area__gte=3000, total_landing_area__lt=5000)
    elif filter_value == '5000+':
        return farmers.filter(total_landing_area__gte=5000)
    else:
        return farmers


@login_required(login_url='accounts/login/')
def export_farmers_xlsx(request, region=None, district=None):
    user = request.user
    farmers = get_filtered_farmers(request, user, region, district)

    wb = openpyxl.Workbook()
    ws = wb.active
    ws.title = "Farmers"

    headers = [
        "Повна назва",
        "Код ЄДРПОУ",
        "Поштова адреса",
        "ПІБ",
        "Телефони",
        "Площа",
        "Культури",
        "Менеджер",
        "Дата останнього редагування",
    ]
    ws.append(headers)

    for cell in ws[1]:
        cell.font = Font(bold=True)

    for farmer in farmers:
        phones = ", ".join(filter(None, [
            farmer.phone_1,
            farmer.phone_2,
            farmer.phone_3,
            farmer.phone_4,
            farmer.phone_5,
            farmer.phone_6,
            farmer.phone_7,
            farmer.phone_mobile_1,
            farmer.phone_mobile_2,
            farmer.phone_mobile_3,
            farmer.phone_mobile_4,
            farmer.phone_mobile_5,
        ]))
        cultures = ", ".join([culture.cultureable_name for culture in farmer.cultureable_names.all()])
        manager = request.user.get_full_name() if farmer.interactions.all() else "Немає взаємодій"
        last_updated = farmer.last_updated
        if last_updated:
            last_updated_str = last_updated.strftime("%Y-%m-%d %H:%M:%S")
        else:
            last_updated_str = ""

        data = [
            farmer.name,
            farmer.erdpou,
            farmer.address,
            farmer.director,
            phones,
            farmer.landing_area,
            cultures,
            manager,
            last_updated_str,
        ]
        ws.append(data)

    for column_cells in ws.columns:
        length = max(len(str(cell.value) or "") for cell in column_cells)
        ws.column_dimensions[get_column_letter(column_cells[0].column)].width = length + 2

    response = HttpResponse(content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
    filename = 'farmers.xlsx'
    response['Content-Disposition'] = f'attachment; filename={filename}'
    wb.save(response)

    return response


@login_required(login_url='accounts/login/')
def farmer_detail(request, farmer_id=None):
    farmer = get_object_or_404(Farmer, id=farmer_id)
    user = request.user

    if is_supervisor(user):
        pass
    elif is_manager(user):
        if farmer.client_status == 'unprocessed' or farmer.interactions.filter(
                Q(user=user) | Q(assigned_to=user)).exists():
            pass
        else:
            return HttpResponseForbidden("Ви не маєте доступу до цього фермера.")
    else:
        return HttpResponseForbidden("Ви не маєте доступу до цього фермера.")

    catalog_landing_fields = farmer.catalog_landing_fields.all()
    landing_fields_count = catalog_landing_fields.count()
    contact_persons = farmer.contact_persons.prefetch_related('contact_details')

    context = {
        'farmer': farmer,
        'catalog_landing_fields': catalog_landing_fields,
        'landing_fields_count': landing_fields_count,
        'contact_persons': contact_persons
    }
    return render(request, 'farmer_detail.html', context)


@login_required(login_url='accounts/login/')
def farmer_general_info(request, farmer_id):
    farmer = get_object_or_404(Farmer, id=farmer_id)
    user = request.user

    # Перевірка прав доступу
    if is_supervisor(user):
        pass
    elif is_manager(user):
        if farmer.client_status == 'unprocessed' or farmer.interactions.filter(
                Q(user=user) | Q(assigned_to=user)).exists():
            pass
        else:
            return HttpResponseForbidden("Ви не маєте доступу до цього фермера.")
    else:
        return HttpResponseForbidden("Ви не маєте доступу до цього фермера.")

    contact_persons = farmer.contact_persons.prefetch_related('contact_details')

    context = {
        'farmer': farmer,
        'contact_persons': contact_persons
    }
    return render(request, 'farmer_general_info.html', context)


@login_required(login_url='accounts/login/')
def farmer_land_bank(request, farmer_id):
    farmer = get_object_or_404(Farmer, id=farmer_id)
    user = request.user

    # Перевірка прав доступу
    if is_supervisor(user):
        pass
    elif is_manager(user):
        if farmer.client_status == 'unprocessed' or farmer.interactions.filter(
                Q(user=user) | Q(assigned_to=user)).exists():
            pass
        else:
            return HttpResponseForbidden("Ви не маєте доступу до цього фермера.")
    else:
        return HttpResponseForbidden("Ви не маєте доступу до цього фермера.")

    catalog_landing_fields = farmer.catalog_landing_fields.all()
    landing_fields_count = catalog_landing_fields.count()

    context = {
        'farmer': farmer,
        'catalog_landing_fields': catalog_landing_fields,
        'landing_fields_count': landing_fields_count
    }
    return render(request, 'farmer_land_bank.html', context)


@login_required(login_url='accounts/login/')
def edit_farmer(request, farmer_id):
    farmer = get_object_or_404(Farmer, id=farmer_id)

    if request.method == 'POST':
        if request.headers.get('x-requested-with') == 'XMLHttpRequest':
            field_name = request.POST.get('field_name')
            field_value = request.POST.get('field_value')
            if field_name and hasattr(farmer, field_name):
                setattr(farmer, field_name, field_value)
                farmer.save()
                return JsonResponse({'success': True})
            else:
                return HttpResponseBadRequest('Invalid field name')

        form = FarmerForm(request.POST, instance=farmer)
        if form.is_valid():
            form.save()
            return redirect('farmer_detail', farmer_id=farmer_id)
    else:
        form = FarmerForm(instance=farmer)
    return render(request, 'edit_farmer.html', {'form': form})


@login_required(login_url='accounts/login/')
def add_landing_field(request, farmer_id):
    farmer = Farmer.objects.get(id=farmer_id)
    if request.method == 'POST':
        form = LandingFieldForm(request.POST)
        if form.is_valid():
            landing_field = form.save(commit=False)
            landing_field.farmer = farmer
            landing_field.save()
            return redirect('farmer_detail', farmer_id=farmer_id)
    else:
        form = LandingFieldForm()
    return render(request, 'add_landing_field.html', {'form': form})


@login_required(login_url='accounts/login/')
def add_farmer(request):
    if request.method == 'POST':
        form = FarmerForm(request.POST)
        if form.is_valid():
            farmer = form.save()
            return redirect('farmer_success', farmer_id=farmer.id)
    else:
        form = FarmerForm()
    return render(request, 'add_farmer.html', {'form': form})


@login_required(login_url='accounts/login/')
def farmer_success(request, farmer_id):
    return render(request, 'farmer_success.html', {'farmer_id': farmer_id})


@login_required
def add_contact_detail(request, person_id):
    contact_person = get_object_or_404(ContactPerson, id=person_id)
    if request.method == 'POST':
        form = ContactDetailForm(request.POST)
        if form.is_valid():
            contact_detail = form.save(commit=False)
            contact_detail.contact_person = contact_person
            contact_detail.save()
            html = render_to_string('contacts/contact_detail_item.html', {'detail': contact_detail}, request=request)
            return JsonResponse({'success': True, 'html': html})
        else:
            html = render_to_string('contacts/contact_detail_form.html', {'form': form}, request=request)
            return JsonResponse({'success': False, 'html': html})
    else:
        form = ContactDetailForm()
        html = render_to_string('contacts/contact_detail_form.html', {'form': form}, request=request)
        return JsonResponse({'html': html})


@login_required
def edit_contact_detail(request, detail_id):
    contact_detail = get_object_or_404(ContactDetail, id=detail_id)
    if request.method == 'POST':
        form = ContactDetailForm(request.POST, instance=contact_detail)
        if form.is_valid():
            form.save()
            html = render_to_string('contacts/contact_detail_item.html', {'detail': contact_detail}, request=request)
            return JsonResponse({'success': True, 'html': html})
        else:
            html = render_to_string('contacts/contact_detail_form.html', {'form': form}, request=request)
            return JsonResponse({'success': False, 'html': html})
    else:
        form = ContactDetailForm(instance=contact_detail)
        html = render_to_string('contacts/contact_detail_form.html', {'form': form}, request=request)
        return JsonResponse({'html': html})


@login_required
def delete_contact_detail(request, detail_id):
    contact_detail = get_object_or_404(ContactDetail, id=detail_id)
    if request.method == 'POST':
        contact_detail.delete()
        return JsonResponse({'success': True})
    else:
        return JsonResponse({'success': False})


@login_required
def add_existing_contact_person(request, farmer_id):
    farmer = get_object_or_404(Farmer, id=farmer_id)
    if request.method == 'POST':
        form = AddExistingContactPersonForm(request.POST)
        if form.is_valid():
            contact_person = form.cleaned_data['contact_person']
            farmer.contact_persons.add(contact_person)
            html = render_to_string('contacts/contact_person_item.html', {'contact_person': contact_person}, request=request)
            return JsonResponse({'success': True, 'html': html})
        else:
            html = render_to_string('contacts/add_existing_contact_person_form.html', {'form': form}, request=request)
            return JsonResponse({'success': False, 'html': html})
    else:
        form = AddExistingContactPersonForm()
        html = render_to_string('contacts/add_existing_contact_person_form.html', {'form': form}, request=request)
        return JsonResponse({'html': html})


class FarmerAutocomplete(autocomplete.Select2QuerySetView):
    def get_queryset(self):
        qs = Farmer.objects.all()

        if self.q:
            qs = qs.filter(name__icontains=self.q)

        return qs
