from django.db import connection
from django.db.models import Q
from django.utils.dateparse import parse_date
from django.utils.timezone import make_aware
from rest_framework import status, viewsets
from rest_framework.filters import OrderingFilter, SearchFilter
from rest_framework.response import Response
from rest_framework.views import APIView
from django_filters.rest_framework import DjangoFilterBackend

from organisations.models import OrganisationBranch
from questbanker_api.utils import get_current_user
from .helper import *
from mmbanking.models import *
from mmbanking.serializers import *


class CustomerSearchViewSet(viewsets.ModelViewSet):
    """
    Handles searching and listing of customers.
    Supports both:
    - Standard organisation filtering (by logged-in user's organisation)
    - Dashboard use (by `organisation_ids` in query params)
    - Filtering by branch, status, customer type, and registration date
    """

    serializer_class = CustomerSearchSerializer
    queryset = CustomerSearch.objects.none()
    filter_backends = [SearchFilter, OrderingFilter, DjangoFilterBackend]
    search_fields = [
        "name",
        "member_number",
        "old_member_number",
        "nin",
        "telephone",
        "physical_address",
        "villagename",
        "subcountyname",
        "districtname",
        "branch_name",
        "customer_type_name",
    ]
    ordering_fields = ["name", "member_number", "date_added"]

    def get_queryset(self):
        request = self.request
        ordering = request.GET.get("ordering", "name")
        organisation_ids = request.GET.get("organisation_ids", None)
        search_term = request.GET.get("search", "").strip()
        branch_id = request.GET.get("branch_id", None)
        status_param = request.GET.get("status", None)
        customer_type_id = request.GET.get("customer_type_id", None)
        start_date = request.GET.get("start_date", None)
        end_date = request.GET.get("end_date", None)
        # Keep backward compatibility with old "date_added" param
        date_added = request.GET.get("date_added", None)

        filter_query = {}

        # 🔹 Organisation filtering
        if organisation_ids:
            try:
                org_ids = [
                    int(x) for x in organisation_ids.split(",") if x.strip().isdigit()
                ]
                filter_query["organisation_id__in"] = org_ids
            except ValueError:
                return CustomerSearch.objects.none()
        else:
            organisation_id = get_current_user(self.request, "organisation_id", None)
            if organisation_id:
                filter_query["organisation_id"] = organisation_id
            else:
                return CustomerSearch.objects.none()

        queryset = CustomerSearch.objects.filter(**filter_query, is_deleted=False)

        # 🔹 Basic filters
        if branch_id:
            queryset = queryset.filter(branch_id=branch_id)
        if status_param:
            queryset = queryset.filter(status__iexact=status_param)
        if customer_type_id:
            queryset = queryset.filter(customer_type_id=customer_type_id)

        # 🔹 Date filtering logic
        if start_date:
            parsed_start = parse_date(start_date)
            if parsed_start:
                queryset = queryset.filter(date_added__date__gte=parsed_start)

        if end_date:
            parsed_end = parse_date(end_date)
            if parsed_end:
                queryset = queryset.filter(date_added__date__lte=parsed_end)

        # Keep legacy support if only "date_added" param is sent
        if not start_date and not end_date and date_added:
            parsed_date = parse_date(date_added)
            if parsed_date:
                queryset = queryset.filter(date_added__date__lte=parsed_date)

        # 🔹 Search filter
        if search_term:
            queryset = queryset.filter(
                Q(name__icontains=search_term)
                | Q(member_number__icontains=search_term)
                | Q(old_member_number__icontains=search_term)
                | Q(nin__icontains=search_term)
                | Q(telephone__icontains=search_term)
                | Q(physical_address__icontains=search_term)
                | Q(villagename__icontains=search_term)
                | Q(subcountyname__icontains=search_term)
                | Q(districtname__icontains=search_term)
                | Q(branch_name__icontains=search_term)
                | Q(customer_type_name__icontains=search_term)
            )

        return queryset.order_by(ordering)

    def list(self, request, *args, **kwargs):
        """
        Paginated list response — consistent with DRF pagination.
        """
        queryset = self.filter_queryset(self.get_queryset())
        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data, status=status.HTTP_200_OK)


class SavingsAccountSearchViewSet(viewsets.ModelViewSet):
    serializer_class = SavingsAccountSearchSerializer
    filter_backends = (
        OrderingFilter,
        DjangoFilterBackend,
    )
    filterset_fields = ["branch_id", "customer_type_id"]

    def get_queryset(self):
        search = self.request.GET.get("search", None)
        status = self.request.GET.get("status", "all")
        start_date = self.request.GET.get("start", None) or self.request.GET.get("start_date", None)
        end_date = self.request.GET.get("end", None) or self.request.GET.get("end_date", None)
        organisation_id = get_current_user(self.request, "organisation_id", None)

        if organisation_id:
            filter_query = {"deleted": False, "organisation_id": organisation_id}

            if status != "all":
                filter_query["status"] = status

            parsed_start = parse_date(start_date) if start_date else None
            parsed_end = parse_date(end_date) if end_date else None

            if parsed_start and parsed_end and parsed_start > parsed_end:
                parsed_start, parsed_end = parsed_end, parsed_start

            # Respect the requested date range using the date portion of open_date.
            if parsed_start and parsed_end:
                filter_query["open_date__date__range"] = (parsed_start, parsed_end)
            elif parsed_start:
                filter_query["open_date__date__gte"] = parsed_start
            elif parsed_end:
                filter_query["open_date__date__lte"] = parsed_end

            if search:
                use_old_mem_no = OrganisationSetting.objects.filter(
                    org_setting__id=organisation_id,
                    setting_key="use_old_mem_no",
                    setting_value="on",
                ).first()

                if use_old_mem_no:
                    return SavingsAccountSearch.objects.filter(
                        Q(customer_old_member_number__icontains=str(search))
                        | Q(customer_name__icontains=search),
                        **filter_query
                    )
                else:
                    return SavingsAccountSearch.objects.filter(
                        Q(customer_member_number__icontains=str(search))
                        | Q(customer_name__icontains=search),
                        **filter_query
                    )
            else:
                return SavingsAccountSearch.objects.filter(**filter_query)

        return SavingsAccountSearch.objects.filter(status=status)


