from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from utils.validation import validate_required_params, validate
from utils.helper import validate_and_convert_deadline
from rest_framework import status
from rest_framework import generics
from .models import Listing, ListingCategory, ListingCategoryService, ListingTerms
from .serializers import ListingTermsSerializer, ListingSerializer, ListingCategorySerializer, ListingCategoryServiceSerializer, ListingRecentSerializer, ListingSingleAPISerializer
from utils.helper import success_response, failed_response , generate_random_text
from rest_framework.pagination import LimitOffsetPagination
from utils.exception import NotFoundError, ValidationError
from utils.logger import record
from utils.data import logger_settings 

log_msg=logger_settings["msg"]


class ListingCategoryCRUDView(APIView):
    def get(self, request, pk=None, format=None):
        process_code = generate_random_text(6)
        record('info', f'{process_code}: {log_msg["started"]} - ListingCategoryCRUDView GET request started')
        try:
            if pk:
                listing_category = ListingCategory.objects.get(pk=pk)
                serializer = ListingCategorySerializer(listing_category)
                record('info', f'{process_code}: {log_msg["completed"]} - Listing Category retrieved successfully')
                return success_response(data=serializer.data, msg='Listing Category retrieved successfully')
            else:
                listing_categories = ListingCategory.objects.all()
                serializer = ListingCategorySerializer(listing_categories, many=True)
                record('info', f'{process_code}: {log_msg["completed"]} - Listing categories retrieved successfully')
                return success_response(data=serializer.data, msg='Listing categories retrieved successfully')
        except ListingCategory.DoesNotExist:
            record('warn', f'{process_code}: Listing category not found')
            return failed_response(msg='Listing category not found', code=status.HTTP_404_NOT_FOUND)
        except Exception as e:
            record('error', f'{process_code}: {str(e)} - Unexpected error occurred during Listing Category retrieval')
            return failed_response(msg='An unexpected error occurred', code=status.HTTP_500_INTERNAL_SERVER_ERROR)

    def post(self, request, format=None):
        process_code = generate_random_text(6)
        record('info', f'{process_code}: {log_msg["started"]} - ListingCategoryCRUDView POST request started')
        try:
            validate_required_params(request, ['title', 'deadline', 'note'])
            validate('title', request.data.get('title', ''), ['length:max:100'])
            validate_and_convert_deadline('deadline', request.data.get('deadline', ''))
            validate('note', request.data.get('note', ''), ['length:max:250'])
            serializer = ListingCategorySerializer(data=request.data)
            if serializer.is_valid():
                serializer.save()
                record('info', f'{process_code}: {log_msg["completed"]} - Listing Category created successfully')
                return success_response(data=serializer.data, msg="Listing Category Created Successfully")
            record('warn', f'{process_code}: {serializer.errors} - Validation errors during Listing Category creation')
            return failed_response(msg=serializer.errors, code=status.HTTP_400_BAD_REQUEST)
        except ValidationError as ve:
            record('warn', f'{process_code}: {str(ve)} - Validation error during Listing Category creation')
            return failed_response(msg=str(ve), code=status.HTTP_400_BAD_REQUEST)
        except Exception as e:
            record('error', f'{process_code}: {str(e)} - Unexpected error occurred during Listing Category creation')
            return failed_response(msg='An unexpected error occurred', code=status.HTTP_500_INTERNAL_SERVER_ERROR)

    def put(self, request, pk=None, format=None):
        process_code = generate_random_text(6)
        record('info', f'{process_code}: {log_msg["started"]} - ListingCategoryCRUDView PUT request started')
        try:
            validate_required_params(request, ['title', 'deadline', 'note'])
            validate('title', request.data.get('title', ''), ['length:max:100'])
            validate_and_convert_deadline('deadline', request.data.get('deadline', ''))
            validate('note', request.data.get('note', ''), ['length:max:250'])
            if not pk:
                record('warn', f'{process_code}: Listing category ID is required for update')
                return failed_response(msg='Listing category ID is required', code=status.HTTP_400_BAD_REQUEST)
            listing_category = ListingCategory.objects.get(pk=pk)
            serializer = ListingCategorySerializer(listing_category, data=request.data)
            if serializer.is_valid():
                serializer.save()
                record('info', f'{process_code}: {log_msg["completed"]} - Listing Category updated successfully')
                return success_response(data=serializer.data, msg="Listing Category Updated Successfully")
            record('warn', f'{process_code}: {serializer.errors} - Validation errors during Listing Category update')
            return failed_response(msg=serializer.errors, code=status.HTTP_400_BAD_REQUEST)
        except ListingCategory.DoesNotExist:
            record('warn', f'{process_code}: Listing category not found for update')
            return failed_response(msg='Listing category not found', code=status.HTTP_404_NOT_FOUND)
        except ValidationError as ve:
            record('warn', f'{process_code}: {str(ve)} - Validation error during Listing Category update')
            return failed_response(msg=str(ve), code=status.HTTP_400_BAD_REQUEST)
        except Exception as e:
            record('error', f'{process_code}: {str(e)} - Unexpected error occurred during Listing Category update')
            return failed_response(msg='An unexpected error occurred', code=status.HTTP_500_INTERNAL_SERVER_ERROR)

    def delete(self, request, pk=None, format=None):
        process_code = generate_random_text(6)
        record('info', f'{process_code}: {log_msg["started"]} - ListingCategoryCRUDView DELETE request started')
        try:
            listing_category = ListingCategory.objects.get(pk=pk)
            listing_category.delete()
            record('info', f'{process_code}: {log_msg["completed"]} - Listing Category deleted successfully')
            return success_response(msg='Listing Category deleted successfully')
        except ListingCategory.DoesNotExist:
            record('warn', f'{process_code}: Listing category not found for deletion')
            return failed_response(msg='Listing Category not found', code=status.HTTP_404_NOT_FOUND)
        except Exception as e:
            record('error', f'{process_code}: {str(e)} - Unexpected error occurred during Listing Category deletion')
            return failed_response(msg='An unexpected error occurred', code=status.HTTP_500_INTERNAL_SERVER_ERROR)


