import os

import openai
from dotenv import load_dotenv

class ContentEvaluator:

    MINIMUM_SCORE_THRESHOLD = 60
    TAG_NOT_FOUND_ERROR_CODE = -1
    ADDITIONAL_REQUIREMENTS_NOT_MET_ERROR_CODE = -2
    PROFANITY_DETECTED_ERROR_CODE = -69

    # Required: 
    # image_url (url to image)
    # Optional:
    # required_tag (tag that must be present in the image)
    # requirements (list of additional requirements)
    @staticmethod
    def score_content(image_url: str, required_tag: str = None, requirements: list = []):
        
        # required_tag_text = f"- The photo must contain the tag {required_tag}. If the tag is not found, return a score of {ContentEvaluator.TAG_NOT_FOUND_ERROR_CODE}." if required_tag else ""
        requirements_text = "\n- ".join(requirements)
        intro_text = f"The brand requested the following requirements. If any of the following requirements are very clearly not met, return a score of {ContentEvaluator.ADDITIONAL_REQUIREMENTS_NOT_MET_ERROR_CODE}."
        full_requirements_text = f"{intro_text}\n- {requirements_text}" if len(requirements) > 0 else ""
        prompt_text = f"""
You are a simulated AI photo reviewer who assesses UGC content for brands.
Based the provided photo and the below criteria, provide a hypothetical score out of 100, understanding that this is an estimation and not a definitive assessment. 

A few notes: 
- The scoring scale should follow a grade-school approach, where 90-100 is an A, 80-89 is a B, 70-79 is a C, 60-69 is a D, and 0-59 is an F. Your should only include a number and not a letter grade. However, keep the grade scale in mind when determining the score.
- It's okay if the content contains text, especially if the text adds to the photo.

The following qualities are not requirements. Photos with these qualities should receive higher scores, but lacking these qualities should not result in a negative score.
The brand would prefer if the photo is:
- Clear
- High-quality
- Well-lit
- In-focus
- Well-composed
- Visually appealing
 
Remember negative scores serve as error codes. Do not return a negative score unless you are 100% certain that there is an issue with the content. If you return a negative score, ensure it is the correct error code.

If offensive language is found, return a score of {ContentEvaluator.PROFANITY_DETECTED_ERROR_CODE}.

{full_requirements_text}

In your response, please include the following.
Score: a number out of 100, where 100 is the best possible score
Pros: Up to three, one-to-four word bullet points of "pros"
Cons: Up to three, one-to-four word bullet points of "cons"
Text: A list of all text found in the image. If no text is found, return an empty list.

Do not mention profanity in the pros or cons. Do not include any additional information.
"""
        print(prompt_text)
        load_dotenv()
        client = openai.OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
        prompt_messages = [
            {
                "role": "user",
                "content": [
                    {"type": "text", "text": prompt_text},
                    {
                    "type": "image_url",
                    "image_url": {
                        "url": image_url,
                        "detail": "low"
                    }
                    }
                ]
            }
        ]

        # Send a request to GPT
        try:
            params = {
                "model": "gpt-4-vision-preview",
                "messages": prompt_messages,
                "max_tokens": 4096,
            }

            result = client.chat.completions.create(**params)
            result_content = result.choices[0].message.content
            return ContentEvaluator.extract_info_from_response(result_content, required_tag)
        except Exception as e:
            return f"Error in processing request: {e}"


    @staticmethod
    def extract_info_from_response(response: str, required_tag: str):
        pros = []
        cons = []
        text_list = []
        score = None

        # Extract score (be sure to account for negative scores)
        score_start_index = response.find("Score:")
        score_end_index = response.find("Pros:")
        score_text = response[score_start_index + len("Score:"):score_end_index].strip()
        if score_text[0] == "-":
            score = int(score_text[1:]) * -1
        else:
            score = int(score_text)

        # Extract pros
        pros_start_index = response.find("Pros:")
        pros_end_index = response.find("Cons:")
        pros_text = response[pros_start_index + len("Pros:"):pros_end_index].strip()
        pros = pros_text.split("\n-")

        # Extract cons
        cons_start_index = response.find("Cons:")
        cons_end_index = response.find("Text:")  # Assuming "Text" section comes after "Cons"
        cons_text = response[cons_start_index + len("Cons:"):cons_end_index].strip()
        cons = cons_text.split("\n-")

        # Extract text
        text_start_index = response.find("Text:")
        if text_start_index != -1:  # Check if "Text" section exists
            all_text_str = response[text_start_index + len("Text:"):].strip()
        
        if required_tag:
            if required_tag not in all_text_str:
                score = ContentEvaluator.TAG_NOT_FOUND_ERROR_CODE # overwrite score with error code if tag is not found

        return {"score": score, "pros": pros, "cons": cons, "texts": text_list}
