import logging
import requests
from typing import Literal
from enum import Enum

logger = logging.getLogger(__name__)


REQUIRED_Q_PARAMS = '-(occurrence_status%3A"absent" OR identification_verification_status%3A"Unconfirmed" OR identification_verification_status%3A"Unconfirmed - not reviewed" OR identification_verification_status%3A"Unconfirmed - plausible")'

#QUERY_A_TOP_SPECIES_COUNTS_BASE_URL = 'https://records-ws.nbnatlas.org/occurrence/facets?facets=taxon_name&flimt=20&q=((species_list_uid%3A"dr2402" OR species_list_uid%3A"dr2413" OR species_list_uid%3A"dr2414" OR species_list_uid%3A"dr590" OR species_list_uid%3A"dr583") AND -(occurrence_status%3A"absent" OR identification_verification_status%3A"Unconfirmed" OR identification_verification_status%3A"Unconfirmed - not reviewed" OR identification_verification_status%3A"Unconfirmed - plausible"))' 
QUERY_A_PROTECTED_TOP_SPECIES_OCCURRENCE_COUNTS_BASE_URL = f'https://records-ws.nbnatlas.org/occurrence/facets?facets=taxon_name&flimit=20&fsort=count&q=((species_list_uid:dr2402 OR species_list_uid:dr2413 OR species_list_uid:dr2414) AND {REQUIRED_Q_PARAMS})'
QUERY_A_PRIORITY_TOP_SPECIES_OCCURRENCE_COUNTS_BASE_URL = f'https://records-ws.nbnatlas.org/occurrence/facets?facets=taxon_name&flimit=20&fsort=count&q=((species_list_uid:dr590 OR species_list_uid:dr583) AND {REQUIRED_Q_PARAMS})'

#this query is called for each list, hence there are no filters on species_list_uid
DYNAMIC_Q_QUERY_A2_UNIQUE_SPECIES_COUNT_BASE_URL = 'https://records-ws.nbnatlas.org/occurrence/facets?facets=taxon_name&flimit=0'

# TODO filtering by species_list_uid doesnt do anything, so for now remove the filter and search the results for species_list_uid
# QUERY_B_PROTECTED_OCCURRENCE_COUNTS_BY_LIST_BASE_URL = f'https://records-ws.nbnatlas.org/occurrence/facets?facets=species_list_uid&flimit=20&q=((species_list_uid:dr2402 OR species_list_uid:dr2413 OR species_list_uid:dr2414) AND {REQUIRED_Q_PARAMS})'
# QUERY_B_PRIORITY_OCCURRENCE_COUNTS_BY_LIST_BASE_URL = f'https://records-ws.nbnatlas.org/occurrence/facets?facets=species_list_uid&flimit=20&q=((species_list_uid:dr590 OR species_list_uid:dr583) AND {REQUIRED_Q_PARAMS})'
QUERY_B_PRIORITY_OCCURRENCE_COUNTS_BY_LIST_BASE_URL = f'https://records-ws.nbnatlas.org/occurrence/facets?facets=species_list_uid&fsort=count&flimit=1000&q=({REQUIRED_Q_PARAMS})'
QUERY_B_PROTECTED_OCCURRENCE_COUNTS_BY_LIST_BASE_URL = f'https://records-ws.nbnatlas.org/occurrence/facets?facets=species_list_uid&fsort=count&flimit=1000&q=({REQUIRED_Q_PARAMS})'

PRIORITY_SPECIES_LISTS = {"dr590":{"name": "Biodiversity Lists - England - NERC S.41)", "uid": "dr590"}, "dr583":{"name": "Biodiversity Action Plan UK list of priority species ", "uid": "dr583"}}

PROTECTED_SPECIES_LISTS = {"dr2402":{"name": "Wildlife and Countryside Act 1981 (Schedule 5) England and Wales ", "uid": "dr2402"}, "dr2413":{"name": "Wildlife and Countryside Act 1981 - Schedule 1, Part I and Part II combined (Birds)", "uid": "dr2413"}, "dr2414":{"name": "Wildlife and Countryside Act 1981 - Schedule 8    (Plants)", "uid": "dr2414"}}


class ListType(str, Enum):
    PRIORITY = "priority"
    PROTECTED = "protected"

