import json as js
import re
import requests as req
from typing import Union, List, Dict, Optional
from pif_compiler.functions.common_log import get_logger

logger = get_logger()

# --- PARSING ---

def parse_cas_numbers(cas_string: list) -> list:
    logger.debug(f"Parsing CAS numbers: {cas_string}")
    
    cas_raw = cas_string[0]
    cas_raw = re.sub(r"\([^)]*\)", "", cas_raw)
    
    cas_parts = re.split(r"[/;,]", cas_raw)
    cas_list = [cas.strip() for cas in cas_parts if cas.strip()]

    if len(cas_list) == 1 and "--" in cas_list[0]:
        cas_list = [cas.strip() for cas in cas_list[0].split("--")]

    cas_list = [cas for cas in cas_list if cas != "-"]
    
    logger.info(f"Parsed CAS numbers: {cas_list}")
    return cas_list

# --- SEARCH ---

def cosing_search(text: str, mode: str = "name") -> Union[list, dict, None]:
    logger.info(f"Starting COSING search: text='{text}', mode='{mode}'")

    url = "https://api.tech.ec.europa.eu/search-api/prod/rest/search?apiKey=285a77fd-1257-4271-8507-f0c6b2961203&text=*&pageSize=100&pageNumber=1"
    agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0"

    if mode == "name":
        search_query = {
            "bool": {
                "must": [{
                    "text": {
                        "query": f"{text}",
                        "fields": ["inciName.exact", "inciUsaName", "innName.exact", "phEurName", "chemicalName", "chemicalDescription"],
                        "defaultOperator": "AND"
                    }
                }]
            }
        }
    elif mode in ["cas", "ec"]:
        search_query = {"bool": {"must": [{"text": {"query": f"*{text}*", "fields": ["casNo", "ecNo"]}}]}}
    elif mode == "id":
        search_query = {"bool": {"must": [{"term": {"substanceId": f"{text}"}}]}}
    else:
        logger.error(f"Invalid search mode: {mode}")
        raise ValueError(f"Invalid search mode: {mode}")

    files = {"query": ("query", js.dumps(search_query), "application/json")}

    try:
        risposta = req.post(url, headers={"user_agent": agent, "Connection": "keep-alive"}, files=files)
        risposta.raise_for_status()
        data = risposta.json()

        if data.get("results"):
            logger.info(f"COSING search successful")
            return data["results"][0]["metadata"]
        else:
            logger.warning(f"No results found")
            return None

    except req.exceptions.RequestException as e:
        logger.error(f"HTTP request error: {e}")
        raise
    except (KeyError, ValueError, TypeError) as e:
        logger.error(f"Parsing error: {e}")
        raise

# --- CLEANING ---

def clean_cosing(json_data: dict, full: bool = True) -> dict:
    substance_id = json_data.get("substanceId", ["Unknown"])[0] if json_data.get("substanceId") else "Unknown"
    logger.info(f"Cleaning COSING data for: {substance_id}")

    string_cols = [
        "itemType", "phEurName", "chemicalName", "innName", "substanceId", "cosmeticRestriction", "reference"
    ]

    list_cols = [
        "casNo", "ecNo", "functionName", "otherRestrictions", "refNo",
        "sccsOpinion", "sccsOpinionUrls", "identifiedIngredient", 
        "annexNo", "otherRegulations", "nameOfCommonIngredientsGlossary", "inciName", "sccsOpinionUrls"
    ]

    base_url = "https://ec.europa.eu/growth/tools-databases/cosing/details/"
    clean_json = {}

    for key in (string_cols + list_cols):
        current_val = json_data.get(key, [])
        filtered_val = [v for v in current_val if v != "<empty>"]

        if key in list_cols:
            if key in ["casNo", "ecNo"] and filtered_val:
                filtered_val = parse_cas_numbers(filtered_val)
            elif key == "identifiedIngredient" and full and filtered_val:
                filtered_val = identified_ingredients(filtered_val)
            
            clean_json[key] = filtered_val
        else:
            nKey = "commonName" if key == "nameOfCommonIngredientsGlossary" else key
            clean_json[nKey] = filtered_val[0] if filtered_val else ""

    clean_json["cosingUrl"] = f"{base_url}{json_data['substanceId'][0]}"
    return clean_json

def identified_ingredients(id_list: list) -> list:
    logger.info(f"Processing identified ingredients: {id_list}")
    identified = []

    for sub_id in id_list:
        ingredient = cosing_search(sub_id, "id")
        if ingredient:
            identified.append(clean_cosing(ingredient, full=False))
            
    return identified

def cosing_entry(cas: str) -> Optional[dict]:
    logger.info(f"Retrieving COSING entry for CAS: {cas}")
    try:
        search_result = cosing_search(cas, mode="cas")
        if search_result:
            return clean_cosing(search_result)
        else:
            logger.warning(f"No COSING entry found for CAS: {cas}")
            return None
    except Exception as e:
        logger.error(f"Error retrieving COSING entry for CAS {cas}: {e}")
        return None

if __name__ == "__main__":
    raw = cosing_search("72-48-0", "cas")
    clean = clean_cosing(raw)
    print(clean)