class ListingCategoryServiceCRUDView(APIView):
    def get(self, request, pk=None, format=None):
        process_code = generate_random_text(6)
        record('info', f'{process_code}: {log_msg["started"]} - ListingCategoryServiceCRUDView GET request started')
        try:
            if pk:
                listing_category_service = ListingCategoryService.objects.get(pk=pk)
                serializer = ListingCategoryServiceSerializer(listing_category_service)
                record('info', f'{process_code}: {log_msg["completed"]} - Listing category service retrieved successfully')
                return success_response(data=serializer.data, msg='Listing category service retrieved successfully')
            else:
                listing_category_services = ListingCategoryService.objects.all()
                serializer = ListingCategoryServiceSerializer(listing_category_services, many=True)
                record('info', f'{process_code}: {log_msg["completed"]} - Listing category services retrieved successfully')
                return success_response(data=serializer.data, msg='Listing category services retrieved successfully')
        except ListingCategoryService.DoesNotExist:
            record('warn', f'{process_code}: Listing category service not found')
            return failed_response(msg='Listing category service not found', code=status.HTTP_404_NOT_FOUND)
        except Exception as e:
            record('error', f'{process_code}: {str(e)} - Unexpected error occurred during Listing Category Service retrieval')
            return failed_response(msg='An unexpected error occurred', code=status.HTTP_500_INTERNAL_SERVER_ERROR)

    def post(self, request, format=None):
        process_code = generate_random_text(6)
        record('info', f'{process_code}: {log_msg["started"]} - ListingCategoryServiceCRUDView POST request started')
        try:
            serializer = ListingCategoryServiceSerializer(data=request.data)
            if serializer.is_valid():
                serializer.save()
                record('info', f'{process_code}: {log_msg["completed"]} - Listing category service created successfully')
                return success_response(data=serializer.data, msg='Listing category service created successfully')
            record('warn', f'{process_code}: {serializer.errors} - Validation errors during Listing Category Service creation')
            return failed_response(msg=serializer.errors, code=status.HTTP_400_BAD_REQUEST)
        except Exception as e:
            record('error', f'{process_code}: {str(e)} - Unexpected error occurred during Listing Category Service creation')
            return failed_response(msg='An unexpected error occurred', code=status.HTTP_500_INTERNAL_SERVER_ERROR)

    def put(self, request, pk=None, format=None):
        process_code = generate_random_text(6)
        record('info', f'{process_code}: {log_msg["started"]} - ListingCategoryServiceCRUDView PUT request started')
        try:
            validate_required_params(request, ['listing', 'vendor_category_service'])
            if not pk:
                record('warn', f'{process_code}: Listing Category Service ID is required for update')
                return failed_response(msg='Listing Category Service ID is required', code=status.HTTP_400_BAD_REQUEST)
            listing_category_service = ListingCategoryService.objects.get(pk=pk)
            serializer = ListingCategoryServiceSerializer(listing_category_service, data=request.data)
            if serializer.is_valid():
                serializer.save()
                record('info', f'{process_code}: {log_msg["completed"]} - Listing category service updated successfully')
                return success_response(data=serializer.data, msg='Listing category service updated successfully')
            record('warn', f'{process_code}: {serializer.errors} - Validation errors during Listing Category Service update')
            return failed_response(msg=serializer.errors, code=status.HTTP_400_BAD_REQUEST)
        except ListingCategoryService.DoesNotExist:
            record('warn', f'{process_code}: Listing category service not found for update')
            return failed_response(msg='Listing category service not found', code=status.HTTP_404_NOT_FOUND)
        except Exception as e:
            record('error', f'{process_code}: {str(e)} - Unexpected error occurred during Listing Category Service update')
            return failed_response(msg='An unexpected error occurred', code=status.HTTP_500_INTERNAL_SERVER_ERROR)

    def delete(self, request, pk=None, format=None):
        process_code = generate_random_text(6)
        record('info', f'{process_code}: {log_msg["started"]} - ListingCategoryServiceCRUDView DELETE request started')
        try:
            listing_category_service = ListingCategoryService.objects.get(pk=pk)
            listing_category_service.delete()
            record('info', f'{process_code}: {log_msg["completed"]} - Listing category service deleted successfully')
            return success_response(msg='Listing Category Service deleted successfully')
        except ListingCategoryService.DoesNotExist:
            record('warn', f'{process_code}: Listing category service not found for deletion')
            return failed_response(msg='Listing category service not found', code=status.HTTP_404_NOT_FOUND)
        except Exception as e:
            record('error', f'{process_code}: {str(e)} - Unexpected error occurred during Listing Category Service deletion')
            return failed_response(msg='An unexpected error occurred', code=status.HTTP_500_INTERNAL_SERVER_ERROR)


