import os
import gradio as gr
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots
from langchain_groq import ChatGroq
from langchain.prompts import PromptTemplate
from typing import TypedDict, List
from typing_extensions import Annotated
from dotenv import load_dotenv
import numpy as np

load_dotenv()
api_key = os.getenv('GROQ_API_KEY')

class AssessmentOutput(TypedDict):
    stress_management: Annotated[float, "Percentage score (0-100) for Stress Management KPI"]
    motivation: Annotated[float, "Percentage score (0-100) for Motivation KPI"]
    restless_night_score: Annotated[float, "Percentage score (0-100) for Restless Night Score KPI"]
    anxiety_level: Annotated[float, "Percentage score (0-100) for Anxiety Level KPI"]
    burnout_level: Annotated[float, "Percentage score (0-100) for Burnout Level KPI"]
    physical_fitness_score: Annotated[float, "Percentage score (0-100) for Physical Fitness KPI"]
    dietary_habit_score: Annotated[float, "Percentage score (0-100) for Diet & Nutrition KPI"]
    focus_score: Annotated[float, "Percentage score (0-100) for Cognitive Performance and Focus KPI"]
    overall_wellness_score: Annotated[float, "Percentage score (0-100) based on all the individual KPIs"]
    package: Annotated[List[str], "List of recommended packages. Options include 'Focus', 'Fitness', and 'Insomnia'. The recommendation can be a single package, a combination of packages, or all three packages based on the assessment."]
    report: Annotated[str, "A detailed summary report of the assessment results and recommendations based on the KPI analysis."]

template = """
You are an AI wellness assessment system designed to evaluate users' well-being and provide personalized insights. This assessment system analyzes responses and generates wellness reports, recommending specific services and packages from *DailyWellnessAI* to help users improve their mental and physical health. While this system itself is not called *DailyWellnessAI*, all recommendations are part of the *DailyWellnessAI* platform.

Based on the user's responses to the following 15 questions, along with their personal details (Age, Gender, Height, Weight), predict the following KPIs as percentages out of 100:
- stress_management
- motivation
- restless_night_score
- anxiety_level
- burnout_level
- physical_fitness_score
- dietary_habit_score
- focus_score
- overall_wellness_score

**Recommendation System:**
Based on the predicted KPIs, recommend one of the following *DailyWellnessAI* packages:
- Focus (for low concentration, motivation, burnout, mental fog, and lack of focus)
- Insomnia (for sleep disturbances, restlessness, anxiety before sleep, difficulty sleeping, and poor sleep quality)
- Fitness (for low physical activity, poor dietary habits, weak physical strength, low endurance, and lack of energy)

If the overall_wellness_score is greater than 90 (or 95), recommend all three packages and let the user choose among them, emphasizing that DailyWellnessAI offers holistic well-being solutions.

**Summary Report:**
Provide a brief wellness summary explaining the predicted KPIs and recommended package(s) based on the user's responses. Justify the recommendations by highlighting key factors affecting the user's well-being and how DailyWellnessAI can help improve them. Take into account the user's name, age, gender, height, and weight when providing recommendations.

### Personal Details:
- Age: {age}
- Gender: {gender}
- Height: {height}
- Weight: {weight}

### Assessment Questions:

1. How often do you feel stressed by daily tasks?
   Options: Never, Sometimes, Often, Always
   Answer: {ans1}

2. How well do you handle stress?
   Options: Excellent, Good, Fair, Poor
   Answer: {ans2}

3. How would you rate your current level of burnout?
   Options: None, Mild, Moderate, Severe
   Answer: {ans3}

4. How well can you concentrate on your daily tasks?
   Options: Excellent, Good, Fair, Poor
   Answer: {ans4}

5. How often do you have trouble falling asleep?
   Options: Never, Rarely, Sometimes, Always
   Answer: {ans5}

6. How would you rate the quality of your sleep?
   Options: Excellent, Good, Fair, Poor
   Answer: {ans6}

7. How often do you wake up during the night?
   Options: Never, Rarely, Sometimes, Often
   Answer: {ans7}

8. How often do you feel anxious before sleep?
   Options: Never, Rarely, Sometimes, Often
   Answer: {ans8}

9. How happy are you with your eating habits?
   Options: Very happy, Happy, Unhappy, Very unhappy
   Answer: {ans9}

10. How balanced is your diet?
    Options: Very balanced, Balanced, Unbalanced, Very unbalanced
    Answer: {ans10}

11. How often do you exercise or do physical activity?
    Options: Daily, Several times a week, Once a week, Never
    Answer: {ans11}

12. How would you rate your physical strength?
    Options: Excellent, Good, Fair, Poor
    Answer: {ans12}

13. How motivated are you to work on your wellness goals daily?
    Options: Very motivated, Moderately motivated, Slightly motivated, Not at all
    Answer: {ans13}

14. How would you rate your overall health and well-being?
    Options: Excellent, Good, Fair, Poor
    Answer: {ans14}

15. Any more remarks about yourself that you want to add?
    Answer: {ans15}

Use the responses and personal details to generate KPI predictions, determine the recommended *DailyWellnessAI* package(s), and provide a concise summary report that briefly justifies the recommendations, taking into account the user's age, gender, height, and weight.
"""

