"""
Admin sets proxy url + allowed email subdomain 
"""
from dotenv import load_dotenv

load_dotenv()
import streamlit as st
import base64, os, json, uuid, requests
import pandas as pd
import plotly.express as px
import click

# Replace your_base_url with the actual URL where the proxy auth app is hosted
your_base_url = os.getenv("BASE_URL")  # Example base URL


# Function to encode the configuration
def encode_config(proxy_url, allowed_email_subdomain, admin_emails):
    combined_string = f"proxy_url={proxy_url}&accepted_email_subdomain={allowed_email_subdomain}&admin_emails={admin_emails}"
    return base64.b64encode(combined_string.encode("utf-8")).decode("utf-8")


# Simple function to update config values
def update_config_values(proxy_url, allowed_email_subdomain, admin_emails):
    st.session_state["proxy_url"] = proxy_url
    st.session_state["allowed_email_subdomain"] = allowed_email_subdomain
    st.session_state["admin_emails"] = admin_emails
    if your_base_url.endswith("/"):
        st.session_state[
            "user_auth_url"
        ] = f"{your_base_url}user?page={encode_config(proxy_url=proxy_url, allowed_email_subdomain=allowed_email_subdomain, admin_emails=admin_emails)}"
    else:
        st.session_state[
            "user_auth_url"
        ] = f"{your_base_url}/user?page={encode_config(proxy_url=proxy_url, allowed_email_subdomain=allowed_email_subdomain, admin_emails=admin_emails)}"
    st.session_state["is_admin"] = True


def proxy_setup():
    # Create a configuration placeholder
    st.session_state.setdefault("proxy_url", "http://example.com")
    st.session_state.setdefault("allowed_email_subdomain", "example.com")
    st.session_state.setdefault("admin_emails", "admin@example.com")
    st.session_state.setdefault("user_auth_url", "NOT_GIVEN")

    with st.form("config_form", clear_on_submit=False):
        proxy_url = st.text_input("Set Proxy URL", st.session_state["proxy_url"])
        allowed_email_subdomain = st.text_input(
            "Set Allowed Email Subdomain", st.session_state["allowed_email_subdomain"]
        )
        admin_emails = st.text_input(
            "Allowed Admin Emails (add ',' to separate multiple emails)",
            st.session_state["admin_emails"],
        )
        submitted = st.form_submit_button("Save")

        if submitted:
            update_config_values(
                proxy_url=proxy_url,
                allowed_email_subdomain=allowed_email_subdomain,
                admin_emails=admin_emails,
            )

    # Display the current configuration
    st.write(f"Current Proxy URL: {st.session_state['proxy_url']}")
    st.write(
        f"Current Allowed Email Subdomain: {st.session_state['allowed_email_subdomain']}"
    )
    st.write(f"Current User Auth URL: {st.session_state['user_auth_url']}")


def add_new_model():
    import streamlit as st
    import json, requests, uuid

    if (
        st.session_state.get("api_url", None) is None
        and st.session_state.get("proxy_key", None) is None
    ):
        st.warning(
            f"Please configure the Proxy Endpoint and Proxy Key on the Proxy Setup page. Currently set Proxy Endpoint: {st.session_state.get('api_url', None)} and Proxy Key: {st.session_state.get('proxy_key', None)}"
        )

    model_name = st.text_input(
        "Model Name - user-facing model name", placeholder="gpt-3.5-turbo"
    )
    st.subheader("LiteLLM Params")
    litellm_model_name = st.text_input(
        "Model", placeholder="azure/gpt-35-turbo-us-east"
    )
    litellm_api_key = st.text_input("API Key")
    litellm_api_base = st.text_input(
        "API Base",
        placeholder="https://my-endpoint.openai.azure.com",
    )
    litellm_api_version = st.text_input("API Version", placeholder="2023-07-01-preview")
    litellm_params = json.loads(
        st.text_area(
            "Additional Litellm Params (JSON dictionary). [See all possible inputs](https://github.com/BerriAI/litellm/blob/3f15d7230fe8e7492c95a752963e7fbdcaf7bf98/litellm/main.py#L293)",
            value={},
        )
    )
    st.subheader("Model Info")
    mode_options = ("completion", "embedding", "image generation")
    mode_selected = st.selectbox("Mode", mode_options)
    model_info = json.loads(
        st.text_area(
            "Additional Model Info (JSON dictionary)",
            value={},
        )
    )

    if st.button("Submit"):
        try:
            model_info = {
                "model_name": model_name,
                "litellm_params": {
                    "model": litellm_model_name,
                    "api_key": litellm_api_key,
                    "api_base": litellm_api_base,
                    "api_version": litellm_api_version,
                },
                "model_info": {
                    "id": str(uuid.uuid4()),
                    "mode": mode_selected,
                },
            }
            # Make the POST request to the specified URL
            complete_url = ""
            if st.session_state["api_url"].endswith("/"):
                complete_url = f"{st.session_state['api_url']}model/new"
            else:
                complete_url = f"{st.session_state['api_url']}/model/new"

            headers = {"Authorization": f"Bearer {st.session_state['proxy_key']}"}
            response = requests.post(complete_url, json=model_info, headers=headers)

            if response.status_code == 200:
                st.success("Model added successfully!")
            else:
                st.error(f"Failed to add model. Status code: {response.status_code}")

            st.success("Form submitted successfully!")
        except Exception as e:
            raise e