def get_unique_species_counts_by_list(list_type: ListType, wkt:str = None) -> tuple[list[dict], int]:
    unique_species_counts_by_list = []
    total_count = 0
    
    if list_type == ListType.PRIORITY:
        species_lists = PRIORITY_SPECIES_LISTS
    else:
        species_lists = PROTECTED_SPECIES_LISTS
    for species_list in species_lists.values():
        url = f'{DYNAMIC_Q_QUERY_A2_UNIQUE_SPECIES_COUNT_BASE_URL}&{_buikdQParam(f"(species_list_uid%3A\"{species_list["uid"]}\")")}'
        if wkt:
            url += f'&wkt={wkt}'
        # print(url)
        base_url, params = _prepare_url_and_params(url)
        try:
            response = requests.get(base_url, params=params, timeout=60)
            response.raise_for_status()
            data = response.json()  
            count = data[0]["count"] if data and data[0].get("count") else 0          
            unique_species_counts_by_list.append({"species_list_name": species_list["name"], "count": count})
            total_count += count
        except requests.exceptions.RequestException as e:
            logger.error(f"Failed to fetch unique species counts from NBN Atlas records-ws: {str(e)}", exc_info=True)
            raise Exception(f"NBN Atlas records-ws error: Failed to fetch species counts. {str(e)}")
    
    return unique_species_counts_by_list, total_count

# def get_priority_unique_species_counts_by_list(wkt:str = None):
#     unique_species_counts_by_list = []
#     for species_list in PROTECTED_SPECIES_LISTS.values():
#         url = f'{DYNAMIC_Q_QUERY_A2_UNIQUE_SPECIES_COUNT_BASE_URL}&wkt={wkt}&{_buikdQParam(f"(species_list_uid%3A\"{species_list["uid"]}\")")}'
#         response = requests.get(url)
#         data = response.json()            
#         unique_species_counts_by_list.append({"species_list_name": species_list["name"], "count": data[0]["count"]})
#     return unique_species_counts_by_list  

# def get_protected_unique_species_counts_by_list(wkt:str = None):
#     unique_species_counts_by_list = []
#     for species_list in PROTECTED_SPECIES_LISTS.values():
#         url = f'{DYNAMIC_Q_QUERY_A2_UNIQUE_SPECIES_COUNT_BASE_URL}&wkt={wkt}&{_buikdQParam(f"(species_list_uid%3A\"{species_list["uid"]}\")")}'
#         response = requests.get(url)
#         data = response.json()            
#         unique_species_counts_by_list.append({"species_list_name": species_list["name"], "count": data[0]["count"]})
#     return unique_species_counts_by_list    

def get_occurrence_counts_by_list_type(list_type: ListType, wkt:str = None):
    occurrence_counts_by_list = []
    total_count = 0
    if list_type == ListType.PRIORITY:        
        base_url = QUERY_B_PRIORITY_OCCURRENCE_COUNTS_BY_LIST_BASE_URL
        species_lists = PRIORITY_SPECIES_LISTS
    else:        
        base_url = QUERY_B_PROTECTED_OCCURRENCE_COUNTS_BY_LIST_BASE_URL
        species_lists = PROTECTED_SPECIES_LISTS
    
    url = f'{base_url}'
    if wkt:
        url += f'&wkt={wkt}'
    base_url, params = _prepare_url_and_params(url)
    print(base_url)
    print(params)
    print(url)
    try:
        response = requests.get(base_url, params=params, timeout=60)
        response.raise_for_status()
        data = response.json()            
        for fieldResult in data[0]["fieldResult"]:
           
            if fieldResult["fq"].split('"')[1] in species_lists.keys(): #temp workaround as facet query ignores the species_list_uid's
                occurrence_counts_by_list.append({"species_list_name": fieldResult["label"], "count": fieldResult["count"]})
                total_count += fieldResult["count"]

            # occurrence_counts_by_list.append({"species_list_name": fieldResult["label"], "count": fieldResult["count"]})
    except requests.exceptions.RequestException as e:
        logger.error(f"Failed to fetch occurrence counts from NBN Atlas records-ws: {str(e)}", exc_info=True)
        raise Exception(f"NBN Atlas records-ws error: Failed to fetch occurrence counts. {str(e)}")

    return occurrence_counts_by_list, total_count