chat = ChatGroq(api_key=api_key, model="llama-3.3-70b-versatile", temperature=0.2)
prompt_template = PromptTemplate(
    input_variables=["age", "gender", "height", "weight"] + [f"ans{i}" for i in range(1, 16)],
    template=template
)

def run_assessment(personal_details, answers):
    prompt = prompt_template.format(**personal_details, **answers)
    structured_llm = chat.with_structured_output(AssessmentOutput)
    return structured_llm.invoke(prompt)

def get_emoji(score):
    if score < 20:
        return "😢"
    elif score < 40:
        return "😞"
    elif score < 60:
        return "😐"
    elif score < 80:
        return "🙂"
    else:
        return "😄"

def create_overall_wellness_donut(score):
    color = '#FF5252' if score < 50 else '#FFC107' if score < 75 else '#4CAF50'
    fig = go.Figure(go.Pie(
        values=[score, 100 - score],
        hole=0.7,
        textinfo='none',
        marker_colors=[color, '#E0E0E0'],
        showlegend=False
    ))
    fig.update_layout(
        annotations=[dict(
            text=f"{get_emoji(score)}",
            font_size=24,
            showarrow=False
        )],
        title=dict(text="Overall Wellness", x=0.5, font=dict(size=16)),
        margin=dict(t=20, b=20, l=20, r=20),
        height=300
    )
    return fig

def create_kpi_bar_chart(kpis, values):
    colors = ['#FF5252' if v < 50 else '#FFC107' if v < 75 else '#4CAF50' for v in values]
    fig = go.Figure(go.Bar(
        x=kpis,
        y=values,
        marker_color=colors,
        text=[f"{v}%" for v in values],
        textposition='auto'
    ))
    fig.update_layout(
        title="KPI Breakdown",
        xaxis=dict(title="KPI"),
        yaxis=dict(title="Score (%)", range=[0, 100]),
        margin=dict(l=40, r=40, t=60, b=40),
        height=400
    )
    return fig

def create_radar_chart(data):
    categories = [
        'Stress Management',
        'Motivation',
        'Sleep Quality',
        'Anxiety Control',
        'Burnout Resistance',
        'Physical Fitness',
        'Diet & Nutrition',
        'Focus'
    ]
    values = [
        float(data['stress_management']),
        float(data['motivation']),
        100 - float(data['restless_night_score']),
        100 - float(data['anxiety_level']),
        100 - float(data['burnout_level']),
        float(data['physical_fitness_score']),
        float(data['dietary_habit_score']),
        float(data['focus_score'])
    ]
    fig = go.Figure()
    fig.add_trace(go.Scatterpolar(
        r=values,
        theta=categories,
        fill='toself',
        fillcolor='rgba(76, 175, 80, 0.3)',
        line=dict(color='#4CAF50', width=2),
        name='Your Profile'
    ))
    fig.update_layout(
        polar=dict(
            radialaxis=dict(visible=True, range=[0, 100], tickfont=dict(size=10))
        ),
        showlegend=False,
        margin=dict(l=40, r=40, t=20, b=20),
        height=400
    )
    return fig

