"""OpenAI prompt management helpers (ported from CrystalliseAppsToolbox prompts.py).

All Streamlit / session_state dependencies have been removed.
"""
from __future__ import annotations

import json
import os
from typing import Any, Dict, Optional, Tuple

import pandas as pd
from openai import OpenAI


# ---------------------------------------------------------------------------
# Fetch prompt details from the API (with CSV fallback)
# ---------------------------------------------------------------------------

def fetch_prompt_details(
    client: OpenAI,
    prompt_id: str,
    prompt_version: Optional[str] = None,
    prompts_df: Optional[pd.DataFrame] = None,
) -> Dict[str, Any]:
    """Retrieve prompt metadata from the OpenAI API.

    Falls back to *prompts_df* (a local CSV/JSON DataFrame) when the API
    call fails.
    """
    out: Dict[str, Any] = {
        "id": prompt_id,
        "version": prompt_version,
        "name": None,
        "description": None,
        "system_message": None,
        "variables": {},
        "tools": [],
        "model_config": {},
        "schema": None,
        "source": "fallback",
    }

    # --- Try the API first ------------------------------------------------
    try:
        if prompt_version:
            p = client.prompts.versions.retrieve(
                prompt_id=prompt_id, version=prompt_version,
            )
        else:
            p = client.prompts.retrieve(prompt_id)

        out["source"] = "api"
        out["name"] = getattr(p, "name", None) or getattr(p, "display_name", None)
        out["description"] = getattr(p, "description", None)

        # System message extraction
        try:
            msgs = getattr(p, "messages", None) or getattr(p, "content", None) or []
            sys_text = None
            for m in msgs:
                role = (
                    getattr(m, "role", None)
                    if hasattr(m, "role")
                    else (m.get("role") if isinstance(m, dict) else None)
                )
                if role == "system":
                    content = (
                        getattr(m, "content", None)
                        if hasattr(m, "content")
                        else m.get("content")
                    )
                    if isinstance(content, list):
                        for part in content:
                            if isinstance(part, dict) and part.get("type") == "input_text":
                                sys_text = part.get("text")
                                break
                    elif isinstance(content, str):
                        sys_text = content
                    break
            out["system_message"] = sys_text
        except Exception:
            pass

        # Variables
        try:
            vars_obj = getattr(p, "variables", None) or {}
            if isinstance(vars_obj, dict):
                out["variables"] = vars_obj
        except Exception:
            pass

        # Tools
        try:
            tools = getattr(p, "tools", None) or []
            out["tools"] = list(tools)
        except Exception:
            pass

        # Model config
        for key in ("defaults", "model_config"):
            try:
                cfg = getattr(p, key, None) or {}
                if isinstance(cfg, dict):
                    out["model_config"] = cfg
                    break
            except Exception:
                continue

        # JSON schema
        try:
            fmt = getattr(p, "text", None) and getattr(p.text, "format", None)
            schema = getattr(fmt, "schema_", None)
            if isinstance(schema, dict):
                out["schema"] = schema
        except Exception:
            pass

        return out

    except Exception:
        pass

    # --- Fallback: local CSV/JSON DataFrame --------------------------------
    try:
        if prompts_df is not None and hasattr(prompts_df, "empty") and not prompts_df.empty:
            row = prompts_df[prompts_df["PromptID"] == prompt_id]
            if not row.empty:
                r = row.iloc[0].to_dict()
                out["name"] = r.get("Prompt Name") or r.get("Prompt_Name")
                out["description"] = r.get("Project")
                out["system_message"] = r.get("SystemMessage")
                out["source"] = "csv"
    except Exception:
        pass

    return out


# ---------------------------------------------------------------------------
# Local prompt file loaders
# ---------------------------------------------------------------------------

def _find_prompts_csv() -> Optional[str]:
    candidates = [
        os.path.join(".config", "prompts.csv"),
        os.path.join("config", "prompts.csv"),
    ]
    for p in candidates:
        if os.path.exists(p):
            return p
    return None