def list_models():
    import streamlit as st
    import requests

    # Check if the necessary configuration is available
    if (
        st.session_state.get("api_url", None) is not None
        and st.session_state.get("proxy_key", None) is not None
    ):
        # Make the GET request
        try:
            complete_url = ""
            if isinstance(st.session_state["api_url"], str) and st.session_state[
                "api_url"
            ].endswith("/"):
                complete_url = f"{st.session_state['api_url']}models"
            else:
                complete_url = f"{st.session_state['api_url']}/models"
            response = requests.get(
                complete_url,
                headers={"Authorization": f"Bearer {st.session_state['proxy_key']}"},
            )
            # Check if the request was successful
            if response.status_code == 200:
                models = response.json()
                st.write(models)  # or st.json(models) to pretty print the JSON
            else:
                st.error(f"Failed to get models. Status code: {response.status_code}")
        except Exception as e:
            st.error(f"An error occurred while requesting models: {e}")
    else:
        st.warning(
            f"Please configure the Proxy Endpoint and Proxy Key on the Proxy Setup page. Currently set Proxy Endpoint: {st.session_state.get('api_url', None)} and Proxy Key: {st.session_state.get('proxy_key', None)}"
        )


def spend_per_key():
    import streamlit as st
    import requests

    # Check if the necessary configuration is available
    if (
        st.session_state.get("api_url", None) is not None
        and st.session_state.get("proxy_key", None) is not None
    ):
        # Make the GET request
        try:
            complete_url = ""
            if isinstance(st.session_state["api_url"], str) and st.session_state[
                "api_url"
            ].endswith("/"):
                complete_url = f"{st.session_state['api_url']}/spend/keys"
            else:
                complete_url = f"{st.session_state['api_url']}/spend/keys"
            response = requests.get(
                complete_url,
                headers={"Authorization": f"Bearer {st.session_state['proxy_key']}"},
            )
            # Check if the request was successful
            if response.status_code == 200:
                spend_per_key = response.json()
                # Create DataFrame
                spend_df = pd.DataFrame(spend_per_key)

                # Display the spend per key as a graph
                st.header("Spend ($) per API Key:")
                top_10_df = spend_df.nlargest(10, "spend")
                fig = px.bar(
                    top_10_df,
                    x="token",
                    y="spend",
                    title="Top 10 Spend per Key",
                    height=550,  # Adjust the height
                    width=1200,  # Adjust the width)
                    hover_data=["token", "spend", "user_id", "team_id"],
                )
                st.plotly_chart(fig)

                # Display the spend per key as a table
                st.write("Spend per Key - Full Table:")
                st.table(spend_df)

            else:
                st.error(f"Failed to get models. Status code: {response.status_code}")
        except Exception as e:
            st.error(f"An error occurred while requesting models: {e}")
    else:
        st.warning(
            f"Please configure the Proxy Endpoint and Proxy Key on the Proxy Setup page. Currently set Proxy Endpoint: {st.session_state.get('api_url', None)} and Proxy Key: {st.session_state.get('proxy_key', None)}"
        )


