# app.py

import os
import json
import time
import streamlit as st

try:
    from google import genai
    from google.genai import types
except ImportError:
    genai = None
    types = None


# Simple approximate token counter: 1 token ≈ 4 chars
def estimate_tokens(text: str) -> int:
    return max(1, len(text) // 4)


# --------------------- Gemini Client ---------------------
class GeminiClient:
    def __init__(self):
        self.project =  ""
        self.location =  ""

        # You can alternatively read your project and location from env vars here:
        if not self.project:
            self.project = os.getenv("GOOGLE_CLOUD_PROJECT", "")
        if not self.location:
            self.location = os.getenv("GOOGLE_CLOUD_LOCATION", "us-central1")  # Provide a default if desired

        if not self.project:
            st.error("Set GOOGLE_CLOUD_PROJECT environment variable before running")
            st.stop()

        if genai is None:
            st.error("Please install the google-generativeai package to use Gemini model")
            st.stop()

        self.client = genai.Client(
            vertexai=True,
            project=self.project,
            location=self.location,
        )

        # Store last request/response tokens and time for frontend display
        self.last_request_tokens = 0
        self.last_response_tokens = 0
        self.last_response_time = 0.0

    def generate(self, system_prompt: str, user_content: str) -> str:
        """
        Generate chat completion using Vertex AI Gemini model.
        Since Vertex AI Gemini doesn't support 'chat.completions' yet as in OpenAI,
        we simulate a chat prompt by concatenating system and user messages.
        """
        # Combine prompts into one message
        full_message = system_prompt + "\n\n" + user_content

        # Estimate tokens in prompt
        self.last_request_tokens = estimate_tokens(full_message)

        # Call the model:
        start_time = time.time()
        response = self.client.models.generate_content(
            model='gemini-2.0-flash-001',
            contents=full_message
        )
        end_time = time.time()
        self.last_response_time = end_time - start_time

        # Extract generated text
        text = response.candidates[0].content.parts[0].text

        # Estimate tokens in response
        self.last_response_tokens = estimate_tokens(text)

        return text


# --------------------- FUNCTIONS ---------------------
def generate_summary(client: GeminiClient, data: dict) -> str:
    system_prompt = """Analyze the JSON order activity log below and produce a structured, detailed summary report strictly based on the data provided. Your analysis must follow these guidelines and structure:

# 1. Final Outcome
- Clearly state the final status of the order: **Cancelled**, **Returned**, or another status.
- Base the conclusion solely on explicit mentions of "Cancelled" or "Returned" found in any "description" or "text" fields.
- If "Returned" appears, specify the exact reason for the return as stated in the JSON.
- If "Cancelled" is found and "Returned" is not, declare the order Cancelled.
- Do not infer or guess beyond the explicit data.

# 2. Key Notes
- Identify any suspicious patterns such as:
  - Frequent or unusual automated system flags.
  - Multiple coaching sessions or repeated reviews.
  - Any unusual or notable user behaviors or system interventions.
- Call out any automation flags and note if events are clearly system-generated vs. human actions.

# 3. Key Evidence
- Provide specific JSON entries verbatim (quoting "description" or "text") that directly support your conclusion about the final outcome.
- Clearly highlight the cancellation or return reason stated within these entries.

# 4. Order Timeline Overview
- Provide the **order creation timestamp**, formatted as MM/DD/YYYY.
- State the **final status** of the order.
- List the **key users, teams, or system automation agents** involved, differentiating human actors from automated systems (e.g., "DOT COM").
- Briefly summarize the main flow of actions/events across the order lifecycle.

# 5. Critical Events (Chronological Breakdown)
Organize and list events chronologically by date (MM/DD/YYYY), grouped as follows:

- **Fraud Checks**
  - Include all declines, fraud holds, account locks, fraud alert emails, or related system flags.
  - Specify whether each event was initiated by system automation or a human user.

- **Payment Actions**
  - List events such as authorizations, voids, failed transactions, chargebacks, or refunds.

- **Customer Issues Reported**
  - Document all customer-reported issues, including dates and descriptions as recorded in the JSON.

- **Claims and Risk Reviews**
  - Detail any claims raised, risk assessment activities, or reviews by risk or claims teams.

- **Cancellation/Return Triggers**
  - Highlight the exact events that triggered cancellation or return, quoting relevant "description" or "text" fields.

- **Post-resolution Access**
  - Include coaching, user reviews, follow-up notes, or other post-resolution activity logs.
  - Group multiple coaching or review events logically together.



---

# Formatting Requirements:
- Use Markdown headers and bullet points for readability.
- Differentiate system automation actions (e.g., "DOT COM," "System") from human operator actions (specific users or team names).
- Use normal date format (MM/DD/YYYY) consistently for all timestamps.
- Group repeated events under combined bullet points with summaries.

---

# Important Rules:
- If any "description" or "text" field contains **"Cancelled"**, classify the order as **Cancelled**.
- If "Returned" is present with reasons, classify order as **Returned** and provide the explicit reason.
- Avoid assumptions and only conclude based on explicit JSON data.

---

Use this prompt verbatim when processing JSON order activity logs to generate insightful, fact-based summaries highlighting order lifecycle, customer interactions, claims and risk assessments, fraud and payment activities, and the conclusive final outcome. """

    user_content = json.dumps(data, indent=2)

    try:
        return client.generate(system_prompt=system_prompt, user_content=user_content)
    except Exception as e:
        return f"Error generating summary: {str(e)}"


# --------------------- STREAMLIT UI ---------------------
st.set_page_config("Macy's Notes Analyzer with Vertex AI Gemini", layout="wide")
st.title("📑 Macy's Notes Analysis — Direct LLM Processing (Vertex AI Gemini)")

uploaded_file = st.file_uploader("Upload Macy's JSON Notes", type="json")

if uploaded_file:
    try:
        data = json.load(uploaded_file)

        client = GeminiClient()  # Initialize Vertex AI client

        with st.spinner("🔍 Analyzing documents..."):
            summary = generate_summary(client, data)

        st.success("✅ Analysis Complete!")

        # Display tokens and time info
        st.markdown(f"**Prompt tokens (approx.):** {client.last_request_tokens}")
        st.markdown(f"**Response tokens (approx.):** {client.last_response_tokens}")
        st.markdown(f"**Response time:** {client.last_response_time:.2f} seconds")

        # Display formatted summary
        st.markdown("## 📝 Comprehensive Summary")
        st.markdown(summary)

    except json.JSONDecodeError:
        st.error("❌ Invalid JSON file format")
    except Exception as e:
        st.error(f"❌ Processing error: {str(e)}")

# Optional: Add original data preview
if uploaded_file and st.checkbox("Show raw data preview"):
    uploaded_file.seek(0)
    st.json(json.load(uploaded_file))


give me a code in python flask api as routes, llms, helpers as you can create also give me similar way to get output by azure gpt like below code , and choose option from which we can get the output also display the llm model name in output 
# llm/openai_client.py
import os
import json
from dotenv import load_dotenv
from openai import AzureOpenAI

# Load env variables once here
load_dotenv()

AZURE_OPENAI_ENDPOINT = os.getenv("AZURE_OPENAI_ENDPOINT")
AZURE_OPENAI_KEY = os.getenv("AZURE_OPENAI_KEY")
AZURE_OPENAI_DEPLOYMENT = os.getenv("AZURE_OPENAI_DEPLOYMENT")
AZURE_OPENAI_API_VERSION = os.getenv("AZURE_OPENAI_API_VERSION")

# Initialize client once
openai_client = AzureOpenAI(
    azure_endpoint=AZURE_OPENAI_ENDPOINT,
    api_key=AZURE_OPENAI_KEY,
    api_version=AZURE_OPENAI_API_VERSION,
)

def generate_summary(data):
    system_prompt = """Analyze the JSON order activity log below and create a structured summary. Focus on:  
1. **Final Outcome**: Clearly state if the order was *Cancelled* or *Returned* or anything else (with reasons from the data and outcome and last recorded activity).  
2. **Order Timeline Overview** (creation timestamp, final status, key users/teams involved)  
3. **Critical Events**: Chronological breakdown of:  
   - Fraud checks (declines, locks, emails)  
   - Payment actions (authorization, voids)  
   - Cancellation/return triggers (e.g., "Order Cancelled" descriptions)  
   - Post-resolution access (e.g., coaching/reviews).  
4. **Key Notes** (patterns, automation flags, unusual access patterns, or notable reasons)    
5. **Key Evidence**: Specific JSON entries proving the outcome (e.g., "Cancelled due to DECLINED: Fraud").  

**Structure Requirements**:  
- Use markdown headers and bullet points.  
- Differentiate between system automation (e.g., "DOT COM") and human actions.  
- Group repeated events (e.g., multiple "Coaching" logs).  
- Highlight the *exact reason* for cancellation/return from the "text" or "description" fields.  

**Rules**:  
- If "Cancelled" appears in any "description" or "text" field, declare it as the outcome.  
- If "Returned" is not explicitly mentioned, assume cancellation.  
- Never guess – use only the provided JSON for conclusions.


"""

    try:
        response = openai_client.chat.completions.create(
            model=AZURE_OPENAI_DEPLOYMENT,
            messages=[
                {"role": "system", "content": system_prompt},
                {"role": "user", "content": json.dumps(data, indent=2)}
            ],
            temperature=0,
        )
        return response.choices[0].message.content
    except Exception as e:
        return f"Error generating summary: {str(e)}"