def create_bullet_charts_combined(data):
    bullet_data = [
        ("Stress Management", float(data['stress_management'])),
        ("Motivation", float(data['motivation'])),
        ("Sleep Quality", 100 - float(data['restless_night_score'])),
        ("Anxiety Control", 100 - float(data['anxiety_level'])),
        ("Burnout Resistance", 100 - float(data['burnout_level'])),
        ("Physical Fitness", float(data['physical_fitness_score'])),
        ("Diet & Nutrition", float(data['dietary_habit_score'])),
        ("Focus", float(data['focus_score']))
    ]
    rows, cols = 2, 4
    target = 80
    fig = make_subplots(rows=rows, cols=cols, subplot_titles=[item[0] for item in bullet_data])
    for i, (label, val) in enumerate(bullet_data):
        row = i // cols + 1
        col = i % cols + 1
        fig.add_trace(go.Bar(
            x=[val],
            y=[""],
            orientation="h",
            marker_color='#4CAF50' if val >= target else '#FF5252',
            text=[f"{val}%"],
            textposition='inside',
            showlegend=False
        ), row=row, col=col)
        fig.update_xaxes(range=[0, 100], row=row, col=col)
        fig.add_shape(
            type="line",
            x0=target, x1=target,
            y0=0, y1=1,
            xref=f"x{i+1}",
            yref=f"y{i+1}",
            line=dict(color="black", width=2, dash="dash")
        )
    fig.update_layout(height=400, width=1000, margin=dict(l=20, r=20, t=40, b=20))
    return fig

def combine_report(results):
    packages = results["package"]
    rec_text = ", ".join(packages) if packages else "None"
    final_text = f"### Report\n{results['report']}\n\n**Recommended Packages:** {rec_text}"
    return final_text

def gradio_assessment(
    age, gender, height, weight,
    ans1, ans2, ans3, ans4, ans5,
    ans6, ans7, ans8, ans9, ans10,
    ans11, ans12, ans13, ans14, ans15
):
    personal_details = {
        "age": age,
        "gender": gender,
        "height": height,
        "weight": weight
    }
    answers = {
        "ans1": ans1, "ans2": ans2, "ans3": ans3, "ans4": ans4, "ans5": ans5,
        "ans6": ans6, "ans7": ans7, "ans8": ans8, "ans9": ans9, "ans10": ans10,
        "ans11": ans11, "ans12": ans12, "ans13": ans13, "ans14": ans14,
        "ans15": ans15
    }
    results = run_assessment(personal_details, answers)
    overall_score = int(float(results["overall_wellness_score"]))
    donut_fig = create_overall_wellness_donut(overall_score)
    kpis = [
        "Stress Management", "Motivation", "Sleep Quality",
        "Anxiety Control", "Burnout Resistance", "Physical Fitness",
        "Diet & Nutrition", "Focus"
    ]
    values = [
        float(results["stress_management"]),
        float(results["motivation"]),
        100 - float(results["restless_night_score"]),
        100 - float(results["anxiety_level"]),
        100 - float(results["burnout_level"]),
        float(results["physical_fitness_score"]),
        float(results["dietary_habit_score"]),
        float(results["focus_score"])
    ]
    bar_fig = create_kpi_bar_chart(kpis, values)
    radar_fig = create_radar_chart(results)
    bullet_fig = create_bullet_charts_combined(results)
    report_text = combine_report(results)
    return donut_fig, bar_fig, radar_fig, bullet_fig, report_text

