"""
Market — TAM/SAM/SOM sizing, competitive benchmarking, and success probability model.
"""

from __future__ import annotations

from dataclasses import dataclass
from typing import Any

import numpy as np
import pandas as pd

from bizanalyticsai.core.dataframe import BizFrame


# ── Market sizing ─────────────────────────────────────────────────────────────

@dataclass
class MarketSize:
    tam:           float    # Total Addressable Market
    sam:           float    # Serviceable Addressable Market
    som:           float    # Serviceable Obtainable Market
    sam_pct:       float    # % of TAM
    som_pct_sam:   float    # % of SAM
    currency:      str = "BRL"

    def summary(self) -> str:
        return (
            f"TAM: {self.currency} {self.tam:,.0f}\n"
            f"SAM: {self.currency} {self.sam:,.0f} ({self.sam_pct:.1f}% of TAM)\n"
            f"SOM: {self.currency} {self.som:,.0f} ({self.som_pct_sam:.1f}% of SAM)"
        )


def tam_sam_som(
    tam: float,
    sam_pct: float,
    som_pct: float,
    currency: str = "BRL",
) -> MarketSize:
    """
    Compute TAM, SAM, SOM from percentages.

    Args:
        tam:      Total addressable market (absolute value).
        sam_pct:  SAM as % of TAM (0–100).
        som_pct:  SOM as % of SAM (0–100).
        currency: Currency label.

    Returns:
        MarketSize dataclass.
    """
    sam = tam * (sam_pct / 100)
    som = sam * (som_pct / 100)
    return MarketSize(
        tam=round(tam, 2),
        sam=round(sam, 2),
        som=round(som, 2),
        sam_pct=sam_pct,
        som_pct_sam=som_pct,
        currency=currency,
    )


# ── Industry benchmarks ───────────────────────────────────────────────────────

