import streamlit as st
from pptx import Presentation
from pptx.util import Inches, Pt
from pptx.dml.color import RGBColor
from pptx.enum.text import PP_ALIGN
from groq import Groq
import os
import json
from dotenv import load_dotenv
import tempfile
from tenacity import retry, stop_after_attempt, wait_fixed
import random

load_dotenv()

# Color palettes inspired by Shutterstock
COLOR_PALETTES = [
    {
        'primary': RGBColor(255, 87, 51),   # Orange
        'secondary': RGBColor(0, 115, 207), # Blue
        'accent': RGBColor(255, 255, 255),  # White
        'text': RGBColor(51, 51, 51),       # Dark Gray
        'background': RGBColor(242, 242, 242)  # Light Gray
    },
    {
        'primary': RGBColor(102, 45, 145),  # Purple
        'secondary': RGBColor(255, 230, 0), # Yellow
        'accent': RGBColor(0, 255, 255),    # Cyan
        'text': RGBColor(51, 51, 51),       # Dark Gray
        'background': RGBColor(230, 230, 250)  # Lavender
    },
    {
        'primary': RGBColor(0, 176, 80),    # Green
        'secondary': RGBColor(255, 192, 0), # Gold
        'accent': RGBColor(0, 112, 192),    # Blue
        'text': RGBColor(51, 51, 51),       # Dark Gray
        'background': RGBColor(240, 255, 240)  # Honeydew
    },
    {
        'primary': RGBColor(192, 0, 0),     # Red
        'secondary': RGBColor(0, 176, 240), # Light Blue
        'accent': RGBColor(255, 255, 255),  # White
        'text': RGBColor(51, 51, 51),       # Dark Gray
        'background': RGBColor(255, 240, 245)  # Lavender Blush
    },
    {
        'primary': RGBColor(0, 80, 115),    # Dark Blue
        'secondary': RGBColor(255, 140, 0), # Dark Orange
        'accent': RGBColor(0, 176, 80),     # Green
        'text': RGBColor(51, 51, 51),       # Dark Gray
        'background': RGBColor(240, 248, 255)  # Alice Blue
    }
]

def get_random_color_palette():
    return random.choice(COLOR_PALETTES)

def apply_theme(prs, color_scheme):
    # Apply theme colors to the master slide
    background = prs.slide_masters[0].background
    background.fill.solid()
    background.fill.fore_color.rgb = color_scheme['background']

    # Apply theme colors to placeholders
    for shape in prs.slide_masters[0].placeholders:
        if shape.has_text_frame:
            for paragraph in shape.text_frame.paragraphs:
                for run in paragraph.runs:
                    run.font.color.rgb = color_scheme['text']

def create_title_slide(prs, title, color_scheme):
    slide_layout = prs.slide_layouts[0]  # Title Slide layout
    slide = prs.slides.add_slide(slide_layout)
    
    title_shape = slide.shapes.title
    subtitle_shape = slide.placeholders[1]

    title_shape.text = title
    title_shape.text_frame.paragraphs[0].alignment = PP_ALIGN.CENTER
    title_shape.text_frame.paragraphs[0].font.color.rgb = color_scheme['primary']
    title_shape.text_frame.paragraphs[0].font.size = Pt(44)

    subtitle_shape.text = "Generated with AI"
    subtitle_shape.text_frame.paragraphs[0].alignment = PP_ALIGN.CENTER
    subtitle_shape.text_frame.paragraphs[0].font.color.rgb = color_scheme['secondary']
    subtitle_shape.text_frame.paragraphs[0].font.size = Pt(24)