class ListingTermsCRUDView(APIView):
    def get(self, request, pk=None, format=None):
        process_code = generate_random_text(6)
        record('info', f'{process_code}: {log_msg["started"]} - ListingTermsCRUDView GET request started')
        try:
            if pk:
                listing_term = ListingTerms.objects.get(pk=pk)
                serializer = ListingTermsSerializer(listing_term)
                record('info', f'{process_code}: {log_msg["completed"]} - Listing term retrieved successfully')
                return success_response(data = serializer.data, msg = 'Listing term retrieved successfully')
            else:
                listing_terms = ListingTerms.objects.all()
                serializer = ListingTermsSerializer(listing_terms, many=True)
                record('info', f'{process_code}: {log_msg["completed"]} - Listing terms retrieved successfully')
                return success_response(data = serializer.data, msg = 'Listing terms retrieved successfully')
        except ListingTerms.DoesNotExist:
            record('warn', f'{process_code}: Listing term not found')
            return failed_response(msg = 'Listing term not found', code=status.HTTP_400_BAD_REQUEST)
        except Exception as e:
            record('error', f'{process_code}: {str(e)} - Unexpected error occurred during Listing Term retrieval')
            return failed_response(msg='An unexpected error occurred: ', code=status.HTTP_500_INTERNAL_SERVER_ERROR)
        
    def post(self, request, format=None):
        process_code = generate_random_text(6)
        record('info', f'{process_code}: {log_msg["started"]} - ListingTermsCRUDView POST request started')
        try:
            validate_required_params(request, ['note'])
            validate('note',request.data.get('note', ''), ['length:max:250'])
            serializer = ListingTermsSerializer(data=request.data)
            if serializer.is_valid():
                serializer.save()
                record('info', f'{process_code}: {log_msg["completed"]} - Listing term created successfully')
                return success_response(data=serializer.data, msg='Listing Term created successfully')
            record('warn', f'{process_code}: {serializer.errors} - Validation errors during Listing Term creation')
            return failed_response(msg = serializer.errors, code=status.HTTP_400_BAD_REQUEST)
        except ValidationError as ve:
            record('warn', f'{process_code}: Validation error - {str(ve)}')
            return failed_response(msg = str(ve), code=status.HTTP_400_BAD_REQUEST)
        except Exception as e:
            record('error', f'{process_code}: {str(e)} - Unexpected error occurred during Listing Term creation')
            return failed_response(msg='An unexpected error occurred: ', code=status.HTTP_500_INTERNAL_SERVER_ERROR)
        
    def put(self, request, pk=None, format=None):
        process_code = generate_random_text(6)
        record('info', f'{process_code}: {log_msg["started"]} - ListingTermsCRUDView PUT request started')
        try:
            validate_required_params(request, ['pk','note'])
            validate('note',request.data.get('note', ''), ['length:max:250'])
            if not pk:
                record('warn', f'{process_code}: Listing Term ID is required for update')
                return failed_response(msg='Listing Term ID is required', code=status.HTTP_400_BAD_REQUEST)
            listing_term = ListingTerms.objects.get(pk=pk)
            serializer = ListingTermsSerializer(listing_term, data=request.data)
            if serializer.is_valid():
                serializer.save()
                record('info', f'{process_code}: {log_msg["completed"]} - Listing term updated successfully')
                return success_response(data=serializer.data, msg='Listing Term updated successfully')
            record('warn', f'{process_code}: {serializer.errors} - Validation errors during Listing Term update')
            return failed_response(msg=serializer.errors, code=status.HTTP_400_BAD_REQUEST)
        except ListingTerms.DoesNotExist:
            record('warn', f'{process_code}: Listing Term not found for update')
            return failed_response(msg='Listing Term not found', code=status.HTTP_404_NOT_FOUND)
        except ValidationError as ve:
            record('warn', f'{process_code}: Validation error - {str(ve)}')
            return failed_response(msg = str(ve), code=status.HTTP_400_BAD_REQUEST)
        except Exception as e:
            record('error', f'{process_code}: {str(e)} - Unexpected error occurred during Listing Term update')
            return failed_response(msg='An unexpected error occurred: ', code=status.HTTP_500_INTERNAL_SERVER_ERROR)
        
    def delete(self, request, pk=None, format=None):
        process_code = generate_random_text(6)
        record('info', f'{process_code}: {log_msg["started"]} - ListingTermsCRUDView DELETE request started')
        try:
            listing_term = ListingTerms.objects.get(pk=pk)
            listing_term.delete()
            record('info', f'{process_code}: {log_msg["completed"]} - Listing term deleted successfully')
            return success_response(msg='Listing Term deleted successfully')
        except ListingTerms.DoesNotExist:
            record('warn', f'{process_code}: Listing Term not found for deletion')
            return failed_response(msg='Listing Term not found', code=status.HTTP_404_NOT_FOUND)
        except Exception as e:
            record('error', f'{process_code}: {str(e)} - Unexpected error occurred during Listing Term deletion')
            return failed_response(msg='An unexpected error occurred: ', code=status.HTTP_500_INTERNAL_SERVER_ERROR)
        

