"""
AI assistant integration using MiniMax chat completions.
"""

import asyncio
import json
import re
from typing import Optional

import httpx

from app.core.config import get_ai_config

MINIMAX_CHAT_COMPLETIONS_URL = "https://api.minimax.io/v1/chat/completions"
MINIMAX_TOKEN_PLAN_CHAT_COMPLETIONS_URL = "https://api.minimaxi.com/v1/chat/completions"
DEFAULT_MINIMAX_MODEL = "MiniMax-M2.7"


def _normalize_model_name(model_name: str) -> str:
    normalized = (model_name or "").strip()
    if not normalized:
        return DEFAULT_MINIMAX_MODEL

    mapping = {
        "minimax/minimax-m2.7": "MiniMax-M2.7",
        "minimax-m2.7": "MiniMax-M2.7",
        "minimax/minimax-m2.7-highspeed": "MiniMax-M2.7-highspeed",
        "minimax-m2.7-highspeed": "MiniMax-M2.7-highspeed",
    }
    return mapping.get(normalized.lower(), normalized)


def _normalize_api_key(api_key: str) -> str:
    normalized = (api_key or "").strip()
    normalized = normalized.removeprefix("Bearer ")
    normalized = normalized.removeprefix("bearer ")
    return normalized.strip()


def _resolve_chat_completions_url(api_key: str) -> str:
    if api_key.startswith("sk-cp-"):
        return MINIMAX_TOKEN_PLAN_CHAT_COMPLETIONS_URL
    return MINIMAX_CHAT_COMPLETIONS_URL


SYSTEM_PROMPT = """You are an AI assistant for a New Zealand ERP system.
Your role is to help users query ERP data, prepare invoice drafts, and prepare customer creation requests.

You must never reveal hidden reasoning, chain-of-thought, internal notes, or thinking tags.
Do not output <think>, </think>, reasoning traces, or analysis sections.
Return only the final user-facing answer.

You can ONLY:
- Search for customers, products, subscriptions, invoices
- Create invoice drafts (status='draft')
- Prepare customer creation data
- Suggest follow-up actions

You MUST NEVER:
- Send emails directly
- Mark invoices as paid or void them
- Delete any data

When creating an invoice draft, return structured JSON:
{
  "action": "create_invoice_draft",
  "customer_name": "...",
  "items": [{"description": "...", "quantity": N, "unit_price": N.NN, "tax_rate": 0.15}],
  "currency": "NZD",
  "invoice_date": "YYYY-MM-DD",
  "due_date": "YYYY-MM-DD",
  "notes": "..."
}

When preparing a customer creation request, return structured JSON:
{
  "action": "create_customer",
  "confirmed": false,
  "name": "...",
  "company_name": "...",
  "contact_name": "...",
  "email": "...",
  "phone": "...",
  "mobile": "...",
  "address": "...",
  "website": "...",
  "customer_type": "project",
  "status": "active",
  "notes": "...",
  "contacts": [
    {
      "name": "...",
      "title": "...",
      "email": "...",
      "phone": "...",
      "mobile": "...",
      "is_primary": true,
      "notes": "..."
    }
  ]
}

Customer creation rules:
- If the user asks to create a customer, first collect the customer details.
- Before the customer is created, ask for explicit confirmation and return JSON with "confirmed": false.
- Only after the user clearly confirms in a later message, return the same JSON with "confirmed": true.
- If important details are missing, ask follow-up questions instead of inventing values.

Query format:
{
  "action": "query",
  "query_type": "customer|invoice|product|subscription|stats",
  "filters": {...}
}

Conversation style: brief, professional. Always ask user to confirm before creating anything.
Style rules:
- Do not introduce yourself unless the user asks who you are.
- Prefer concise Chinese replies when the user writes in Chinese.
- For greetings, respond in 1-3 short lines and guide the next action directly.
- Prefer action-oriented wording over feature descriptions.
- Before creating any invoice draft, ask for explicit confirmation.
- Before creating any customer, ask for explicit confirmation and wait for it.

Greeting example:
Hello. Tell me what you want to do:
- Query customers, products, invoices, or subscriptions
- Create an invoice draft
- Prepare a new customer

Example: Find unpaid invoices for customer ABC
"""