BENCHMARKS: dict[str, dict] = {
    "Tecnologia / SaaS": {
        "avg_churn_monthly": 3.2, "top_churn_monthly": 1.0,
        "avg_ltv_cac": 3.5, "top_ltv_cac": 5.0,
        "avg_payback_months": 14, "avg_growth_monthly": 8,
        "avg_gross_margin": 72, "success_rate_5y": 22,
        "avg_cac": 400, "avg_arpu": 250,
        "notes": "B2B SaaS tem churn menor que B2C. LTV/CAC ≥ 3 é padrão investível.",
    },
    "E-commerce": {
        "avg_churn_monthly": 6.5, "top_churn_monthly": 2.8,
        "avg_ltv_cac": 2.2, "top_ltv_cac": 3.8,
        "avg_payback_months": 8, "avg_growth_monthly": 12,
        "avg_gross_margin": 38, "success_rate_5y": 18,
        "avg_cac": 45, "avg_arpu": 180,
        "notes": "Margem baixa exige alto volume. Frete e logística são gargalos.",
    },
    "Alimentação": {
        "avg_churn_monthly": 8.0, "top_churn_monthly": 3.5,
        "avg_ltv_cac": 1.8, "top_ltv_cac": 3.0,
        "avg_payback_months": 6, "avg_growth_monthly": 7,
        "avg_gross_margin": 42, "success_rate_5y": 15,
        "avg_cac": 30, "avg_arpu": 120,
        "notes": "Alta concorrência local. Diferenciação por nicho é essencial.",
    },
    "Saúde": {
        "avg_churn_monthly": 2.5, "top_churn_monthly": 0.8,
        "avg_ltv_cac": 4.2, "top_ltv_cac": 6.5,
        "avg_payback_months": 18, "avg_growth_monthly": 9,
        "avg_gross_margin": 55, "success_rate_5y": 28,
        "avg_cac": 350, "avg_arpu": 300,
        "notes": "Ciclo de venda longo, mas retenção alta. Regulação é barreira.",
    },
    "Educação": {
        "avg_churn_monthly": 4.8, "top_churn_monthly": 1.8,
        "avg_ltv_cac": 2.8, "top_ltv_cac": 4.5,
        "avg_payback_months": 12, "avg_growth_monthly": 10,
        "avg_gross_margin": 60, "success_rate_5y": 20,
        "avg_cac": 180, "avg_arpu": 200,
        "notes": "EdTech cresce 15%/ano globalmente. Engajamento é o maior desafio.",
    },
    "Varejo": {
        "avg_churn_monthly": 7.0, "top_churn_monthly": 3.0,
        "avg_ltv_cac": 2.0, "top_ltv_cac": 3.2,
        "avg_payback_months": 7, "avg_growth_monthly": 6,
        "avg_gross_margin": 35, "success_rate_5y": 14,
        "avg_cac": 40, "avg_arpu": 150,
        "notes": "Omnichannel é essencial. Margem pressionada por marketplaces.",
    },
    "Serviços": {
        "avg_churn_monthly": 4.0, "top_churn_monthly": 1.5,
        "avg_ltv_cac": 3.0, "top_ltv_cac": 5.0,
        "avg_payback_months": 10, "avg_growth_monthly": 7,
        "avg_gross_margin": 50, "success_rate_5y": 24,
        "avg_cac": 200, "avg_arpu": 350,
        "notes": "Escalabilidade limitada pelo capital humano.",
    },
    "Indústria": {
        "avg_churn_monthly": 1.8, "top_churn_monthly": 0.5,
        "avg_ltv_cac": 4.5, "top_ltv_cac": 7.0,
        "avg_payback_months": 24, "avg_growth_monthly": 4,
        "avg_gross_margin": 30, "success_rate_5y": 32,
        "avg_cac": 1500, "avg_arpu": 2000,
        "notes": "Alto CAPEX inicial. Clientes fiéis por anos quando conquistados.",
    },
    "Outro": {
        "avg_churn_monthly": 5.0, "top_churn_monthly": 2.0,
        "avg_ltv_cac": 2.5, "top_ltv_cac": 4.0,
        "avg_payback_months": 12, "avg_growth_monthly": 8,
        "avg_gross_margin": 45, "success_rate_5y": 20,
        "avg_cac": 200, "avg_arpu": 200,
        "notes": "Dados médios do mercado geral brasileiro.",
    },
}


def get_benchmark(segment: str) -> dict:
    """Return industry benchmark for a given segment."""
    return BENCHMARKS.get(segment, BENCHMARKS["Outro"])


def benchmark_compare(
    segment: str,
    your_metrics: dict[str, float],
) -> BizFrame:
    """
    Compare your metrics against industry benchmarks.

    Args:
        segment:      Industry segment key (from BENCHMARKS).
        your_metrics: Dict of metric_name → value. Accepted keys:
                      avg_churn_monthly, avg_ltv_cac, avg_payback_months,
                      avg_gross_margin, avg_cac, avg_arpu.

    Returns:
        BizFrame with metric, your_value, industry_avg, top_quartile, status columns.
    """
    bm = get_benchmark(segment)
    higher_better = {
        "avg_ltv_cac", "avg_gross_margin", "avg_arpu", "success_rate_5y",
    }
    lower_better = {
        "avg_churn_monthly", "avg_payback_months", "avg_cac",
    }

    rows = []
    for metric, your_val in your_metrics.items():
        avg_key = metric
        top_key = metric.replace("avg_", "top_") if "avg_churn" in metric or "avg_ltv" in metric else None
        avg = bm.get(avg_key)
        top = bm.get(top_key) if top_key else None

        if avg is None:
            continue

        if metric in higher_better:
            status = "✅ Above avg" if your_val >= avg else ("⚠ Below avg" if your_val >= avg * 0.7 else "❌ Critical")
        elif metric in lower_better:
            status = "✅ Above avg" if your_val <= avg else ("⚠ Below avg" if your_val <= avg * 1.3 else "❌ Critical")
        else:
            status = "—"

        rows.append({
            "metric":       metric,
            "your_value":   your_val,
            "industry_avg": avg,
            "top_quartile": top,
            "status":       status,
        })

    return BizFrame(rows)