def build_app():
    with gr.Blocks() as demo:
        gr.Markdown("# 🌿 DailyWellnessAI Assessment")
        gr.Markdown("Fill out the questionnaire below to receive personalized insights and recommendations.")
        with gr.Row():
            with gr.Column():
                age = gr.Number(label="Your Age")
                gender = gr.Dropdown(label="Your Gender", choices=["Male", "Female", "Other"], value="Male")
                height = gr.Textbox(label="Your Height (e.g., 180 cm)", placeholder="Enter your height")
                weight = gr.Textbox(label="Your Weight (e.g., 80 kg)", placeholder="Enter your weight")
            with gr.Column():
                ans1 = gr.Dropdown(label="1. How often do you feel stressed by daily tasks?", choices=["Never", "Sometimes", "Often", "Always"], value="Never")
                ans2 = gr.Dropdown(label="2. How well do you handle stress?", choices=["Excellent", "Good", "Fair", "Poor"], value="Good")
                ans3 = gr.Dropdown(label="3. How would you rate your current level of burnout?", choices=["None", "Mild", "Moderate", "Severe"], value="None")
                ans4 = gr.Dropdown(label="4. How well can you concentrate on your daily tasks?", choices=["Excellent", "Good", "Fair", "Poor"], value="Good")
                ans5 = gr.Dropdown(label="5. How often do you have trouble falling asleep?", choices=["Never", "Rarely", "Sometimes", "Always"], value="Rarely")
                ans6 = gr.Dropdown(label="6. How would you rate the quality of your sleep?", choices=["Excellent", "Good", "Fair", "Poor"], value="Good")
                ans7 = gr.Dropdown(label="7. How often do you wake up during the night?", choices=["Never", "Rarely", "Sometimes", "Often"], value="Rarely")
                ans8 = gr.Dropdown(label="8. How often do you feel anxious before sleep?", choices=["Never", "Rarely", "Sometimes", "Often"], value="Rarely")
            with gr.Column():
                ans9 = gr.Dropdown(label="9. How happy are you with your eating habits?", choices=["Very happy", "Happy", "Unhappy", "Very unhappy"], value="Happy")
                ans10 = gr.Dropdown(label="10. How balanced is your diet?", choices=["Very balanced", "Balanced", "Unbalanced", "Very unbalanced"], value="Balanced")
                ans11 = gr.Dropdown(label="11. How often do you exercise or do physical activity?", choices=["Daily", "Several times a week", "Once a week", "Never"], value="Daily")
                ans12 = gr.Dropdown(label="12. How would you rate your physical strength?", choices=["Excellent", "Good", "Fair", "Poor"], value="Good")
                ans13 = gr.Dropdown(label="13. How motivated are you to work on your wellness goals daily?", choices=["Very motivated", "Moderately motivated", "Slightly motivated", "Not at all"], value="Very motivated")
                ans14 = gr.Dropdown(label="14. How would you rate your overall health and well-being?", choices=["Excellent", "Good", "Fair", "Poor"], value="Good")
                ans15 = gr.Textbox(label="15. Any more remarks about yourself that you want to add?", lines=3)
        with gr.Row():
            submit_btn = gr.Button("Submit Assessment")
        with gr.Row():
            gr.Markdown("## Results")
        with gr.Row():
            donut_plot = gr.Plot(label="Overall Wellness Donut")
            bar_plot = gr.Plot(label="KPI Bar Chart")
        with gr.Row():
            radar_plot = gr.Plot(label="Radar Chart")
            bullet_plot = gr.Plot(label="Bullet Charts")
        with gr.Row():
            report_md = gr.Markdown(label="Assessment Report")
        submit_btn.click(
            fn=gradio_assessment,
            inputs=[age, gender, height, weight, ans1, ans2, ans3, ans4, ans5, ans6, ans7, ans8, ans9, ans10, ans11, ans12, ans13, ans14, ans15],
            outputs=[donut_plot, bar_plot, radar_plot, bullet_plot, report_md]
        )
    return demo

if __name__ == "__main__":
    demo_app = build_app()
    demo_app.launch(server_name="0.0.0.0", server_port=7860, share=True)