from datetime import datetime, timedelta

import jdatetime
from dateutil.relativedelta import relativedelta
from django.db.models import Count, Q
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
from oauth2_provider.contrib.rest_framework import TokenHasReadWriteScope
from rest_framework import viewsets
from rest_framework import status
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import AllowAny
from rest_framework.response import Response

from LiveStock.LiveStoksAndPoultry.filterset import LiveStockFilterSet
from LiveStock.LiveStoksAndPoultry.serializers import LiveStockSerializer, PosLiveStockSerializer
from LiveStock.Rancher.helpers import update_one_rancher
from LiveStock.helpers import build_query, CustomPagination, convert_to_miladi
from LiveStock.models import LiveStock, Rancher, LiveStockProduct, LiveStockRolseProduct, Cooperative, Union, \
    CooperativeProductsShare
from authentication.models import SystemUserProfile
from panel.models import POSMachine, PosMachineTransactions
from panel.validate_headers import PosDeviceValidator


class LiveStockViewSet(viewsets.ModelViewSet):
    queryset = LiveStock.objects.filter(trash=False).order_by('-birth_day_gh')
    permission_classes = [TokenHasReadWriteScope]
    serializer_class = LiveStockSerializer
    filterset_class = LiveStockFilterSet
    pagination_class = CustomPagination

    def list(self, request, *args, **kwargs):
        role = request.GET['role']
        user = SystemUserProfile.objects.get(user=request.user, trash=False)
        type=request.GET.get('type')
        if type == 'archive':
            live_stocks=LiveStock.objects.filter(trash=True,archive=True).order_by('-birth_day_gh')
        else:
            live_stocks=LiveStock.objects.filter(trash=False).order_by('-birth_day_gh')

        if role == 'Cooperative':
            # todo:فعلا چون دامدار تکراری داریم نمیشه از طریق دامدار پیداکرد باید از طریف آدرس بریم
            cooperative = Cooperative.objects.get(user=user, trash=False)
            ranchers = Rancher.objects.filter(city=cooperative.address.city.name).values_list('herd_code',
                                                                                              flat=True).distinct()
            live_stocks = live_stocks.filter(herd_code__in=ranchers)

        date1 = request.GET.get('date1')
        date2 = request.GET.get('date2')
        if date1 and date2:
            date1 = datetime.strptime(str(request.GET['date1']), '%Y-%m-%d').date()
            date2 = datetime.strptime(str(request.GET['date2']), '%Y-%m-%d').date()
            live_stocks = live_stocks.filter(birth_day__gte=date1, birth_day__lte=date2)

        value = request.GET.get('value')
        search = request.GET.get('search')
        if value and search == 'filter':
            if search != 'undefined' and search.strip():
                live_stocks = live_stocks.filter(
                    build_query(self.filterset_class.Meta.fields, value)
                )
        page = self.paginate_queryset(live_stocks)
        if page is not None:
            serializer = self.serializer_class(page, many=True)
            return self.get_paginated_response(serializer.data)
        serializer = self.serializer_class(live_stocks, many=True)
        return Response(serializer.data, status=status.HTTP_200_OK)

    def create(self, request, *args, **kwargs):
        rancher = Rancher.objects.get(key=request.data['rancher_key'])
        request.data.pop('rancher_key')

        serializer = self.serializer_class(data=request.data)
        if serializer.is_valid():
            live_stock = serializer.create(validated_data=request.data)
            live_stock.rancher = rancher
            live_stock.herd_code = rancher.herd_code
            live_stock.contractor_code = rancher.contractor_code
            live_stock.save()
            return Response({"result": "با موفقیت ثبت شد"}, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def update(self, request, pk=None, *args, **kwargs):
        user=SystemUserProfile.objects.filter(trash=False,user=request.user).first()

        filter_kwargs = {'key': request.data['live_stock_key']}
        if 'return_from_archive' in request.data.keys():
            filter_kwargs['trash']=True
            filter_kwargs['archive']=True
        else:
            filter_kwargs['trash'] = False

        live_stock = LiveStock.objects.get(**filter_kwargs)
        live_stocks = LiveStock.objects.filter(herd_code=live_stock.herd_code, trash=False)
        rancher = Rancher.objects.get(herd_code=live_stock.herd_code)

        request.data.pop('live_stock_key')
        serializer = self.serializer_class(live_stock)
        if 'herd_code' in request.data.keys() and request.data['herd_code']:
            rancher.herd_code = request.data['herd_code']
            rancher.save()
            live_stocks.update(herd_code=request.data['herd_code'])
        if 'return_from_archive' in request.data.keys():
            live_stock.archive = False
            live_stock.trash = False
            live_stock.returner_from_archive=user.fullname
            live_stock.return_from_archive_date=datetime.now()
            live_stock.save()
            request.data.pop('return_from_archive')

        serializer.update(instance=live_stock, validated_data=request.data)
        return Response(serializer.data, status=status.HTTP_200_OK)

    def destroy(self, request, *args, **kwargs):
        user=SystemUserProfile.objects.filter(trash=False,user=request.user).first()
        live_stock = LiveStock.objects.get(key=request.GET['live_stock_key'], trash=False)
        if not live_stock.birth_day_gh:
            year, month, day = map(int, live_stock.birth_day.split('/'))
            live_stock.birth_day_gh = convert_to_miladi(year, month, day)
            live_stock.save()
        live_stock.trash=True
        live_stock.archive=True
        live_stock.archiver=user.fullname
        live_stock.archive_date=datetime.now()
        live_stock.age_of_archive=(datetime.now().date() - live_stock.birth_day_gh.date()).days
        live_stock.save()

        return Response({"result":"با موفقیت بایگانی شد."}, status=status.HTTP_200_OK)

class PosLiveStockViewSet(viewsets.ModelViewSet):
    queryset = Rancher.objects.all()
    permission_classes = [AllowAny]
    serializer_class = PosLiveStockSerializer

    def get_transactions_month(self,natcode):
        import json
        transactions = PosMachineTransactions.objects.filter(natcode=natcode,paid=True,live_stock=True, trash=False)

        has_month_data = False
        last_month = None
        earliest_transaction_date = None

        for transaction in transactions:
            try:
                additional_data = json.loads(transaction.additional)
                if 'month' in additional_data and isinstance(additional_data['month'], list):
                    has_month_data = True
                    for month in additional_data['month']:
                        if last_month is None or month > last_month:
                            last_month = month
            except (json.JSONDecodeError, AttributeError):
                pass

            if hasattr(transaction, 'create_date'):
                created_date = transaction.create_date
                if earliest_transaction_date is None or created_date < earliest_transaction_date:
                    earliest_transaction_date = created_date

        future_months = []

        if not transactions:
            base_date = jdatetime.date.today().togregorian() - relativedelta(months=1)
            include_current = True
        elif has_month_data and last_month:
            year = int(str(last_month)[:4])
            month = int(str(last_month)[4:6])
            base_date = jdatetime.date(year, month, 1).togregorian()
            include_current = False
        else:
            if earliest_transaction_date:
                base_date = earliest_transaction_date
            else:
                base_date = jdatetime.date.today().togregorian()
            include_current = False

        start_offset = 0 if include_current else 1

        for i in range(start_offset, start_offset + 6):
            future_date = base_date + relativedelta(months=i)
            jd_future = jdatetime.date.fromgregorian(date=future_date)
            future_months.append(int(f"{jd_future.year}{jd_future.month:02d}"))



        return future_months


    def list(self, request, *args, **kwargs):
        validator = PosDeviceValidator(request)
        validation_error = validator.validation_version()
        if validation_error:
            return validation_error

        validation_device = validator.validation_device()
        if not validation_device:
            return Response({"result": "نشست شما منقضی شده لطفا محدد وارد شوید!"}, status=status.HTTP_401_UNAUTHORIZED)
        pos = POSMachine.objects.get(pos_id=validation_device)
        if pos.cooperative is None:
            return Response({"result": "دستگاه شما برای مدیریت امور دام تعریف نشده است!"},
                            status=403)

        if int(validator.device_version) < 218:
                return Response(
                    {"result": "لطفا جهت بروزرسانی نسخه دستگاه کارت خوان با پشتیبانی دستگاه ارتباط بگیرید!"},
                    status=status.HTTP_403_FORBIDDEN)

        if 'nath_id' in request.GET:
            ranchers = Rancher.objects.filter(national_id=request.GET['nath_id'], trash=False).first()
            if not ranchers:
                return Response({"result": "دامدار یافت نشد!"},
                                status=403)

            union = Union.objects.filter(trash=False).first()
            if 'product_key' in request.GET:
                product = LiveStockRolseProduct.objects.filter(key=request.GET['product_key'], trash=False).select_related(
                    'parent_product').only('parent_product__price', 'parent_product__name', 'parent_product__image',
                                           'parent_product__light_wight', 'parent_product__heavy_wight',
                                           'parent_product__shipping_price', 'parent_product__union_price',
                                           'parent_product__cooperative_price').first()
            else:
                product = LiveStockRolseProduct.objects.filter(cooperative=pos.cooperative, trash=False).select_related(
                    'parent_product').only('parent_product__price', 'parent_product__name', 'parent_product__image',
                                           'parent_product__light_wight', 'parent_product__heavy_wight',
                                           'parent_product__shipping_price', 'parent_product__union_price',
                                           'parent_product__cooperative_price').first()
            main_product = product.parent_product
            share = CooperativeProductsShare.objects.get(product=main_product, cooperative=pos.cooperative, trash=False)

            if ranchers.type == 'rural':
                heavy_rate= product.parent_product.heavy_wight
                light_rate= product.parent_product.light_wight
            else:
                heavy_rate= product.parent_product.heavy_wight_industrial
                light_rate= product.parent_product.light_wight_industrial



            month_list = self.get_transactions_month(request.GET['nath_id'])
            shares_list = []
            if share.union_price > 0:

                shares_list.append({
                    "name":'union',
                    "shaba":union.account,
                    "price":share.union_price,
                })
            if share.company_price > 0:

                shares_list.append({
                    "name":'company',
                    "shaba":"IR170150000003100050545702",
                    "price":share.company_price,
                })

            if pos.cooperative.first_sub_cooperative_price > 0:

                shares_list.append({
                    "name":'first_sub_cooperative',
                    "shaba":pos.cooperative.first_sub_cooperative_account,
                    "price":pos.cooperative.first_sub_cooperative_price,
                })

            if pos.cooperative.second_sub_cooperative_price > 0:

                shares_list.append({
                    "name":'second_sub_cooperative',
                    "shaba":pos.cooperative.second_sub_cooperative_price,
                    "price":pos.cooperative.second_sub_cooperative_price,
                })



            dict1 = {
                "title": [
                    {"key": "نام و نام خانوادگی", "value": ranchers.fullname if ranchers.fullname else ranchers.user.fullname},
                    {"key": "موبایل", "value": ranchers.mobile},
                    {"key": "وزن کل خریداری شده", "value": str(ranchers.total_weight)}
                ],
                "key": ranchers.key,
                "herd_code": ranchers.herd_code,
                "national_id": ranchers.national_id,
                "fullname": ranchers.fullname if ranchers.fullname else ranchers.user.fullname,
                "type": ranchers.type,
                "mobile": ranchers.mobile,
                "allow_buy": ranchers.allow_buy,
                "more_than_inventory": True,
                "pos_owners": [],
                "allow_buy_message": " ",
                "real_light_livestock": ranchers.light_livestock,  # تعداد تعیین شده دام توسط سامانه
                "real_heavy_livestock": ranchers.heavy_livestock,  # تعداد تعیین شده دام توسط سامانه
                "real_dhi_livestock": 0,  # تعداد تعیین شده دام توسط سامانه
                "weight_quota_heavy": ranchers.weight_quota_heavy,  # سهمیه قابل دریافت
                "weight_quota_light": ranchers.weight_quota_light,  # سهمیه قابل دریافت
                "weight_quota_dhi": ranchers.dhi_amount,  # سهمیه قابل دریافت
                "heavy_rate": heavy_rate,  # نرخ تبدیل جهت دریافت سهمیه
                "light_rate": light_rate,  # نرخ تبدیل جهت دریافت سهمیه
                "dhi_rate": product.parent_product.heavy_wight_dha,  # نرخ تبدیل جهت دریافت سهمیه
                "round_rate": 1,  # مضرب رند کردن فروش
                "total_weight": ranchers.total_weight,  # کل خرید دامدار ریم د دمش

                "product_total_weight": product.total_weight,
                "product_total_allocated_weight": product.total_allocated_weight,
                "product_total_remain_weight": product.total_remain_weight,
                "product_name": product.parent_product.name,
                "product_image": product.parent_product.image,
                "product_price": share.price,
                "cooperative_price_with_shipping": share.price + share.shipping_price + share.cooperative_price,
                "cooperative_price_without_shipping": share.price + share.cooperative_price,
                "union_price": share.union_price,
                "union_shaba": union.account,
                "shares": shares_list,
                "cooperative_shaba": pos.cooperative.account,
                "month_list": month_list,

            }
            return Response(dict1, status=status.HTTP_200_OK)

        return Response({"resut": "کد ملی وارد نشده است!"}, status=status.HTTP_403_FORBIDDEN)


# class DashboardLiveStockViewSet(viewsets.ModelViewSet):
#     queryset = LiveStock.objects.filter(trash=False)
#     permission_classes = [TokenHasReadWriteScope]
#     serializer_class = LiveStockSerializer
#     filterset_class = LiveStockFilterSet
#
#     def list(self, request, *args, **kwargs):
#         role = request.GET['role']
#         user = SystemUserProfile.objects.get(user=request.user, trash=False)
#         if role == 'Cooperative':
#             # todo:فعلا چون دامدار تکراری داریم نمیشه از طریق دامدار پیداکرد باید از طریف آدرس بریم
#             cooperative = Cooperative.objects.get(user=user, trash=False)
#             ranchers = Rancher.objects.filter(city=cooperative.address.city.name).values_list('herd_code',
#                                                                                               flat=True).distinct()
#             live_stocks = self.queryset.filter(herd_code__in=ranchers)
#         else:
#             live_stocks = self.queryset
#         date1 = request.GET.get('date1')
#         date2 = request.GET.get('date2')
#         if date1 and date2:
#             date1 = datetime.strptime(str(request.GET['date1']), '%Y-%m-%d').date()
#             date2 = datetime.strptime(str(request.GET['date2']), '%Y-%m-%d').date()
#             live_stocks = live_stocks.filter(birth_day__gte=date1, birth_day__lte=date2)
#
#         value = request.GET.get('value')
#         search = request.GET.get('search')
#         if value and search == 'filter':
#             if search != 'undefined' and search.strip():
#                 live_stocks = live_stocks.filter(
#                     build_query(self.filterset_class.Meta.fields, value)
#                 )
#         sheep = live_stocks.filter(type='گوسفند').count()
#         goat = live_stocks.filter(type='بز').count()
#         cow = live_stocks.filter(type='گاو').count()
#         horse = live_stocks.filter(type='اسب').count()
#         camel = live_stocks.filter(type='شتر').count()
#         light_livestock = live_stocks.filter(type__in=('بز', 'گوسفند')).count()
#         heavy_livestock = live_stocks.filter(type__in=('گاو', 'اسب', 'شتر')).count()
#
#         dict1={
#             'live_stocks_count':live_stocks.count(),
#             "sheep":sheep,
#             "goat":goat,
#             "cow":cow,
#             "horse":horse,
#             "camel":camel,
#             "light_livestock":light_livestock,
#             "heavy_livestock":heavy_livestock,
#
#         }
#         return Response(dict1, status=status.HTTP_200_OK)


@api_view(["GET"])
@csrf_exempt
@permission_classes([TokenHasReadWriteScope])
def dashboard_live_stock(request):
    role = request.GET['role']
    user = SystemUserProfile.objects.get(user=request.user, trash=False)
    type = request.GET.get('type')
    if type == 'archive':
        live_stocks = LiveStock.objects.filter(trash=True, archive=True).only('type')
    else:
        live_stocks = LiveStock.objects.filter(trash=False).only('type')

    if role == 'Cooperative':
        cooperative = Cooperative.objects.get(user=user, trash=False)
        ranchers = Rancher.objects.filter(city=cooperative.address.city.name).values_list('herd_code',
                                                                                          flat=True).distinct()
        live_stocks = live_stocks.filter(herd_code__in=ranchers)

    date1 = request.GET.get('date1')
    date2 = request.GET.get('date2')
    if date1 and date2:
        date1 = datetime.strptime(str(request.GET['date1']), '%Y-%m-%d').date()
        date2 = datetime.strptime(str(request.GET['date2']), '%Y-%m-%d').date()
        live_stocks = live_stocks.filter(birth_day__gte=date1, birth_day__lte=date2)

    value = request.GET.get('value')
    search = request.GET.get('search')
    if value and search == 'filter':
        if search != 'undefined' and search.strip():
            live_stocks = live_stocks.filter(
                build_query(LiveStockFilterSet.Meta.fields, value)
            )
    counts = live_stocks.values('type').annotate(total=Count('id'))
    count_dict = {item['type']: item['total'] for item in counts}

    light_livestock = count_dict.get('بز', 0) + count_dict.get('گوسفند', 0)
    heavy_livestock = count_dict.get('گاو', 0) + count_dict.get('اسب', 0) + count_dict.get('شتر', 0)

    result = {
        'live_stocks_count': sum(count_dict.values()),
        "sheep": count_dict.get('گوسفند', 0),
        "goat": count_dict.get('بز', 0),
        "cow": count_dict.get('گاو', 0),
        "horse": count_dict.get('اسب', 0),
        "camel": count_dict.get('شتر', 0),
        "light_livestock": light_livestock,
        "heavy_livestock": heavy_livestock,
    }

    return Response(result, status=status.HTTP_200_OK)

from datetime import date, timedelta

def archive_live_stock(request):
    today = date.today()
    archive_msg = 'بایگانی خودکار به علت سن بالا'

    stocks_to_convert = LiveStock.objects.filter(trash=False, birth_day_gh__isnull=True)
    for stock in stocks_to_convert:
        try:
            year, month, day = map(int, stock.birth_day.split('/'))
            stock.birth_day_gh = convert_to_miladi(year, month, day)
            stock.save()
        except:
            continue

    archive_conditions = Q(
        Q(type__in=['بز', 'گوسفند'], gender='نر') & Q(birth_day_gh__lte=today - timedelta(days=425)) |
        Q(type__in=['بز', 'گوسفند'], gender='ماده') & Q(birth_day_gh__lte=today - timedelta(days=1825)) |
        Q(type='گاو') & Q(birth_day_gh__lte=today - timedelta(days=3285)) |
        Q(type='اسب') & Q(birth_day_gh__lte=today - timedelta(days=4380))
    )

    archived_count = LiveStock.objects.filter(
        trash=False,
        birth_day_gh__isnull=False
    ).filter(archive_conditions).update(
        trash=True,
        archive=True,
        archiver=archive_msg
    )



    return HttpResponse('ok')