import random

from django.db.models import Q
from django.db.models.aggregates import Count

from apps.authentication.models import Organization
from apps.livestock.web.api.v1.serializers import LiveStockSerializer
from apps.tag.exceptions import TagException
from apps.tag.models import Tag, TagBatch
from apps.tag.tools import tag_code_serial_scanning


class TagService:
    """
    Different Services of Livestock Tags
    """

    def tag_code_compelition(self, tag_data: dict, serial, ownership_code, organization):
        """
        complete data of tag
        """

        tag_data.update({
            'serial': serial,
            'ownership_code': ownership_code,
            'organization': organization,
            'tag_code': f"{tag_data.get('country_code')}"
                        f"{tag_data.get('static_code')}"
                        f"{ownership_code}"
                        f"{tag_data.get('species_code')}"
                        f"{tag_code_serial_scanning(str(serial))}"
        })

        return tag_data

    def create_tag(
            self,
            serial_start_range: int = None,
            serial_end_range: int = None,
            org: Organization = None,
            data: dict = None
    ):
        """
        create livestock tag with batch / batch item
        """

        # create tag batch
        request_number = (serial_end_range - serial_start_range) + 1
        batch_identity = f'{serial_start_range}{serial_end_range}{data.get("species_code")}{random.randint(1000, 9999)}'
        batch = TagBatch.objects.create(
            batch_identity=batch_identity,
            organization=org,
            request_number=request_number if request_number > 0 else 1,
            species_code=data.get('species_code'),
            serial_from=serial_start_range,
            serial_to=serial_end_range,
            status='created',
        )

        tag_list = []
        while serial_start_range <= serial_end_range:
            tag_data = self.tag_code_compelition(
                tag_data=data,
                serial=serial_start_range,
                organization=org,
                ownership_code=org.ownership_code
            )
            tag_list.append(Tag(**tag_data))

            if Tag.objects.filter(serial=serial_start_range, species_code=data.get('species_code')).exists():
                raise TagException(f' پلاک با مشخصات مورد نظر {serial_start_range} وجود دارد ', status_code=403)  # noqa

            serial_start_range += 1

        created_tags = Tag.objects.bulk_create(tag_list)
        batch.tag.add(*created_tags)

        return created_tags

    def update_batch_tag(
            self,
            serial_start_range: int = None,
            serial_end_range: int = None,
            org: Organization = None,
            data: dict = None,
            batch_id: int = None,
    ):
        """
        update livestock tag with batch / batch item
        """

        # update tag batch
        request_number = (serial_end_range - serial_start_range) + 1
        batch = TagBatch.objects.get(id=batch_id)
        batch.request_number = request_number
        batch.species_code = data.get('species_code')
        batch.serial_from = serial_start_range
        batch.serial_to = serial_end_range
        batch.save(update_fields=['request_number', 'species_code', 'serial_from', 'serial_to'])

        # recreate tags for batch
        tag_list = []
        while serial_start_range <= serial_end_range:
            tag_data = self.tag_code_compelition(
                tag_data=data,
                serial=serial_start_range,
                organization=org,
                ownership_code=org.ownership_code
            )
            tag_list.append(Tag(**tag_data))

            if Tag.objects.filter(
                    serial=serial_start_range,
                    species_code=data.get('species_code')
            ).exists() and not batch.tag.filter(
                serial=serial_start_range
            ).exists():
                raise TagException(f' پلاک با مشخصات مورد نظر {serial_start_range} وجود دارد ', status_code=403)  # noqa

            serial_start_range += 1

        created_tags = Tag.objects.bulk_create(tag_list)
        # hard delete of created tags for batch
        batch.tag.all().delete()
        batch.tag.add(*created_tags)

        return created_tags

    def tag_detail(self, by_id: int = None, by_queryset: bool = False):
        """
        get detail of a tag like: livestock, rancher, herd, etc
        """

        if by_id:
            tag = Tag.objects.prefetch_related(
                'livestock_tag'
            ).get(id=by_id)

            livestock = tag.livestock_tag.first()

            result = LiveStockSerializer(livestock).data
        else:
            result = dict()

        return result

    def tag_dashboard(self):
        """
        dashboard of tags page
        """

        queryset = Tag.objects.all()
        response = queryset.aggregate(
            count=Count('id'),
            cow_count=Count('id', filter=Q(species_code=1)),
            buffalo_count=Count('id', filter=Q(species_code=2)),
            camel_count=Count('id', filter=Q(species_code=3)),
            sheep_count=Count('id', filter=Q(species_code=4)),
            goat_count=Count('id', filter=Q(species_code=5)),
            free_count=Count('id', filter=Q(status='F')),
            assign_count=Count('id', filter=Q(status='A')),

        )

        return response
