#!/usr/bin/env python3
"""
FAK Web App — Cippà Trasporti
Mini web app Flask per richiedere il miglior prezzo FAK
Avvio: python3 fak_webapp.py
Porta: 5000
"""
import json, os, sys
from datetime import datetime
from flask import Flask, render_template_string, request, jsonify

BASE = os.path.expanduser("~/.hermes/fak-comparison")
DATA_FILE = os.path.join(BASE, "comparison_data.json")

app = Flask(__name__)

def load_data():
    if os.path.exists(DATA_FILE):
        with open(DATA_FILE) as f:
            return json.load(f)
    return {"rates": {}, "surcharges": {}, "metadata": {}}

def gather_routes(data):
    carriers = list(data.get("rates", {}).keys())
    routes = {}
    for carrier in carriers:
        for key, rate in data["rates"].get(carrier, {}).items():
            if isinstance(rate, dict) and "pol" in rate:
                if key not in routes:
                    routes[key] = {"pol": rate.get("pol",""), "pol_name": rate.get("pol_name",""), "pod": rate.get("pod","")}
                routes[key][carrier] = {"20": rate.get("20"), "40": rate.get("40"), "40h": rate.get("40h")}
    return list(routes.values()), carriers

POLS = sorted(set())
PODS = sorted(set())
ROUTES_LIST = []
CARRIERS = []

def refresh_data():
    global POLS, PODS, ROUTES_LIST, CARRIERS
    data = load_data()
    ROUTES_LIST, CARRIERS = gather_routes(data)
    pols_set = set()
    pods_set = set()
    for r in ROUTES_LIST:
        if r.get("pol_name"): pols_set.add(r["pol_name"])
        if r.get("pol"): pols_set.add(r["pol"])
        if r.get("pod"): pods_set.add(r["pod"])
    POLS = sorted(pols_set)
    PODS = sorted(pods_set)