def spend_per_user():
    import streamlit as st
    import requests

    # Check if the necessary configuration is available
    if (
        st.session_state.get("api_url", None) is not None
        and st.session_state.get("proxy_key", None) is not None
    ):
        # Make the GET request
        try:
            complete_url = ""
            if isinstance(st.session_state["api_url"], str) and st.session_state[
                "api_url"
            ].endswith("/"):
                complete_url = f"{st.session_state['api_url']}/spend/users"
            else:
                complete_url = f"{st.session_state['api_url']}/spend/users"
            response = requests.get(
                complete_url,
                headers={"Authorization": f"Bearer {st.session_state['proxy_key']}"},
            )
            # Check if the request was successful
            if response.status_code == 200:
                spend_per_user = response.json()
                # Create DataFrame
                spend_df = pd.DataFrame(spend_per_user)

                # Display the spend per key as a graph
                st.header("Spend ($) per User:")
                top_10_df = spend_df.nlargest(10, "spend")
                fig = px.bar(
                    top_10_df,
                    x="user_id",
                    y="spend",
                    title="Top 10 Spend per User",
                    height=550,  # Adjust the height
                    width=1200,  # Adjust the width)
                    hover_data=["user_id", "spend", "max_budget"],
                )
                st.plotly_chart(fig)

                # Display the spend per key as a table
                st.write("Spend per User - Full Table:")
                st.table(spend_df)

            else:
                st.error(f"Failed to get models. Status code: {response.status_code}")
        except Exception as e:
            st.error(f"An error occurred while requesting models: {e}")
    else:
        st.warning(
            f"Please configure the Proxy Endpoint and Proxy Key on the Proxy Setup page. Currently set Proxy Endpoint: {st.session_state.get('api_url', None)} and Proxy Key: {st.session_state.get('proxy_key', None)}"
        )


def create_key():
    import streamlit as st
    import json, requests, uuid

    if (
        st.session_state.get("api_url", None) is None
        and st.session_state.get("proxy_key", None) is None
    ):
        st.warning(
            f"Please configure the Proxy Endpoint and Proxy Key on the Proxy Setup page. Currently set Proxy Endpoint: {st.session_state.get('api_url', None)} and Proxy Key: {st.session_state.get('proxy_key', None)}"
        )

    duration = st.text_input("Duration - Can be in (h,m,s)", placeholder="1h")

    models = st.text_input("Models it can access (separated by comma)", value="")
    models = models.split(",") if models else []

    additional_params = json.loads(
        st.text_area(
            "Additional Key Params (JSON dictionary). [See all possible inputs](https://litellm-api.up.railway.app/#/key%20management/generate_key_fn_key_generate_post)",
            value={},
        )
    )

    if st.button("Submit"):
        try:
            key_post_body = {
                "duration": duration,
                "models": models,
                **additional_params,
            }
            # Make the POST request to the specified URL
            complete_url = ""
            if st.session_state["api_url"].endswith("/"):
                complete_url = f"{st.session_state['api_url']}key/generate"
            else:
                complete_url = f"{st.session_state['api_url']}/key/generate"

            headers = {"Authorization": f"Bearer {st.session_state['proxy_key']}"}
            response = requests.post(complete_url, json=key_post_body, headers=headers)

            if response.status_code == 200:
                st.success(f"Key added successfully! - {response.json()}")
            else:
                st.error(f"Failed to add Key. Status code: {response.status_code}")

            st.success("Form submitted successfully!")
        except Exception as e:
            raise e