def create_content_slide(prs, title, content, color_scheme):
    slide_layout = prs.slide_layouts[1]  # Content with Caption layout
    slide = prs.slides.add_slide(slide_layout)
    
    title_shape = slide.shapes.title
    title_shape.text = title
    title_shape.text_frame.paragraphs[0].font.color.rgb = color_scheme['primary']
    title_shape.text_frame.paragraphs[0].font.size = Pt(36)
    
    content_shape = slide.placeholders[1]
    tf = content_shape.text_frame
    tf.clear()  # Clear existing text
    
    # Add main content
    p = tf.paragraphs[0]
    p.text = content['main']
    p.font.size = Pt(18)
    p.font.color.rgb = color_scheme['text']
    
    # Add bullet points
    for bullet in content['bullets']:
        p = tf.add_paragraph()
        p.text = bullet
        p.level = 1
        p.font.size = Pt(16)
        p.font.color.rgb = color_scheme['text']

    # Add a subtle accent to the slide
    left = Inches(0)
    top = Inches(6.5)
    width = prs.slide_width
    height = Inches(0.5)
    shape = slide.shapes.add_shape(1, left, top, width, height)
    shape.fill.solid()
    shape.fill.fore_color.rgb = color_scheme['accent']
    shape.line.color.rgb = color_scheme['accent']

@retry(stop=stop_after_attempt(5), wait=wait_fixed(2))
def generate_slides_content(user_input, num_slides):
    client = Groq(
    api_key=os.environ.get("GROQ_API_KEY"),)
    
    prompt = f"""
    Based on the following input, generate a PowerPoint presentation structure with exactly {num_slides} slides.
    The output should be a JSON array of slides, where each slide is an object with a 'title', 'main' content, and 'bullets' (an array of bullet points).
    Make sure the content is concise and suitable for a presentation.

    User Input: {user_input}

    Example output format:
    [
        {{
            "title": "Slide Title",
            "main": "Main content of the slide",
            "bullets": ["Bullet point 1", "Bullet point 2", "Bullet point 3"]
        }},
        // ... more slides (total should be {num_slides})
    ]
    """

    try:
        chat_completion = client.chat.completions.create(
            messages=[
                {"role": "system", "content": "You are a helpful assistant that generates PowerPoint presentation content and return the content in JSON format."},
                {"role": "user", "content": prompt}
            ],
            model="mixtral-8x7b-32768",
            temperature=1,
            max_tokens=8000
        )

        return json.loads(chat_completion.choices[0].message.content)
    except json.JSONDecodeError:
        st.error("Error: Invalid JSON response from the AI. Retrying...")
        raise
    except Exception as e:
        st.error(f"An error occurred: {str(e)}. Retrying...")
        raise

def generate_presentation(user_input, num_slides):
    try:
        slides_content = generate_slides_content(user_input, num_slides)
        
        prs = Presentation()
        color_scheme = get_random_color_palette()
        apply_theme(prs, color_scheme)
        
        # Create title slide
        create_title_slide(prs, slides_content[0]['title'], color_scheme)
        
        # Create content slides
        for slide in slides_content[1:]:  # Skip the first slide as it's used for the title
            create_content_slide(prs, slide['title'], {'main': slide['main'], 'bullets': slide['bullets']}, color_scheme)
        
        with tempfile.NamedTemporaryFile(delete=False, suffix='.pptx') as tmp:
            prs.save(tmp.name)
            return tmp.name
    except Exception as e:
        st.error(f"Failed to generate presentation: {str(e)}")
        return None

def main():
    st.set_page_config(page_title="PowerPoint Generator", page_icon="📊", layout="wide")
    
    st.title("🎨 AI-Powered PowerPoint Generator")
    st.write("Enter your presentation idea and the number of slides you want, and we'll generate a stylish PowerPoint for you!")

    user_input = st.text_area("Enter the content idea for your presentation:", height=150)
    num_slides = st.number_input("Number of slides:", min_value=2, max_value=20, value=5)

    if st.button("Generate Presentation", use_container_width=True, type="primary"):
        if user_input and num_slides:
            with st.spinner("Generating your stylish presentation... This may take a moment."):
                ppt_file = generate_presentation(user_input, num_slides)
            
            if ppt_file:
                st.success("Presentation generated successfully!")
                
                with open(ppt_file, "rb") as file:
                    st.download_button(
                        label="Download PowerPoint",
                        data=file,
                        file_name="generated_presentation.pptx",
                        mime="application/vnd.openxmlformats-officedocument.presentationml.presentation"
                    )
            else:
                st.error("Failed to generate the presentation. Please try again.")
        else:
            st.warning("Please enter content and specify the number of slides (minimum 2).")

if __name__ == "__main__":
    main()