"""Jam verhandelt Verkaufspreise – mit David, Käufern und beim nächsten Produkt."""

from __future__ import annotations

import random
import re
import time
from pathlib import Path

from jam.brain import JamBrain, JamState
from jam.owner import owner_name
from jam.paypal_donate import paypal_donate_url

COUNTER_LINES = (
    "{owner}, **{old} €** war fair – ich kann auf **{new} €** gehen. Deal?",
    "Verhandlung: von {old} auf **{new} €** – Jam gibt nach, aber nicht umsonst!",
    "Okay {owner} – **{new} €** für {title}. PayPal-Link ist aktualisiert!",
    "Jam-Händler: {old} € → **{new} €**. So verkauft sich's schneller!",
)

HOLD_LINES = (
    "{owner}, bei **{price} €** bleibe ich – das ist schon Jam-Fair-Preis!",
    "Nicht tiefer als **{price} €** – sonst lohnt sich die Arbeit nicht!",
)

UP_LINES = (
    "Premium-Verhandlung: jetzt **{new} €** – mehr Qualität, mehr Wert!",
    "{owner}, **{new} €** – wer Qualität will, zahlt fair!",
)


def hears_price_negotiate(text: str) -> bool:
    h = text.lower().replace("jam", " ")
    if any(
        w in h
        for w in (
            "verhandl",
            "verhandle",
            "handel den preis",
            "preis handeln",
            "rabatt",
            "nachlass",
            "runter mit dem preis",
            "preis runter",
            "günstiger",
            "billiger",
            "teurer",
            "preis hoch",
            "preis senken",
        )
    ):
        return True
    if "preis" in h and any(w in h for w in ("verhandl", "rabatt", "günstig", "billig", "teuer", "euro", "€")):
        return True
    return False


def _parse_euro_amount(text: str) -> float | None:
    h = text.lower().replace(",", ".")
    m = re.search(r"(\d+(?:\.\d{1,2})?)\s*(?:€|eur|euro)", h)
    if m:
        return float(m.group(1))
    m = re.search(r"(?:für|auf|nur|preis)\s*(\d+(?:\.\d{1,2})?)", h)
    if m:
        return float(m.group(1))
    m = re.search(r"\b(\d+(?:\.\d{1,2})?)\b", h)
    if m and any(w in h for w in ("euro", "eur", "€", "preis", "nur", "für", "auf")):
        return float(m.group(1))
    return None


def _parse_percent(text: str) -> float | None:
    m = re.search(r"(\d+)\s*(?:%|prozent)", text.lower())
    if m:
        return min(0.5, int(m.group(1)) / 100.0)
    return None


def _parse_direction(text: str) -> str:
    h = text.lower()
    if any(w in h for w in ("teurer", "teuerer", "hoch", "mehr", "erhöh", "premium")):
        return "up"
    if any(
        w in h
        for w in (
            "günstiger",
            "billiger",
            "runter",
            "senk",
            "rabatt",
            "nachlass",
            "runter",
            "weniger",
        )
    ):
        return "down"
    if _parse_euro_amount(text) is not None:
        return "offer"
    return "negotiate"


def _template_range(state: JamState, entry: dict) -> tuple[float, float, bool]:
    from jam.sales_engine import CENT_TEMPLATE_IDS, TEMPLATES

    tid = entry.get("template", "")
    info = TEMPLATES.get(tid) if tid else None
    if info:
        lo, hi = info.get("range", (5, 50))
        cent = bool(info.get("cent")) or tid in CENT_TEMPLATE_IDS
        return float(lo), float(hi), cent
    price = float(entry.get("price", 9))
    if price <= 6:
        return 0.49, 5.99, True
    return max(1.0, price * 0.5), min(199.0, price * 1.4), False


def jam_compute_negotiated_price(
    state: JamState,
    current: float,
    heard: str,
    *,
    lo: float,
    hi: float,
    cent: bool,
    title: str,
) -> tuple[float, str]:
    """Neuer Preis + Begründung nach Verhandlung."""
    from jam.sales_engine import _snap_price
    from jam.upbringing import ensure_traits

    ensure_traits(state)
    t = state.traits
    frech = float(t.get("frech", 0.35))
    hilfs = float(t.get("hilfsbereit", 0.5))
    owner = owner_name(state)
    direction = _parse_direction(heard)
    target = _parse_euro_amount(heard)
    pct = _parse_percent(heard)

    if target is not None:
        proposed = target
    elif pct and direction != "up":
        proposed = current * (1.0 - pct)
    elif direction == "down":
        drop = 0.12 + hilfs * 0.12 - frech * 0.06
        proposed = current * (1.0 - drop)
    elif direction == "up":
        rise = 0.1 + frech * 0.12
        proposed = current * (1.0 + rise)
    else:
        proposed = current * (0.9 if hilfs >= frech else 0.94)

    floor = lo
    if frech > 0.55 and direction in ("down", "negotiate", "offer"):
        floor = max(lo, current * (0.82 if cent else 0.78))
    if target is not None and target < floor and frech > 0.45:
        proposed = max(floor, target)
    else:
        proposed = max(floor, min(hi * 1.05, proposed))

    new_price = _snap_price(proposed, lo, hi, cent=cent)
    if new_price == current:
        if direction == "down" or (target is not None and target < current):
            new_price = _snap_price(current * 0.88, lo, hi, cent=cent)
        elif direction == "up":
            new_price = _snap_price(current * 1.08, lo, hi, cent=cent)

    if new_price < current:
        reason = (
            f"Verhandelt mit {owner}: {current} → {new_price} EUR – "
            f"Jam gibt Rabatt damit jemand kauft!"
        )
    elif new_price > current:
        reason = f"Premium-Verhandlung: {new_price} EUR – mehr Wert für {title}."
    else:
        reason = f"Jam bleibt bei {new_price} EUR – fairer Mindestpreis."

    return new_price, reason