# ── Success probability model ─────────────────────────────────────────────────

def success_probability(
    segment:           str    = "Outro",
    margin_pct:        float  = 0,
    payback_months:    float  = 36,
    cac_ratio:         float  = 1.0,
    churn_rate:        float  = 10,
    market_size:       float  = 0,
    growth_trend:      int    = 0,      # -1 declining, 0 stable, 1 growing, 2 hot
    competition_level: int    = 3,      # 1 low … 5 very high
    team_score:        int    = 3,      # 1 none … 5 expert
    has_revenue:       bool   = False,
    has_customers:     bool   = False,
) -> dict[str, Any]:
    """
    Compute a multi-factor success probability score (0–100).

    Factors and weights:
    - Financial health:   30 pts (margin, payback, LTV/CAC)
    - Market opportunity: 25 pts (TAM, trend)
    - Competitive moat:   20 pts (competition level)
    - Team quality:       15 pts
    - Traction:           10 pts (has revenue, has customers)
    - Churn penalty:      variable

    Returns:
        Dict with score (0–100), breakdown per factor, and rating label.
    """
    bm = get_benchmark(segment)

    # 1. Financial (30 pts)
    margin_ratio  = margin_pct / (bm["avg_gross_margin"] or 50)
    financial     = min(10, margin_ratio * 10)

    if np.isfinite(payback_months):
        payback_ratio = bm["avg_payback_months"] / max(payback_months, 1)
        financial    += min(10, payback_ratio * 10)

    financial += min(10, (cac_ratio / bm["avg_ltv_cac"]) * 10)
    financial  = round(min(30, financial), 2)

    # 2. Market opportunity (25 pts)
    if market_size >= 1e9:   market = 12
    elif market_size >= 1e8: market = 8
    elif market_size >= 1e7: market = 5
    elif market_size > 0:    market = 2
    else:                    market = 0

    trend_score = min(10, max(0, (growth_trend + 1) * 3.25))
    market     += trend_score + min(3, growth_trend + 1)
    market      = round(min(25, market), 2)

    # 3. Competition (20 pts)
    competition = round(max(0, 20 - competition_level * 3.5), 2)

    # 4. Team (15 pts)
    team = round(min(15, team_score * 3), 2)

    # 5. Traction (10 pts)
    traction = (6 if has_revenue else 0) + (4 if has_customers else 0)

    # Churn penalty
    churn_excess = max(0, churn_rate - bm["avg_churn_monthly"])
    penalty      = round(churn_excess * 1.5, 2)

    raw = financial + market + competition + team + traction - penalty
    raw = max(0, min(95, raw))

    # Anchor to industry survival rate
    floor = bm["success_rate_5y"] - 5
    ceil  = min(95, bm["success_rate_5y"] + 45)
    score = int(round(min(ceil, max(floor, raw))))

    label = "Alto Potencial" if score >= 65 else ("Moderado" if score >= 40 else "Alto Risco")
    emoji = "🚀" if score >= 65 else ("⚠️" if score >= 40 else "🔴")

    return {
        "score":     score,
        "label":     label,
        "emoji":     emoji,
        "breakdown": {
            "financial":   financial,
            "market":      market,
            "competition": competition,
            "team":        team,
            "traction":    traction,
            "churn_penalty": penalty,
        },
        "benchmark": {
            "industry_success_rate_5y": bm["success_rate_5y"],
            "segment": segment,
        },
    }


def benchmarks_all() -> BizFrame:
    """Return all industry benchmarks as a BizFrame."""
    rows = []
    for segment, bm in BENCHMARKS.items():
        rows.append({"segment": segment, **bm})
    return BizFrame(rows)