class CustomerStatusViewSet(viewsets.ModelViewSet):
    serializer_class = SavingsAccountSearchSerializer
    filter_backends = (
        OrderingFilter,
        DjangoFilterBackend,
    )
    filterset_fields = [
        "branch_id",
    ]

    def get_queryset(self):
        status = self.request.GET.get("search", None)
        organisation_id = get_current_user(self.request, "organisation_id", None)
        filter_query = {"deleted": False, "organisation_id": organisation_id}
        return SavingsAccountSearch.objects.filter(**filter_query).distinct("status")


class CustomerSearchAPIView(APIView):
    def get(self, request, format=None):
        q_filters = {}
        branch_ids = []
        request_data = self.request.query_params
        start_date = request_data.get("start", None)
        end_date = request_data.get("end", None)
        branch_id = request_data.get("customer_branch", None)
        page = request_data.get("page", 1)
        ordering = request_data.get("ordering", None)
        search = request_data.get("search", None)
        page_size = request_data.get("page_size", 50)

        source_customer_type_id = self.request.GET.get("source_customer_type_id", None)
        has_members = self.request.GET.get("has_members", False)
        date_added = self.request.GET.get("date_added", None)

        if start_date:
            start_date = make_aware(datetime.strptime(start_date, "%Y-%m-%d"))
        if end_date:
            end_date = make_aware(datetime.strptime(end_date, "%Y-%m-%d"))
        organisationid = get_current_user(self.request, "organisation_id", 1)

        if branch_id:
            branch_ids.append(int(branch_id))
        else:
            branch_ids = OrganisationBranch.objects.filter(
                branch_organisation__id=organisationid
            ).values_list("id", flat=True)

        q_filters["ordering"] = ordering
        q_filters["start_date"] = start_date
        q_filters["end_date"] = end_date
        q_filters["has_members"] = has_members
        q_filters["search"] = search
        q_filters["page"] = page
        q_filters["page_size"] = page_size
        q_filters["is_deleted"] = False
        q_filters["branch_ids"] = branch_ids
        q_filters["organisation_id"] = organisationid
        q_filters["source_customer_type_id"] = source_customer_type_id

        if date_added:
            end_date = make_aware(datetime.strptime(date_added, "%Y-%m-%d"))
            q_filters["end_date"] = end_date

        query_set = retrieve_customers(q_filters)
        return Response(query_set)


class CustomerCardSearchViewSet(viewsets.ModelViewSet):
    serializer_class = CustomerSearchSerializer
    filter_backends = (DjangoFilterBackend,)
    filterset_fields = ["branch_id", "customer_type_id"]
    response = []

    def get_queryset(self):
        ordering = self.request.GET.get("ordering")
        search = self.request.GET.get("search", None)
        organisation_id = get_current_user(self.request, "organisation_id", None)
        if organisation_id:
            filter_query = {"is_deleted": False, "organisation_id": organisation_id}
            if search:
                return CustomerSearch.objects.filter(
                    Q(card_id__icontains=str(search)), **filter_query
                ).first()
            else:
                return Response({"results": [], "count": 0})
        return Response({"results": [], "count": 0})


class CustomerMobileBankingSubscribers(viewsets.ViewSet):
    serializer_class = CustomerMobileBankingSubscriptionSerializer
    pagination_class = None  # Disable pagination

    def list(self, request, *args, **kwargs):
        organisation_id = get_current_user(self.request, "organisation_id", None)
        branch_id = get_current_user(self.request, "organisation_branch_id", None)
        start_date = self.request.GET.get("start", None)
        end_date = self.request.GET.get("end", None)

        query = """
            SELECT M.id, M.telephone_no, M.date_added, M.active, M.added_by_id, M.customer_id, 
                   C.name, COALESCE(C.old_member_number, C.member_number) AS member_number, 
                   T.customer_type, B.name AS branch_name
            FROM mobile_banking_subscription M
            INNER JOIN customer C ON C.id = M.id
            LEFT JOIN customer_type T ON C.branch_customer_type_id = T.id
            INNER JOIN organisation_branch B ON B.id = C.customer_branch_id
            WHERE M.active = TRUE AND C.is_deleted = FALSE
              AND B.branch_organisation_id = %s
              AND M.date_added::date BETWEEN %s AND %s
            ORDER BY id DESC
        """
        with connection.cursor() as cursor:
            cursor.execute(query, [organisation_id, start_date, end_date])
            rows = cursor.fetchall()
            columns = [col[0] for col in cursor.description]
            results = [dict(zip(columns, row)) for row in rows]

        return Response(
            {"message": "Mobile Subscribers", "results": results},
            status=status.HTTP_200_OK,
        )