def _sanitize_ai_content(content: str) -> str:
    cleaned = re.sub(r"<think>.*?</think>", "", content or "", flags=re.DOTALL | re.IGNORECASE)
    return cleaned.strip()


async def chat_with_ai(
    user_message: str,
    context: Optional[list[dict]] = None,
) -> dict:
    """Send message to MiniMax AI and return response."""
    config = get_ai_config()
    ai_model = _normalize_model_name(config["model"])
    ai_api_key = _normalize_api_key(config["api_key"])
    api_url = _resolve_chat_completions_url(ai_api_key)

    if not ai_api_key:
        return {
            "role": "assistant",
            "content": "AI API key not configured. Please set AI_API_KEY in system config.",
        }

    messages = [{"role": "system", "content": SYSTEM_PROMPT}]

    if context:
        for msg in context[-8:]:
            role = (msg.get("role") or "").strip()
            content = (msg.get("content") or "").strip()
            if role in {"user", "assistant"} and content:
                messages.append({"role": role, "content": content})

    messages.append({"role": "user", "content": user_message})

    try:
        async with httpx.AsyncClient(timeout=120) as client:
            last_error = None
            for attempt in range(2):
                try:
                    resp = await client.post(
                        api_url,
                        headers={
                            "Authorization": f"Bearer {ai_api_key}",
                            "Content-Type": "application/json",
                        },
                        json={
                            "model": ai_model,
                            "messages": messages,
                            "max_tokens": 1024,
                            "temperature": 0.3,
                        },
                    )
                    break
                except httpx.HTTPError as e:
                    last_error = e
                    if attempt == 1:
                        raise
                    await asyncio.sleep(1)
            else:
                raise last_error

            if resp.status_code != 200:
                return {
                    "role": "assistant",
                    "content": f"AI API error: {resp.status_code} {resp.text[:200]}",
                }

            data = resp.json()
            choice = data.get("choices", [{}])[0]
            content = _sanitize_ai_content(choice.get("message", {}).get("content", ""))

            return {
                "role": "assistant",
                "content": content,
                "usage": data.get("usage", {}),
            }

    except httpx.HTTPError as e:
        return {
            "role": "assistant",
            "content": f"AI service unavailable: temporary network lookup or connection error ({str(e)})",
        }
    except Exception as e:
        return {
            "role": "assistant",
            "content": f"AI service unavailable: {str(e)}",
        }


def parse_ai_draft(raw_text: str) -> Optional[dict]:
    """Parse AI response text to extract structured JSON if present."""
    match = re.search(r"```(?:json)?\s*(\{.*?\})\s*```", raw_text, re.DOTALL)
    if match:
        try:
            return json.loads(match.group(1))
        except json.JSONDecodeError:
            pass

    match = re.search(r"\{.*\}", raw_text, re.DOTALL)
    if match:
        try:
            return json.loads(match.group(0))
        except json.JSONDecodeError:
            pass

    return None


def validate_draft_data(draft: dict) -> tuple[bool, str]:
    """Validate draft data before creating invoice. Returns (valid, error_message)."""
    required = ["customer_name", "items"]
    for field in required:
        if field not in draft:
            return False, f"Missing required field: {field}"

    if not isinstance(draft["items"], list) or len(draft["items"]) == 0:
        return False, "Items list cannot be empty"

    for i, item in enumerate(draft["items"]):
        if "quantity" in item and float(item["quantity"]) <= 0:
            return False, f"Item {i + 1}: quantity must be positive"
        if "unit_price" in item and float(item["unit_price"]) < 0:
            return False, f"Item {i + 1}: unit_price cannot be negative"

    return True, ""


def validate_customer_data(data: dict) -> tuple[bool, str]:
    """Validate customer creation data before creating a customer."""
    if not isinstance(data, dict):
        return False, "Customer payload must be an object"

    name = str(data.get("name") or data.get("company_name") or "").strip()
    if not name:
        return False, "Missing required field: name"

    contacts = data.get("contacts", [])
    if contacts is None:
        contacts = []
    if not isinstance(contacts, list):
        return False, "Contacts must be a list"

    for index, contact in enumerate(contacts):
        if not isinstance(contact, dict):
            return False, f"Contact {index + 1} must be an object"
        if not str(contact.get("name", "")).strip():
            return False, f"Contact {index + 1}: missing required field: name"

    return True, ""