# def get_priority_occurrence_counts_by_list(wkt:str):
#     occurrence_counts_by_list = []
#     for species_list in PRIORITY_SPECIES_LISTS.values():
#         url = f'{QUERY_B_PRIORITY_OCCURRENCE_COUNTS_BY_LIST_BASE_URL}&wkt={wkt}&{_buikdQParam(f"(species_list_uid%3A\"{species_list["uid"]}\")")}'
#         response = requests.get(url)
#         data = response.json()            
#         occurrence_counts_by_list.append({"species_list_name": species_list["name"], "count": data[0]["count"]})
#     return occurrence_counts_by_list

# def get_protected_occurrence_counts_by_list(wkt:str):
#     occurrence_counts_by_list = []
#     for species_list in PROTECTED_SPECIES_LISTS.values():
#         url = f'{QUERY_B_PROTECTED_OCCURRENCE_COUNTS_BY_LIST_BASE_URL}&wkt={wkt}&{_buikdQParam(f"(species_list_uid%3A\"{species_list["uid"]}\")")}'
#         response = requests.get(url)
#         data = response.json()            
#         occurrence_counts_by_list.append({"species_list_name": species_list["name"], "count": data[0]["count"]})
#     return occurrence_counts_by_list

def get_top_species_occurrence_counts_by_list_type(list_type: ListType, wkt:str):
    top_species_counts = []
    if list_type == ListType.PRIORITY:
        species_lists = PRIORITY_SPECIES_LISTS
        base_url = QUERY_A_PRIORITY_TOP_SPECIES_OCCURRENCE_COUNTS_BASE_URL
    else:
        species_lists = PROTECTED_SPECIES_LISTS
        base_url = QUERY_A_PROTECTED_TOP_SPECIES_OCCURRENCE_COUNTS_BASE_URL
    
    url = f'{base_url}'
    if wkt:
        url += f'&wkt={wkt}'
    # print(url)
    base_url, params = _prepare_url_and_params(url)
    # print(base_url)
    # print(params)
    try:
        response = requests.get(base_url, params=params, timeout=60)
        response.raise_for_status()
        data = response.json()        
        
        for fieldResult in data[0]["fieldResult"]:
            print(fieldResult)
            top_species_counts.append({"taxon_name": fieldResult["label"], "count": fieldResult["count"]})
    except requests.exceptions.RequestException as e:
        logger.error(f"Failed to fetch top species counts from NBN Atlas records-ws: {str(e)}", exc_info=True)
        raise Exception(f"NBN Atlas records-ws error: Failed to fetch species occurrence counts. {str(e)}")
            
    return top_species_counts

# def get_priority_top_species_counts(wkt:str):
#     top_species_counts = []
#     for species_list in PRIORITY_SPECIES_LISTS.values():
#         url = f'{QUERY_A_PRIORITY_TOP_SPECIES_COUNTS_BASE_URL}&wkt={wkt}&{_buikdQParam(f"(species_list_uid%3A\"{species_list["uid"]}\")")}'
#         response = requests.get(url)
#         data = response.json()            
#         top_species_counts.append({"species_list_name": species_list["name"], "count": data[0]["count"]})
#     return top_species_counts

# def get_protected_top_species_counts(wkt:str):
#     top_species_counts = []
#     for species_list in PROTECTED_SPECIES_LISTS.values():
#         url = f'{QUERY_A_PROTECTED_TOP_SPECIES_COUNTS_BASE_URL}&wkt={wkt}&{_buikdQParam(f"(species_list_uid%3A\"{species_list["uid"]}\")")}'
#         response = requests.get(url)
#         data = response.json()            
#         top_species_counts.append({"species_list_name": species_list["name"], "count": data[0]["count"]})
#     return top_species_counts

def _buikdQParam(part):
    return f'q=({part} AND {REQUIRED_Q_PARAMS})'


from urllib.parse import urlparse, parse_qsl, urlencode

def _prepare_url_and_params(url: str, extra_params: dict = None):
    """
    Takes a base URL (which may already have query params)
    and merges in extra_params. Returns a tuple: (base_url, params_dict)
    suitable for passing to requests.get().
    """
    extra_params = extra_params or {}

    # Parse existing query params
    parsed = urlparse(url)
    base_url = f"{parsed.scheme}://{parsed.netloc}{parsed.path}"
    existing_params = dict(parse_qsl(parsed.query))

    # Merge existing and extra params
    all_params = {**existing_params, **extra_params}

    return base_url, all_params