def update_config():
    if (
        st.session_state.get("api_url", None) is None
        and st.session_state.get("proxy_key", None) is None
    ):
        st.warning(
            f"Please configure the Proxy Endpoint and Proxy Key on the Proxy Setup page. Currently set Proxy Endpoint: {st.session_state.get('api_url', None)} and Proxy Key: {st.session_state.get('proxy_key', None)}"
        )

    st.markdown("#### Alerting")
    input_slack_webhook = st.text_input(
        "Slack Webhook URL (Optional)",
        value=st.session_state.get("slack_webhook", ""),
        placeholder="https://hooks.slack.com/services/...",
    )
    st.markdown(
        "More information on Slack alerting configuration can be found in the [documentation]"
        "(https://docs.litellm.ai/docs/proxy/alerting)."
    )
    alerting_threshold = st.text_input(
        "Alerting threshold (in seconds) (Optional)",
        value=st.session_state.get("alerting_threshold", 300),
        placeholder=300,
    )
    st.markdown("How long to wait before a request is considered hanging")
    st.markdown("#### Logging")

    enable_langfuse_logging = st.checkbox("Enable Langfuse Logging")
    if enable_langfuse_logging == True:
        langfuse_host_url = st.text_input(
            "Langfuse Host",
            value=st.session_state.get("langfuse_host", "https://cloud.langfuse.com"),
            placeholder="https://cloud.langfuse.com",
        )
        langfuse_public_key = st.text_input(
            "Langfuse Public Key",
            value=st.session_state.get("langfuse_public_key", ""),
            placeholder="pk-lf-...",
        )
        langfuse_secret_key = st.text_input(
            "Langfuse Secret Key",
            value=st.session_state.get("langfuse_secret_key", ""),
            placeholder="sk-lf-...",
        )
    # When the "Save" button is clicked, update the session state
    if st.button("Save"):
        try:
            config_post_body = {}
            if (
                enable_langfuse_logging == True
                and langfuse_host_url is not None
                and langfuse_public_key is not None
                and langfuse_secret_key is not None
            ):
                config_post_body["litellm_settings"] = {
                    "success_callback": ["langfuse"]
                }
                config_post_body["environment_variables"] = {
                    "LANGFUSE_HOST": langfuse_host_url,
                    "LANGFUSE_PUBLIC_KEY": langfuse_public_key,
                    "LANGFUSE_SECRET_KEY": langfuse_secret_key,
                }
            if input_slack_webhook is not None and alerting_threshold is not None:
                config_post_body["general_settings"] = {
                    "alerting": ["slack"],
                    "alerting_threshold": alerting_threshold,
                }
                config_post_body["environment_variables"] = {
                    "SLACK_WEBHOOK_URL": input_slack_webhook
                }

            # Make the POST request to the specified URL
            complete_url = ""
            if st.session_state["api_url"].endswith("/"):
                complete_url = f"{st.session_state.get('api_url')}config/update"
            else:
                complete_url = f"{st.session_state.get('api_url')}/config/update"

            headers = {"Authorization": f"Bearer {st.session_state['proxy_key']}"}
            response = requests.post(
                complete_url, json=config_post_body, headers=headers
            )

            if response.status_code == 200:
                st.success(f"Config updated successfully! - {response.json()}")
            else:
                st.error(
                    f"Failed to update config. Status code: {response.status_code}. Error message: {response.json()['detail']}"
                )

            st.success("Form submitted successfully!")
        except Exception as e:
            raise e


def admin_page(is_admin="NOT_GIVEN", input_api_url=None, input_proxy_key=None):
    # Display the form for the admin to set the proxy URL and allowed email subdomain
    st.set_page_config(
        layout="wide",  # Use "wide" layout for more space
    )
    st.header("Admin Configuration")
    st.session_state.setdefault("is_admin", is_admin)
    # Add a navigation sidebar
    st.sidebar.title("Navigation")

    page = st.sidebar.radio(
        "Go to",
        (
            "Connect to Proxy",
            "View Spend Per Key",
            "View Spend Per User",
            "List Models",
            "Update Config",
            "Add Models",
            "Create Key",
            "End-User Auth",
        ),
    )
    # Display different pages based on navigation selection
    if page == "Connect to Proxy":
        # Use text inputs with intermediary variables
        if input_api_url is None:
            input_api_url = st.text_input(
                "Proxy Endpoint",
                value=st.session_state.get("api_url", ""),
                placeholder="http://0.0.0.0:8000",
            )
        else:
            st.session_state["api_url"] = input_api_url

        if input_proxy_key is None:
            input_proxy_key = st.text_input(
                "Proxy Key",
                value=st.session_state.get("proxy_key", ""),
                placeholder="sk-...",
            )
        else:
            st.session_state["proxy_key"] = input_proxy_key
        # When the "Save" button is clicked, update the session state
        if st.button("Save"):
            st.session_state["api_url"] = input_api_url
            st.session_state["proxy_key"] = input_proxy_key
            st.success("Configuration saved!")
    elif page == "Update Config":
        update_config()
    elif page == "End-User Auth":
        proxy_setup()
    elif page == "Add Models":
        add_new_model()
    elif page == "List Models":
        list_models()
    elif page == "Create Key":
        create_key()
    elif page == "View Spend Per Key":
        spend_per_key()
    elif page == "View Spend Per User":
        spend_per_user()


# admin_page()


@click.command()
@click.option("--proxy_endpoint", type=str, help="Proxy Endpoint")
@click.option("--proxy_master_key", type=str, help="Proxy Master Key")
def main(proxy_endpoint, proxy_master_key):
    admin_page(input_api_url=proxy_endpoint, input_proxy_key=proxy_master_key)


if __name__ == "__main__":
    main()
