from django.http import JsonResponse
import json
import random 
import string
from rest_framework.response import Response
from rest_framework import status
from rest_framework.pagination import LimitOffsetPagination
from utils.exception import ValidationError
from datetime import datetime, timedelta
import re
from listing.models import Listing
import pytz
from django.utils import timezone
from utils.data import validation_msg

from rest_framework.views import APIView
from rest_framework import status
from rest_framework.response import Response
from django.contrib.auth import get_user_model
from utils.validation import is_email

def success_response(data=None, msg='Success'):
    return Response({
        'status': 'success',
        'msg': msg,
        'data': data
    }, status=status.HTTP_200_OK)

def failed_response(msg, code):
    return Response({
        'status': 'failure',
        'msg': msg
    }, status=code)


def generate_random_text(length):
        characters = string.ascii_lowercase + string.digits[1:]

        return ''.join(random.choice(characters) for _ in range(length))

User = get_user_model()
class CheckUniqueUsernameOrEmailAPIView(APIView):
    def post(self, request, *args, **kwargs):
        try:
            data = request.data
            if 'email' in data:
                email = data.get('email')
                if self.is_email(email):
                    if User.objects.filter(email=email).exists():
                        return failed_response(msg="Email is already registered.", code=status.HTTP_400_BAD_REQUEST)
                else:
                    return failed_response(msg="Invalid email format.", code=status.HTTP_400_BAD_REQUEST)
            if 'username' in data:
                username = data.get('username')
                if User.objects.filter(username=username).exists():
                    return failed_response(msg="Username is already taken.", code=status.HTTP_400_BAD_REQUEST)
            return success_response(msg="Both email and username are available.")
        except Exception as e:
            return failed_response(msg=f"An unexpected error occurred: {str(e)}", code=status.HTTP_500_INTERNAL_SERVER_ERROR)
    def is_email(self, value):
        return is_email(value)


def bs_to_ad(bs_year): 
    return bs_year - 56

def ad_to_bs(ad_year):
    return ad_year + 56
       
def validate_fiscal_year(fiscal_year):
    ad_pattern = re.compile(r'^(\d{4}) AD$')
    bs_pattern = re.compile(r'^(\d{4}) BS$')
    range_pattern = re.compile(r'^(\d{4}) - (\d{4}) (AD|BS)$')

    if ad_pattern.match(fiscal_year):
        year = int(ad_pattern.match(fiscal_year).group(1))
        current_year = datetime.now().year
        if year < 1900 or year > current_year + 10:
            raise ValidationError(f"Year {year} is out of range")
    elif bs_pattern.match(fiscal_year):
        year = int(bs_pattern.match(fiscal_year).group(1))
        ad_year = bs_to_ad(year)
        if ad_year < 1900 or ad_year > datetime.now().year + 10 :
            raise ValidationError(f"Year {year} BS (converted to {ad_year} AD) is out of plausible range")
    elif range_pattern.match(fiscal_year):
        start_year, end_year, year_type = range_pattern.match(fiscal_year).groups()
        start_year = int(start_year)
        end_year = int(end_year)
        if year_type == 'AD':
            if start_year >= end_year:
                raise ValidationError("Start year must be less than end year")
            if start_year < 1900 or end_year > datetime.now().year + 10:
                raise ValidationError(f"Year range {start_year} - {end_year} AD is out of range")
        elif year_type == 'BS':
            start_ad = bs_to_ad(start_year)
            end_ad = bs_to_ad(end_year)
            if start_ad >= end_ad:
                raise ValidationError("Start year should be less than end year")
            if start_ad < 1900 or end_ad > datetime.now().year + 10:
                raise ValidationError(f"Year range {start_year} - {end_year} BS is out of range")
    else:
        raise ValidationError("Fiscal year format must be 'YYYY AD', 'YYYY BS', 'YYYY-YYYY AD', or 'YYYY-YYYY BS'")


def validate_and_convert_deadline(deadline_utc):
    kathmandu_tz = pytz.timezone('Asia/Kathmandu')
    try:
        deadline_naive = datetime.fromisoformat(deadline_utc.replace('Z', '+00:00'))
    except ValueError:
        raise ValidationError("Invalid date format. Please provide a valid ISO date string.")
    if deadline_naive.tzinfo is None:
        deadline_utc = pytz.utc.localize(deadline_naive)
    else:
        deadline_utc = deadline_naive.astimezone(pytz.utc)
    deadline_kathmandu = deadline_utc.astimezone(kathmandu_tz)
    if deadline_kathmandu < timezone.now():
        raise ValidationError(f"Deadline cannot be in the past. Provided deadline: {deadline_kathmandu}")
    return deadline_kathmandu

def calculate_remaining_time(request):
    if request.method == 'POST':
        # Extract the deadline from POST data
        deadline_str = request.POST.get('deadline')  # Assumes deadline is passed as a string

        if deadline_str:
            try:
                # Convert the string to a datetime object
                deadline = datetime.strptime(deadline_str, '%Y-%m-%d %H:%M:%S')
                
                # Calculate the remaining time
                remaining_time = get_deadline_remaining_time(deadline)
                
                return JsonResponse({'remaining_time': remaining_time})
            
            except ValueError:
                return JsonResponse(f"{validation_msg['datetime']}", status=400)
        else:
            return JsonResponse({'error': 'Deadline not provided'}, status=400)
    
    return JsonResponse({'error': 'Invalid request method. Use POST.'}, status=405)


def get_deadline_remaining_time(deadline):
    time_remaining = deadline - datetime.now()
    if time_remaining <= timedelta(0):
        return "Deadline has passed"
    days, seconds = time_remaining.days, time_remaining.seconds
    hours = seconds // 3600
    minutes = (seconds % 3600) // 60
    seconds = seconds % 60

    time_parts = []
    if days > 0:
        time_parts.append(f"{days} day(s)")
    if hours > 0:
        time_parts.append(f"{hours} hour(s)")
    if minutes > 0:
        time_parts.append(f"{minutes} minute(s)")
    if seconds > 0:
        time_parts.append(f"{seconds} second(s)")

    return ', '.join(time_parts)