def load_prompts_csv() -> pd.DataFrame:
    """Load prompts from the first ``prompts.csv`` found on disk."""
    path = _find_prompts_csv()
    if not path:
        return pd.DataFrame()
    try:
        return pd.read_csv(path)
    except Exception:
        return pd.DataFrame()


def _find_prompts_json() -> Optional[str]:
    candidates = [
        os.path.join(".config", "prompts.json"),
        os.path.join("config", "prompts.json"),
    ]
    for p in candidates:
        if os.path.exists(p):
            return p
    return None


def load_prompts_json() -> pd.DataFrame:
    """Load prompts from the first ``prompts.json`` found on disk."""
    path = _find_prompts_json()
    if not path:
        return pd.DataFrame()
    try:
        with open(path, "r", encoding="utf-8") as f:
            data = json.load(f)
        if not isinstance(data, list):
            return pd.DataFrame()
        return pd.DataFrame(data)
    except Exception:
        return pd.DataFrame()


def load_prompts() -> pd.DataFrame:
    """Unified loader: tries CSV first, then JSON."""
    df = load_prompts_csv()
    if df is not None and not df.empty:
        return df
    return load_prompts_json()


# ---------------------------------------------------------------------------
# Prompt DataFrame helpers
# ---------------------------------------------------------------------------

def filter_prompts_for_tool(df: Optional[pd.DataFrame], tool_name: str) -> pd.DataFrame:
    """Return rows from *df* whose ``Tool`` column matches *tool_name*."""
    if df is None or df.empty:
        return pd.DataFrame()
    col = None
    for c in df.columns:
        if c.strip().lower() == "tool":
            col = c
            break
    if not col:
        return pd.DataFrame()
    return df[
        df[col].astype(str).str.strip().str.lower() == tool_name.strip().lower()
    ].copy()


def extract_prompt_fields(
    row: Dict[str, Any],
) -> Tuple[
    Optional[str],  # api_id
    Optional[str],  # version
    Optional[str],  # title
    Optional[str],  # description
    Optional[str],  # prompt_message
    Optional[str],  # system_message
    Optional[str],  # json_schema
    Optional[str],  # flatten_fn
    Optional[int],  # max_output_tokens
]:
    """Extract standard prompt fields from a row dict.

    Returns a 9-tuple of
    ``(api_id, version, title, desc, prompt_msg, sys_msg, json_schema, flatten_fn, max_out)``.
    """
    # api_id
    api_id = None
    if "api_id" in row:
        api_id = str(row.get("api_id"))
    elif "PromptID.1" in row:
        api_id = str(row.get("PromptID.1"))
    elif "PromptID" in row:
        api_id = str(row.get("PromptID"))

    # version
    version = None
    for key in ("version", "PromptVersion"):
        if key in row:
            version = str(row.get(key))
            break

    # title
    title = None
    for key in ("title", "PromptTitle"):
        if key in row:
            title = str(row.get(key))
            break

    # description
    desc = None
    for key in ("description", "PromptDescription"):
        if key in row:
            desc = str(row.get(key))
            break

    # prompt_message
    prompt_msg = None
    for key in ("prompt_message", "PromptMessage"):
        if key in row:
            prompt_msg = str(row.get(key))
            break

    # system_message
    sys_msg = None
    for key in ("system_message", "SystemMessage"):
        if key in row:
            sys_msg = str(row.get(key))
            break

    # json_schema
    json_schema = None
    for key in ("json_schema", "JSONschema"):
        if key in row:
            json_schema = str(row.get(key))
            break

    # flattening function
    flatten_fn = None
    for key in ("Flattening_Function", "flattening_function", "FlatteningFunction"):
        if key in row:
            flatten_fn = str(row.get(key))
            break

    # max output tokens
    max_out = None
    for key in ("max_output_tokens", "MaxOutputTokens", "max_tokens", "MaxTokens"):
        if key in row and pd.notna(row.get(key)):
            try:
                max_out = int(float(row.get(key)))
            except Exception:
                max_out = None
            break

    return api_id, version, title, desc, prompt_msg, sys_msg, json_schema, flatten_fn, max_out