class ListingCRUDView(APIView):
    def get(self, request, pk=None, format=None):
        process_code = generate_random_text(6)
        record('info', f'{process_code}: {log_msg["started"]} - ListingCRUDView GET request started')
        try:
            if pk:
                listing = Listing.objects.get(pk = pk)
                serializer = ListingSerializer(listing)
                record('info', f'{process_code}: {log_msg["completed"]} - Listing retrieved successfully')
                return success_response(data = serializer.data, msg = 'Listing retrieved successfully')
            else:
                listings = Listing.objects.all()
                serializer = ListingSerializer(listings, many=True)
                record('info', f'{process_code}: {log_msg["completed"]} - Listings retrieved successfully')
                return success_response(data = serializer.data, msg='Listings retrieved successfully')
        except Listing.DoesNotExist:
            record('warn', f'{process_code}: Listing not found')
            return failed_response(msg = 'Listings not found', code = status.HTTP_404_NOT_FOUND)
        except Exception as e:
            record('error', f'{process_code}: {str(e)} - Unexpected error occurred during Listing retrieval')
            return failed_response(msg = "An unexpected error occurred: ")

    def post(self, request, format=None):
        process_code = generate_random_text(6)
        record('info', f'{process_code}: {log_msg["started"]} - ListingCRUDView POST request started')
        try:
            validate_required_params(request, ['title','deadline','note'])
            validate('title', request.data.get('title',''),['length:max:100'])
            deadline = validate_and_convert_deadline(request.data.get('deadline',''))
            validate('note',request.data.get('note',''),['length:max:250'])
            data = request.data.copy()
            data['deadline'] = deadline
            serializer = ListingSerializer(data=request.data)
            if serializer.is_valid():
                serializer.save()
                record('info', f'{process_code}: {log_msg["completed"]} - Listing created successfully')
                return success_response(data = serializer.data, msg = 'Listing created successfully')
            record('warn', f'{process_code}: {serializer.errors} - Validation errors during Listing creation')
            return failed_response(msg = serializer.errors, code = status.HTTP_400_BAD_REQUEST)
        except ValidationError as ve:
            record('warn', f'{process_code}: Validation error - {str(ve)}')
            return failed_response(msg = str(ve), code=status.HTTP_400_BAD_REQUEST)
        except Exception as e:
            record('error', f'{process_code}: {str(e)} - Unexpected error occurred during Listing creation')
            return failed_response(msg = 'An unexpected error occurred: ')
        
    def put(self, request, pk=None, format=None):
        process_code = generate_random_text(6)
        record('info', f'{process_code}: {log_msg["started"]} - ListingCRUDView PUT request started')   
        try:
            validate_required_params(request, ['title','deadline','note'])
            validate('title', request.data.get('title',''),['length:max:100'])
            validate_and_convert_deadline(request.data.get('deadline',''))
            validate('note',request.data.get('note',''),['length:max:250'])
            if not pk:
                record('warn', f'{process_code}: Listing ID is required')
                return failed_response(msg='Listing ID is required', code=status.HTTP_404_NOT_FOUND)
            listing = Listing.objects.get(pk = pk)
            serializer = ListingSerializer(listing, data=request.data)
            if serializer.is_valid():
                serializer.save()
                record('info', f'{process_code}: {log_msg["completed"]} - Listing updated successfully')
                return success_response(data = serializer.data, msg='Listing updated successfully')
            record('warn', f'{process_code}: {serializer.errors} - Validation errors during Listing update')
            return failed_response(msg = serializer.errors, code = status.HTTP_400_BAD_REQUEST)
        except Listing.DoesNotExist:
            record('warn', f'{process_code}: Listing not found for update')
            return failed_response(msg = 'Listing not found', code = status.HTTP_404_NOT_FOUND)
        except ValidationError as ve:
            record('warn', f'{process_code}: Validation error - {str(ve)}')
            return failed_response(msg = str(ve), code=status.HTTP_400_BAD_REQUEST)
        except Exception as e:
            record('error', f'{process_code}: {str(e)} - Unexpected error occurred during Listing update')
            return failed_response(msg = 'An unexpected error occurred: ', code = status.HTTP_500_INTERNAL_SERVER_ERROR)
        
    def delete(self, request, pk=None, format=None):
        process_code = generate_random_text(6)
        record('info', f'{process_code}: {log_msg["started"]} - ListingCRUDView DELETE request started')
        try:
            listing = Listing.objects.get(pk = pk)
            listing.delete()
            record('info', f'{process_code}: {log_msg["completed"]} - Listing deleted successfully')
            return success_response(msg = 'Listing deleted successfully')
        except Listing.DoesNotExist:
            record('warn', f'{process_code}: Listing not found')
            return failed_response(msg = 'Listing not found')
        except Exception as e:
            record('error', f'{process_code}: {str(e)} - Unexpected error occurred during Listing deletion')
            return failed_response(msg = 'An unexpected error occurred: ', code = status.HTTP_500_INTERNAL_SERVER_ERROR)