TEMPLATE = """<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>FAK Miglior Prezzo — Cippà Trasporti</title>
<style>
*{margin:0;padding:0;box-sizing:border-box;}
body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;background:#0d1117;color:#c9d1d9;min-height:100vh;}
.header{background:linear-gradient(135deg,#161b22,#0d1117);border-bottom:1px solid #30363d;padding:20px 24px;text-align:center;}
.header h1{color:#58a6ff;font-size:24px;}
.header .sub{color:#8b949e;font-size:12px;margin-top:4px;}
.main{max-width:960px;margin:0 auto;padding:24px;}
.card{background:#161b22;border:1px solid #30363d;border-radius:12px;padding:24px;margin-bottom:20px;}
.card h2{color:#d29922;font-size:18px;margin-bottom:16px;}
.card h2 small{color:#8b949e;font-weight:400;font-size:12px;}
.form-row{display:flex;gap:12px;flex-wrap:wrap;align-items:end;}
.form-group{flex:1;min-width:150px;}
.form-group label{display:block;color:#8b949e;font-size:11px;margin-bottom:4px;text-transform:uppercase;}
.form-group input,.form-group select{width:100%;background:#0d1117;border:1px solid #30363d;color:#c9d1d9;padding:10px 12px;border-radius:8px;font-size:15px;outline:none;}
.form-group input:focus,.form-group select:focus{border-color:#d29922;}
.btn{background:#d29922;color:#0d1117;font-weight:700;border:none;padding:10px 28px;border-radius:8px;cursor:pointer;font-size:15px;height:42px;white-space:nowrap;}
.btn:hover{background:#e3b341;}
.btn-secondary{background:#21262d;color:#c9d1d9;border:1px solid #30363d;padding:10px 20px;border-radius:8px;cursor:pointer;font-size:14px;height:42px;}
.btn-secondary:hover{border-color:#8b949e;}

#result{display:none;}
#result.show{display:block;}
.result-card{background:#1a2332;border:2px solid #3fb950;border-radius:12px;padding:20px;margin-bottom:20px;}
.winner{font-size:26px;font-weight:700;color:#3fb950;}
.winner small{font-size:14px;color:#8b949e;font-weight:400;}
.comparison{display:flex;gap:12px;flex-wrap:wrap;margin-top:12px;}
.comp-item{background:#21262d;border-radius:8px;padding:12px 16px;text-align:center;flex:1;min-width:120px;}
.comp-item.best-item{background:#23863622;border:1px solid #3fb950;}
.comp-item .carrier{font-weight:700;color:#58a6ff;font-size:14px;}
.comp-item .price{font-size:20px;font-weight:700;color:#c9d1d9;margin:4px 0;}
.comp-item .price.best-price{color:#3fb950;}
.comp-item .badge{font-size:11px;color:#3fb950;}
.saving{color:#d29922;font-weight:600;font-size:16px;margin-top:10px;text-align:center;}

.stats{display:flex;gap:10px;flex-wrap:wrap;margin-bottom:16px;}
.stat{background:#161b22;border:1px solid #30363d;border-radius:8px;padding:10px 16px;flex:1;min-width:100px;text-align:center;}
.stat .n{font-size:22px;font-weight:700;color:#58a6ff;}
.stat .l{font-size:10px;color:#8b949e;text-transform:uppercase;}

.table-wrap{overflow-x:auto;margin-top:16px;}
table{width:100%;border-collapse:collapse;font-size:12px;}
th{background:#1c2333;color:#58a6ff;padding:7px 10px;text-align:left;border-bottom:2px solid #30363d;}
td{padding:5px 10px;border-bottom:1px solid #21262d;}
tr:hover{background:#1c233322;}
.best-cell{color:#3fb950;font-weight:700;}
.footer{text-align:center;color:#484f58;font-size:11px;border-top:1px solid #21262d;padding:14px;margin-top:20px;}
@media(max-width:600px){.form-row{flex-direction:column;}.form-group{min-width:100%;}}
</style>
</head>
<body>

<div class="header">
    <h1>&#128674; FAK Miglior Prezzo</h1>
    <div class="sub">Cipp&agrave; Trasporti &middot; Far East &rarr; Italia</div>
</div>

<div class="main">

<div class="stats" id="stats"></div>

<div class="card">
    <h2>&#127942; Richiedi il miglior prezzo <small>confronto istantaneo su tutti i carrier</small></h2>
    <form id="quote-form" onsubmit="return false;">
        <div class="form-row">
            <div class="form-group">
                <label>POL &mdash; Porto di partenza</label>
                <input type="text" id="pol" list="pol-list" placeholder="es. Shanghai" autocomplete="off">
                <datalist id="pol-list"></datalist>
            </div>
            <div class="form-group">
                <label>POD &mdash; Porto di destinazione</label>
                <input type="text" id="pod" list="pod-list" placeholder="es. Genova" autocomplete="off">
                <datalist id="pod-list"></datalist>
            </div>
            <div class="form-group" style="min-width:120px;">
                <label>Tipo container</label>
                <select id="ctype">
                    <option value="20">20\' Standard</option>
                    <option value="40" selected>40\' Standard</option>
                    <option value="40h">40\' High Cube</option>
                </select>
            </div>
            <div style="display:flex;gap:6px;">
                <button type="submit" class="btn" onclick="searchQuote()">&#128269; Cerca prezzo</button>
                <button type="reset" class="btn-secondary" onclick="resetForm()">&#10005;</button>
            </div>
        </div>
    </form>
</div>

<div id="result">
    <div class="result-card" id="result-content"></div>
</div>

<div class="card">
    <h2>&#128202; Tabella completa</h2>
    <div style="display:flex;gap:6px;flex-wrap:wrap;margin-bottom:12px;" id="pills"></div>
    <div class="table-wrap">
        <table>
            <thead><tr id="thead"></tr></thead>
            <tbody id="tbody"></tbody>
        </table>
    </div>
</div>

</div>

<div class="footer">FAK Web App &middot; Cipp&agrave; Trasporti &middot; &#129426; Emma</div>

<script>
var CARRIERS = JSON.parse('{{carriers_json|safe}}');
var ROUTES = JSON.parse('{{routes_json|safe}}');
var SURCHARGES = JSON.parse('{{surcharges_json|safe}}');
var POLS = JSON.parse('{{pols_json|safe}}');
var PODS = JSON.parse('{{pods_json|safe}}');
var ACTIVE = new Set(CARRIERS);

// Popola datalist
document.getElementById('pol-list').innerHTML = POLS.map(function(p){return '<option value="'+p+'">';}).join('');
document.getElementById('pod-list').innerHTML = PODS.map(function(p){return '<option value="'+p+'">';}).join('');

function fm(v){return v!=null?'$'+Number(v).toLocaleString():'&mdash;';}

// Stats
(function(){
    var cnt = {}; CARRIERS.forEach(function(c){cnt[c]=0;});
    ROUTES.forEach(function(r){CARRIERS.forEach(function(c){if(r[c])cnt[c]++;});});
    var h = '<div class="stat"><div class="n">'+ROUTES.length+'</div><div class="l">Rotte totali</div></div>';
    CARRIERS.forEach(function(c){h+='<div class="stat"><div class="n" style="color:#3fb950">'+(cnt[c]||0)+'</div><div class="l">'+c.toUpperCase()+'</div></div>';});
    document.getElementById('stats').innerHTML = h;
})();

// Pills
function renderPills(){
    var h = '<button class="btn-secondary" onclick="toggleAll()" style="font-size:11px;padding:5px 10px;height:auto;">'+(ACTIVE.size===CARRIERS.length?'&#10004; Tutti':'&#9660; Tutti')+'</button>';
    CARRIERS.forEach(function(c){
        var act = ACTIVE.has(c);
        h += '<button class="btn-secondary" onclick="toggleCarrier(\''+c+'\')" style="font-size:11px;padding:5px 10px;height:auto;'+(act?'background:#1f6feb33;border-color:#58a6ff;color:#58a6ff;':'')+'">'+(act?'&#10004; ':'')+c.toUpperCase()+'</button>';
    });
    document.getElementById('pills').innerHTML = h;
    filterTable();
}

function toggleCarrier(c){
    if(ACTIVE.has(c)) ACTIVE.delete(c); else ACTIVE.add(c);
    if(ACTIVE.size===0) ACTIVE = new Set(CARRIERS);
    renderPills();
}

function toggleAll(){
    ACTIVE = ACTIVE.size===CARRIERS.length ? new Set() : new Set(CARRIERS);
    if(ACTIVE.size===0) ACTIVE = new Set(CARRIERS);
    renderPills();
}

// Tabella
function filterTable(){
    var tg = Array.from(ACTIVE);
    var filtered = ROUTES.filter(function(r){
        return tg.some(function(c){ return r[c] && (r[c]['20']||r[c]['40']||r[c]['40h']); });
    }).slice(0, 50);
    
    var hh = '<th>POL &rarr; POD</th>';
    tg.forEach(function(c){ hh += '<th>'+c.toUpperCase()+' 40\'</th>'; });
    hh += '<th>&#127942; Migliore</th><th>&#128176; Risparmio</th>';
    document.getElementById('thead').innerHTML = hh;
    
    var bd = '';
    filtered.forEach(function(r){
        var pn = r.pol_name||r.pol||'?', dn = r.pod||'?';
        bd += '<tr><td><strong>'+pn+'</strong> &rarr; '+dn+'</td>';
        var pr = [];
        tg.forEach(function(c){
            var v = r[c] ? r[c]['40'] : null;
            if(v) pr.push({c:c, v:v});
            bd += '<td>'+fm(v)+'</td>';
        });
        if(pr.length>1){
            var b = pr.reduce(function(a,b){return a.v<b.v?a:b;});
            var w = pr.reduce(function(a,b){return a.v>b.v?a:b;});
            bd += '<td><span style="color:#3fb950;font-weight:700;">&#10004; '+b.c.toUpperCase()+' '+fm(b.v)+'</span></td><td class="best-cell">'+fm(w.v-b.v)+'</td>';
        } else if(pr.length===1){
            bd += '<td><span style="color:#3fb950;">'+pr[0].c.toUpperCase()+' '+fm(pr[0].v)+'</span></td><td>&mdash;</td>';
        } else {
            bd += '<td>&mdash;</td><td>&mdash;</td>';
        }
        bd += '</tr>';
    });
    if(!bd) bd = '<tr><td colspan="'+(tg.length+3)+'" style="text-align:center;padding:30px;color:#484f58;">Nessuna rotta</td></tr>';
    document.getElementById('tbody').innerHTML = bd;
}

// Ricerca prezzo
function searchQuote(){
    var pol = document.getElementById('pol').value.trim().toUpperCase();
    var pod = document.getElementById('pod').value.trim().toUpperCase();
    var ct = document.getElementById('ctype').value;
    
    if(!pol || !pod){ alert('Inserisci POL e POD'); return; }
    
    var matches = [];
    ROUTES.forEach(function(r){
        var pm = (r.pol_name||'').toUpperCase().includes(pol) || (r.pol||'').toUpperCase().includes(pol);
        var dm = (r.pod||'').toUpperCase().includes(pod);
        if(pm && dm){
            CARRIERS.forEach(function(c){
                var v = r[c] ? r[c][ct] : null;
                if(v) matches.push({carrier:c, price:v, pol:r.pol_name||r.pol, pod:r.pod});
            });
        }
    });
    
    var el = document.getElementById('result');
    var rc = document.getElementById('result-content');
    
    if(!matches.length){
        rc.innerHTML = '<div style="color:#f85149;font-weight:600;font-size:16px;">&#10060; Nessuna tariffa trovata per questa rotta. Prova con altri termini.</div>';
        el.classList.add('show'); return;
    }
    
    matches.sort(function(a,b){return a.price-b.price;});
    var best = matches[0];
    var worst = matches[matches.length-1];
    var saving = worst.price - best.price;
    
    var h = '<div class="winner">&#127942; '+best.carrier.toUpperCase()+' &mdash; '+fm(best.price)+'<br><small>'+best.pol+' &rarr; '+best.pod+' &middot; '+ct+'\'</small></div>';
    h += '<div class="comparison">';
    matches.forEach(function(p){
        var isBest = p.price === best.price;
        h += '<div class="comp-item'+(isBest?' best-item':'')+'">';
        h += '<div class="carrier">'+p.carrier.toUpperCase()+'</div>';
        h += '<div class="price'+(isBest?' best-price':'')+'">'+fm(p.price)+'</div>';
        if(isBest) h += '<div class="badge">&#10004; Migliore</div>';
        h += '</div>';
    });
    h += '</div>';
    if(saving > 0){
        h += '<div class="saving">&#128176; Risparmio scegliendo '+best.carrier.toUpperCase()+': '+fm(saving)+'</div>';
    }
    rc.innerHTML = h;
    el.classList.add('show');
    el.scrollIntoView({behavior:'smooth', block:'center'});
}

function resetForm(){
    document.getElementById('pol').value = '';
    document.getElementById('pod').value = '';
    document.getElementById('result').classList.remove('show');
}

renderPills();
</script>
</body>
</html>"""

