File size: 5,769 Bytes
38f9c15
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
"""
Utility per convertire StructuredPlan in markdown formattato per webapp
"""

import logging
from typing import Dict
from data_models import StructuredPlan, StructuredSection, DataPoint

logger = logging.getLogger(__name__)


def structured_plan_to_markdown(structured_plan: StructuredPlan) -> Dict[str, str]:
    """
    Converte un StructuredPlan object in dictionary di sezioni markdown.

    Returns:
        Dict con chiavi: technical_sporting, youth_development, infrastructure, etc.
    """
    sections_markdown = {}

    for section_key, section in structured_plan.sections.items():
        try:
            markdown = _section_to_markdown(section)
            sections_markdown[section_key] = markdown
            logger.info(f"Converted section {section_key} to markdown ({len(markdown)} chars)")
        except Exception as e:
            logger.error(f"Error converting section {section_key}: {e}", exc_info=True)
            sections_markdown[section_key] = f"<p class='empty-section'>Errore nella conversione: {str(e)}</p>"

    # Aggiungi executive summary se presente
    if structured_plan.executive_summary:
        sections_markdown['executive_summary'] = structured_plan.executive_summary

    logger.info(f"Converted {len(sections_markdown)} sections to markdown")
    return sections_markdown


def _section_to_markdown(section: StructuredSection) -> str:
    """Converte una StructuredSection in markdown formattato"""
    if not section.data_points:
        return "<p class='empty-section'>Sezione non disponibile</p>"

    md = f"# {section.title}\n\n"

    # Aggiungi data points organizzati
    md += "## Indicatori Chiave\n\n"

    for dp in section.data_points:
        # Header del data point con badge
        md += f"### {dp.label}\n\n"

        # Valore principale con units
        if dp.value is not None:
            md += f"**Valore:** {_format_value(dp.value, dp.unit)}\n\n"

        # Benchmark se disponibile
        if dp.benchmark and dp.benchmark.value is not None:
            md += f"**Benchmark {dp.benchmark.category}:** {_format_value(dp.benchmark.value, dp.unit)}\n\n"

            # Deviazione con colore
            if dp.deviation is not None:
                deviation_class = "success" if dp.deviation >= 0 else "warning"
                md += f"**Scostamento:** <span class='badge-{deviation_class}'>{dp.deviation:+.1f}%</span>\n\n"

        # Fonte
        if dp.source:
            # Gestisci source.type che potrebbe essere un enum o una stringa
            if hasattr(dp.source.type, 'value'):
                source_type = dp.source.type.value
            elif dp.source.type:
                source_type = str(dp.source.type)
            else:
                source_type = "unknown"

            source_desc = dp.source.description if dp.source.description else "N/A"
            md += f"📌 **Fonte:** {source_desc} ({source_type})\n\n"

        # Confidenza (gestisce sia float che ConfidenceLevel object)
        if hasattr(dp.confidence, 'value'):
            # E' un ConfidenceLevel object
            confidence_value = dp.confidence.value
        else:
            # E' un float diretto - converti in stringa
            if isinstance(dp.confidence, float):
                if dp.confidence >= 0.8:
                    confidence_value = "high"
                elif dp.confidence >= 0.5:
                    confidence_value = "medium"
                else:
                    confidence_value = "low"
            else:
                confidence_value = str(dp.confidence)

        confidence_emoji = _confidence_emoji(confidence_value)

        # Aggiungi tooltip di aiuto per spiegare l'affidabilità
        tooltip_html = '''<span class="confidence-tooltip">
            <span class="confidence-help">?</span>
            <span class="tooltip-content">
                <strong>Cos'è l'Affidabilità?</strong>
                Indica quanto sono attendibili i dati:<br><br>
                <ul>
                    <li><strong>✅ High (80-100%):</strong> Dati verificati da fonti ufficiali (bilanci certificati, FIGC)</li>
                    <li><strong>⚠️ Medium (50-80%):</strong> Stime basate su dati parziali o medie di categoria</li>
                    <li><strong>❗ Low (&lt;50%):</strong> Stime approssimative che richiedono verifica dal club</li>
                </ul>
                Per migliorare l'affidabilità, fornire dati ufficiali del club.
            </span>
        </span>'''

        md += f"{confidence_emoji} **Affidabilità:** {confidence_value.title()} {tooltip_html}\n\n"

        md += "---\n\n"

    # Aggiungi insights se presenti (attributo opzionale)
    if hasattr(section, 'insights') and section.insights:
        md += "\n## 💡 Insights Strategici\n\n"
        for insight in section.insights:
            md += f"- {insight}\n"
        md += "\n"

    return md


def _format_value(value: float, unit: str) -> str:
    """Formatta valore con unit appropriate"""
    if unit == "EUR":
        if value >= 1_000_000:
            return f"€{value/1_000_000:.2f}M"
        elif value >= 1_000:
            return f"€{value/1_000:.1f}K"
        else:
            return f"€{value:.0f}"
    elif unit == "%":
        return f"{value:.1f}%"
    elif unit in ["anni", "giocatori", "atleti", "squadre", "campi", "posti", "abbonati", "followers", "progetti", "persone", "FTE", "membri"]:
        return f"{int(value)} {unit}"
    else:
        return f"{value} {unit}"


def _confidence_emoji(confidence_level: str) -> str:
    """Emoji per livello di confidenza"""
    mapping = {
        "high": "✅",
        "medium": "⚠️",
        "low": "❗",
        "estimated": "📊"
    }
    return mapping.get(confidence_level.lower(), "❓")