class ListingCountView(APIView):
    def get(self, request, format=None):
        process_code = generate_random_text(6)
        record('info', f'{process_code}: {log_msg["started"]} - ListingCountView GET request started')
        try:
            total_listings = Listing.objects.count()
            record('info', f'{process_code}: {log_msg["completed"]} - Total listings count retrieved successfully: {total_listings}')

            return Response(
                data = {'total_listings':total_listings},
                status=status.HTTP_200_OK
            )
        except Exception as e:
            record('error', f'{process_code}: {str(e)} - Unexpected error occurred while retrieving listing count')

            return Response(
                data = {'error': f'An unexpected error occurred: {str(e)}'},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )
        
class ListingRecentView(APIView):
    def get(self, request, format=None):
        process_code = generate_random_text(6)
        record('info', f'{process_code}: {log_msg["started"]} - ListingRecentView GET request started')
        try:
            listings = Listing.objects.order_by('-created_at')
            record('info', f'{process_code}: Listings ordered by creation date retrieved successfully')
            paginator = LimitOffsetPagination()
            paginator.default_limit = 10
            paginator.limit = int(request.query_params.get('limit', paginator.default_limit))
            paginator.offset = int(request.query_params.get('offset', 0))
            result_page = paginator.paginate_queryset(listings, request)
            serializer = ListingRecentSerializer(result_page, many=True)
            record('info', f'{process_code}: Listings pagination and serialization completed successfully')
            total_count = listings.count()
            categories = ListingCategory.objects.all()
            category_desc = [cat.description for cat in categories]
            record('info', f'{process_code}: Categories retrieved and descriptions extracted')
            response_data = {
                'listings': serializer.data,
                'total_count': total_count,
                'categories': category_desc,
                'applied_count': total_count
            }
            record('info', f'{process_code}: Response data prepared successfully')
            return paginator.get_paginated_response(response_data)
        except Exception as e:
            record('error', f'{process_code}: {str(e)} - Unexpected error occurred during GET request')
            return Response(
                data = {'error': f'An unexpected error occurred: {str(e)}'},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )
        
    
class ListingSingleAPIView(generics.RetrieveAPIView):
    queryset = Listing.objects.all()
    serializer_class = ListingSingleAPISerializer
    

class SearchListingFromNameOrCategoryView(APIView):
    def get(self, request, *args, **kwargs):
        title = request.GET.get('title')
        category = request.GET.get('category')
        try:
            listings = Listing.objects.all()
            if title:
                listings = listings.filter(title__icontains=title)
            if category:
                listings = listings.filter(listingcategory__description__icontains = category)
            if not listings.exists():
                return Response({"listings": []}, status=status.HTTP_200_OK)
            serializer = ListingSerializer(listings, many=True)
            return Response({'listings': serializer.data}, status=status.HTTP_200_OK)
        except NotFoundError as e:
            return Response({"error": str(e)}, status=status.HTTP_404_NOT_FOUND)
        except Exception as e:
            return Response({'error': 'An unexpected error occurred.'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)