refresh_data()

@app.route("/")
def home():
    return render_template_string(TEMPLATE,
        carriers_json=json.dumps(CARRIERS),
        routes_json=json.dumps(ROUTES_LIST),
        surcharges_json=json.dumps(load_data().get("surcharges", {})),
        pols_json=json.dumps(POLS),
        pods_json=json.dumps(PODS))

@app.route("/api/search")
def api_search():
    pol = request.args.get("pol", "").strip().upper()
    pod = request.args.get("pod", "").strip().upper()
    ctype = request.args.get("type", "40")
    if not pol or not pod:
        return jsonify({"error": "POL e POD richiesti"}), 400
    
    matches = []
    for r in ROUTES_LIST:
        pm = (r.get("pol_name","") or "").upper().find(pol) >= 0 or (r.get("pol","") or "").upper().find(pol) >= 0
        dm = (r.get("pod","") or "").upper().find(pod) >= 0
        if pm and dm:
            for c in CARRIERS:
                v = r.get(c, {}).get(ctype)
                if v:
                    matches.append({"carrier": c.upper(), "price": v,
                                    "pol": r.get("pol_name") or r.get("pol"),
                                    "pod": r.get("pod")})
    
    if not matches:
        return jsonify({"error": "Nessuna tariffa trovata"}), 404
    
    matches.sort(key=lambda x: x["price"])
    best = matches[0]
    saving = matches[-1]["price"] - best["price"] if len(matches) > 1 else 0
    
    return jsonify({
        "best": best,
        "all": matches,
        "saving": saving,
        "count": len(matches)
    })

@app.route("/api/refresh")
def api_refresh():
    refresh_data()
    return jsonify({"status": "ok", "carriers": CARRIERS, "routes": len(ROUTES_LIST)})

if __name__ == "__main__":
    port = int(sys.argv[1]) if len(sys.argv) > 1 else 5000
    print(f"[OK] FAK Web App avviata su http://0.0.0.0:{port}")
    app.run(host="0.0.0.0", port=port, debug=False)