def apply_price_to_product(
    brain: JamBrain,
    entry: dict,
    new_price: float,
    reason: str,
    *,
    repush: bool = True,
) -> str:
    """Shop, Listings und Log auf neuen Preis setzen."""
    from jam.sales_engine import _shop_html, _write_listings

    state = brain.state
    owner = owner_name(state)
    project = Path(entry.get("path", ""))
    title = entry.get("title", "Produkt")
    old = float(entry.get("price", new_price))
    new_price = float(new_price)

    if not project.is_dir():
        return f"{owner}, Projekt-Ordner fehlt – erst neues Produkt verkaufen!"

    paypal_url = paypal_donate_url()
    try:
        from jam.active_sell import paypal_buy_url

        paypal_url = paypal_buy_url(new_price, title)
    except Exception:
        pass

    price_out = int(new_price) if new_price >= 10 and new_price == int(new_price) else new_price
    (project / "index.html").write_text(
        _shop_html(title, owner, price_out, reason, paypal_url),
        encoding="utf-8",
    )
    _write_listings(project, title, owner, price_out, reason)
    (project / "VERHANDLUNG.txt").write_text(
        f"# Preisverhandlung – {title}\n\n"
        f"- **Alt:** {old:.2f} EUR\n"
        f"- **Neu:** {new_price:.2f} EUR\n"
        f"- **Jam:** {reason}\n"
        f"- **Verhandelbar:** Ja – Jam kann weiter handeln (Sprache: „Jam, verhandel den Preis“)\n",
        encoding="utf-8",
    )

    entry["price"] = new_price
    entry["reason"] = reason
    entry["negotiated"] = True
    entry["negotiate_from"] = old
    entry["negotiated_at"] = time.time()

    log = list(getattr(state, "jam_sales_log", []) or [])
    if log and log[-1] is entry:
        log[-1] = entry
    else:
        for i, e in enumerate(log):
            if isinstance(e, dict) and e.get("path") == entry.get("path"):
                log[i] = entry
                break
    state.jam_sales_log = log
    state.last_jam_sale_price = new_price
    hist = list(getattr(state, "jam_price_history", []) or [])
    hist.append(new_price)
    state.jam_price_history = hist[-20:]
    state.jam_negotiate_count = getattr(state, "jam_negotiate_count", 0) + 1
    state.last_negotiate_at = time.time()
    state.jam_next_price_target = 0.0
    state.remember(f"Preis verhandelt: {title} {old}→{new_price}€")
    brain.add_xp(8)
    brain.save()

    push_bit = ""
    if repush:
        try:
            from jam.active_sell import push_product_sale

            push_bit = push_product_sale(
                brain, project, title, new_price, user_initiated=True
            )
        except Exception:
            pass

    if new_price < old:
        line = random.choice(COUNTER_LINES).format(
            owner=owner, old=old, new=new_price, title=title
        )
    elif new_price > old:
        line = random.choice(UP_LINES).format(owner=owner, new=new_price, title=title)
    else:
        line = random.choice(HOLD_LINES).format(owner=owner, price=new_price)

    if push_bit:
        line += " " + push_bit[:100]
    return line


def negotiate_last_product(brain: JamBrain, heard: str) -> str:
    """Letztes Produkt: Preis mit David verhandeln."""
    state = brain.state
    owner = owner_name(state)
    log = getattr(state, "jam_sales_log", []) or []
    if not log or not isinstance(log[-1], dict):
        from jam.sales_engine import run_sale_project

        msg = run_sale_project(brain, user_initiated=True)
        return f"{owner}, erst Produkt – dann verhandeln wir! {msg}"[:400]

    entry = log[-1]
    current = float(entry.get("price", 9))
    lo, hi, cent = _template_range(state, entry)
    new_price, reason = jam_compute_negotiated_price(
        state,
        current,
        heard,
        lo=lo,
        hi=hi,
        cent=cent,
        title=entry.get("title", "Produkt"),
    )

    if abs(new_price - current) < 0.001:
        return random.choice(HOLD_LINES).format(owner=owner, price=current) + (
            " Sag „günstiger“ oder „5 Euro“ – dann handele ich!"
        )

    return apply_price_to_product(brain, entry, new_price, reason, repush=True)


def negotiate_for_next_sale(brain: JamBrain, heard: str) -> None:
    """Zielpreis für das nächste automatische Produkt merken."""
    state = brain.state
    target = _parse_euro_amount(heard)
    if target and target > 0:
        state.jam_next_price_target = float(target)
        brain.save()


def handle_speech(brain: JamBrain, heard: str) -> str | None:
    if not hears_price_negotiate(heard):
        return None
    negotiate_for_next_sale(brain, heard)
    if any(w in heard.lower() for w in ("nächst", "naechst", "später", "spaeter", "beim nächsten")):
        t = getattr(brain.state, "jam_next_price_target", 0)
        if t:
            return (
                f"{owner_name(brain.state)}, beim nächsten Verkauf strebe ich **{t:.2f} €** an – verhandelt!"
            )
    return negotiate_last_product(brain, heard)


def negotiation_hint_for_decide(state: JamState) -> float | None:
    t = float(getattr(state, "jam_next_price_target", 0) or 0)
    return t if t > 0 else None
