"""
Visualização interativa do resultado OAMRP — Esquadrão Arara C-105.

Gera um único HTML com título "Planejamento de Diagonal de Manutenção" contendo:
  - Gantt (Plotly): calendário aeronave × tempo com voos e inspeções
  - Mapa (Folium): rotas por aeronave, missões não cumpridas, bases

Uso:
    python software/visualizar_resultado.py \
        --resultado db/processed/resultado_oamrp_sintetico.csv \
        --saida db/processed/planejamento.html
"""

import argparse
import csv
import io
from datetime import datetime, timedelta, timezone
from html import escape
from pathlib import Path

import folium

BASE_DIR = Path(__file__).resolve().parents[1]

RESULTADO_PADRAO = BASE_DIR / "db" / "processed" / "resultado_oamrp_sintetico.csv"
SAIDA_PADRAO = BASE_DIR / "db" / "processed" / "planejamento.html"

# Coordenadas das bases (lat, lon)
BASES_COORDS: dict[str, tuple[float, float]] = {
    "SBMN": (-3.15, -59.99),
    "SBBE": (-1.38, -48.48),
    "SBBV": ( 2.84, -60.69),
    "SBSN": (-2.42, -54.79),
    "SBPV": (-8.71, -63.90),
    "SBTS": (-4.25, -69.94),
    "SBTT": (-3.38, -64.72),
    "SBUA": (-0.15, -67.05),
    "SWBC": (-0.98, -62.92),
    "SBMY": (-5.81, -61.28),
}

BASES_NOMES = {
    "SBMN": "Manaus / Ponta Pelada (Hub)",
    "SBBE": "Belém",
    "SBBV": "Boa Vista",
    "SBSN": "Santarém",
    "SBPV": "Porto Velho",
    "SBTS": "Tabatinga",
    "SBTT": "Tefé",
    "SBUA": "São Gabriel da Cachoeira",
    "SWBC": "Barcelos",
    "SBMY": "Manicoré",
}

CORES_AERONAVE = {
    "2800": "#1f77b4",
    "2803": "#2ca02c",
    "2809": "#d62728",
    "2811": "#ff7f0e",
}
COR_NAO_CUMPRIDA = "#aaaaaa"

_GANTT_CORES = {
    "cumprida": {
        "1": "#d62728",
        "2": "#ff7f0e",
        "3": "#2ca02c",
        "4": "#1f77b4",
        "5": "#9467bd",
        "": "#1f77b4",
    },
    "inspecao": "#8c564b",
    "nao_cumprida": "#aaaaaa",
}


def _cor_prio(prio: str) -> str:
    return {"1": "red", "2": "orange", "3": "yellow", "4": "lightblue", "5": "lightgray"}.get(str(prio), "white")


def _cor_gantt(linha: dict) -> str:
    status = linha["status"]
    if status == "inspecao":
        return _GANTT_CORES["inspecao"]
    if status == "nao_cumprida":
        return _GANTT_CORES["nao_cumprida"]
    return _GANTT_CORES["cumprida"].get(linha.get("prioridade", ""), "#1f77b4")


def carregar_resultado(caminho: Path) -> list[dict]:
    with caminho.open(newline="", encoding="utf-8-sig") as f:
        return list(csv.DictReader(f))


def _resumir_resultado(linhas: list[dict]) -> None:
    cumpridas = sum(1 for r in linhas if r["status"] == "cumprida")
    total_missoes = sum(1 for r in linhas if r["status"] in ("cumprida", "nao_cumprida"))
    print(f" Missões: {cumpridas}/{total_missoes} cumpridas")
    aeronaves: dict[str, int] = {}
    for r in linhas:
        if r["aeronave"] and r["status"] == "cumprida":
            aeronaves.setdefault(r["aeronave"], 0)
            aeronaves[r["aeronave"]] += 1
    for k, c in sorted(aeronaves.items()):
        print(f"   FAB {k}: {c} missões")


# ---------------------------------------------------------------------------
# Mapa Folium → string HTML
# ---------------------------------------------------------------------------

def _construir_mapa(linhas: list[dict]) -> str:
    mapa = folium.Map(location=[-3.5, -62.0], zoom_start=5, tiles="CartoDB positron")

    aeronaves_vistas = sorted({r["aeronave"] for r in linhas if r["aeronave"]})
    grupos: dict[str, folium.FeatureGroup] = {}
    for k in aeronaves_vistas:
        grupos[k] = folium.FeatureGroup(name=f"FAB {k}", show=True)
    grupos["nao_cumprida"] = folium.FeatureGroup(name="Não cumpridas", show=True)

    for r in linhas:
        if r["status"] != "cumprida":
            continue
        orig, dest = r["orig"], r["dest"]
        if orig not in BASES_COORDS or dest not in BASES_COORDS:
            continue
        k = r["aeronave"]
        cor = CORES_AERONAVE.get(k, "#333333")
        lat_o, lon_o = BASES_COORDS[orig]
        lat_d, lon_d = BASES_COORDS[dest]

        folium.PolyLine(
            locations=[[lat_o, lon_o], [lat_d, lon_d]],
            color=cor, weight=2.5, opacity=0.8,
            tooltip=f"FAB {k} | {orig}→{dest} | OM {r['om']} | prio {r['prioridade']}",
            popup=folium.Popup(
                f"<b>FAB {k}</b> — Missão #{r['ordem']}<br>"
                f"{orig} → {dest}<br>"
                f"OM: {r['om']} | Prio: {r['prioridade']}<br>"
                f"Partida: {r['partida_utc'][:16].replace('T',' ')}Z<br>"
                f"Chegada: {r['chegada_utc'][:16].replace('T',' ')}Z<br>"
                f"Duração: {r['dur_h']}h",
                max_width=250,
            ),
        ).add_to(grupos[k])
        folium.CircleMarker(
            location=[lat_o, lon_o], radius=4, color=cor,
            fill=True, fill_color=_cor_prio(r["prioridade"]), fill_opacity=0.9,
            tooltip=f"{orig} | prio {r['prioridade']}",
        ).add_to(grupos[k])

    for r in linhas:
        if r["status"] == "nao_cumprida":
            orig, dest = r["orig"], r["dest"]
            if orig not in BASES_COORDS or dest not in BASES_COORDS:
                continue
            lat_o, lon_o = BASES_COORDS[orig]
            lat_d, lon_d = BASES_COORDS[dest]
            folium.PolyLine(
                locations=[[lat_o, lon_o], [lat_d, lon_d]],
                color=COR_NAO_CUMPRIDA, weight=1.5, opacity=0.5, dash_array="6 4",
                tooltip=f"NÃO CUMPRIDA | {orig}→{dest} | OM {r['om']} | prio {r['prioridade']}",
            ).add_to(grupos["nao_cumprida"])

    for g in grupos.values():
        g.add_to(mapa)

    for icao, (lat, lon) in BASES_COORDS.items():
        folium.Marker(
            location=[lat, lon],
            tooltip=f"<b>{icao}</b><br>{BASES_NOMES.get(icao, '')}",
            popup=folium.Popup(f"<b>{icao}</b><br>{BASES_NOMES.get(icao, '')}", max_width=200),
            icon=folium.Icon(color="red" if icao == "SBMN" else "blue", icon="plane", prefix="fa"),
        ).add_to(mapa)

    folium.LayerControl(collapsed=False).add_to(mapa)

    legenda_html = """
    <div style="position:fixed;bottom:30px;left:30px;z-index:1000;background:white;
                padding:12px 16px;border-radius:8px;box-shadow:2px 2px 6px rgba(0,0,0,0.3);
                font-family:sans-serif;font-size:12px;">
      <b>Esquadrão Arara — OAMRP v3</b><br><br>
      <b>Aeronaves:</b><br>
    """
    for k, cor in CORES_AERONAVE.items():
        legenda_html += (
            f'  <span style="display:inline-block;width:16px;height:4px;'
            f'background:{cor};margin-right:6px;vertical-align:middle;"></span>'
            f'FAB {k}<br>'
        )
    legenda_html += """
      <br><b>Prioridade (preenchimento):</b><br>
      <span style="display:inline-block;width:12px;height:12px;border-radius:50%;
        background:red;margin-right:6px;"></span>Prio 1 (urgente)<br>
      <span style="display:inline-block;width:12px;height:12px;border-radius:50%;
        background:orange;margin-right:6px;"></span>Prio 2<br>
      <span style="display:inline-block;width:12px;height:12px;border-radius:50%;
        background:yellow;margin-right:6px;"></span>Prio 3<br>
      <span style="display:inline-block;width:12px;height:12px;border-radius:50%;
        background:lightblue;margin-right:6px;"></span>Prio 4–5<br>
      <br>
      <span style="border-bottom:2px dashed #aaa;display:inline-block;width:20px;
        margin-right:6px;"></span>Não cumprida
    </div>
    """
    mapa.get_root().html.add_child(folium.Element(legenda_html))

    return mapa.get_root().render()


# ---------------------------------------------------------------------------
# Gantt Plotly → string HTML (só o div, sem <html>)
# ---------------------------------------------------------------------------

def _construir_gantt(linhas: list[dict]) -> str:
    try:
        import plotly.graph_objects as go
    except ImportError:
        return "<p><em>plotly não instalado — instale com: pip install plotly</em></p>"

    aeronaves_ord = sorted(
        {r["aeronave"] for r in linhas if r["aeronave"]},
        key=lambda k: int(k) if k.isdigit() else 0,
    )
    y_pos = {k: i for i, k in enumerate(aeronaves_ord)}

    fig = go.Figure()

    for i, k in enumerate(aeronaves_ord):
        fig.add_hrect(
            y0=i - 0.45, y1=i + 0.45,
            fillcolor="#f0f0f0" if i % 2 == 0 else "white",
            layer="below", line_width=0,
        )

    shapes = []
    hover_traces = []

    for r in linhas:
        k = r["aeronave"]
        if not k or k not in y_pos:
            continue
        try:
            ini = r["partida_utc"].replace("Z", "+00:00")
            fim = r["chegada_utc"].replace("Z", "+00:00")
        except Exception:
            continue

        yi = y_pos[k]
        cor = _cor_gantt(r)
        status = r["status"]

        shapes.append(dict(
            type="rect", xref="x", yref="y",
            x0=ini, x1=fim,
            y0=yi - 0.4, y1=yi + 0.4,
            fillcolor=cor,
            line=dict(color="white", width=0.5),
            opacity=1.0 if status == "inspecao" else 0.85,
            layer="above",
        ))

        if status == "inspecao":
            txt = (
                f"<b>FAB {k}</b> — Inspeção {r['om']}<br>"
                f"Início: {ini[:16].replace('T',' ')}Z<br>"
                f"Fim: {fim[:16].replace('T',' ')}Z<br>"
                f"Duração: {r['dur_h']}h"
            )
        else:
            txt = (
                f"<b>FAB {k}</b> — Missão #{r['ordem']}<br>"
                f"{r['orig']} → {r['dest']}<br>"
                f"OM: {r['om']} | Prio: {r['prioridade']}<br>"
                f"Partida: {ini[:16].replace('T',' ')}Z<br>"
                f"Chegada: {fim[:16].replace('T',' ')}Z<br>"
                f"Duração: {r['dur_h']}h"
            )
        hover_traces.append(go.Scatter(
            x=[ini, fim], y=[yi, yi], mode="markers",
            marker=dict(size=0.1, color=cor, opacity=0),
            hovertext=[txt, txt], hoverinfo="text", showlegend=False,
        ))

    # Divisões diárias
    datas_utc = [
        r[campo].replace("Z", "+00:00")
        for r in linhas
        for campo in ("partida_utc", "chegada_utc")
        if r.get(campo)
    ]
    if datas_utc:
        t_min = datetime.fromisoformat(min(datas_utc))
        t_max = datetime.fromisoformat(max(datas_utc))
        dia = datetime(t_min.year, t_min.month, t_min.day, tzinfo=timezone.utc)
        while dia <= t_max + timedelta(days=1):
            shapes.append(dict(
                type="line", xref="x", yref="paper",
                x0=dia.isoformat(), x1=dia.isoformat(),
                y0=0, y1=1,
                line=dict(color="#bbbbbb", width=1, dash="dot"),
                layer="above",
            ))
            dia += timedelta(days=1)

    # Legenda
    for nome, cor in [
        ("Prio 1", _GANTT_CORES["cumprida"]["1"]),
        ("Prio 2", _GANTT_CORES["cumprida"]["2"]),
        ("Prio 3", _GANTT_CORES["cumprida"]["3"]),
        ("Prio 4", _GANTT_CORES["cumprida"]["4"]),
        ("Prio 5", _GANTT_CORES["cumprida"]["5"]),
        ("Inspeção", _GANTT_CORES["inspecao"]),
    ]:
        fig.add_trace(go.Scatter(
            x=[None], y=[None], mode="markers",
            marker=dict(size=12, color=cor, symbol="square"),
            name=nome, showlegend=True,
        ))

    for t in hover_traces:
        fig.add_trace(t)

    fig.update_layout(
        shapes=shapes,
        xaxis=dict(
            title="Data / Hora (UTC)", type="date",
            tickformat="%d/%m", dtick=86400000,
            showgrid=True, gridcolor="#dddddd",
        ),
        yaxis=dict(
            title="Aeronave",
            tickvals=list(range(len(aeronaves_ord))),
            ticktext=[f"FAB {k}" for k in aeronaves_ord],
            showgrid=False,
        ),
        height=max(300, 120 + 80 * len(aeronaves_ord)),
        plot_bgcolor="white",
        paper_bgcolor="white",
        legend=dict(title="Legenda", orientation="v", x=1.01, y=1, xanchor="left"),
        margin=dict(l=100, r=160, t=10, b=60),
        hovermode="closest",
    )

    return fig.to_html(full_html=False, include_plotlyjs="cdn")


# ---------------------------------------------------------------------------
# Tabela de voos com filtros
# ---------------------------------------------------------------------------

def _construir_tabela(linhas: list[dict]) -> str:
    import json

    # Monta lista de registros para a tabela (missões + inspeções, sem nao_cumprida sem aeronave)
    registros = []
    for r in linhas:
        status = r["status"]
        k = r["aeronave"]
        if status == "nao_cumprida" and not k:
            # mantém como linha sem aeronave
            k = "—"
        registros.append({
            "status":    status,
            "aeronave":  f"FAB {k}" if k and k != "—" else "—",
            "ordem":     r.get("ordem", ""),
            "om":        r.get("om", ""),
            "orig":      r.get("orig", ""),
            "dest":      r.get("dest", ""),
            "partida":   r.get("partida_utc", "")[:16].replace("T", " ") + "Z" if r.get("partida_utc") else "",
            "chegada":   r.get("chegada_utc", "")[:16].replace("T", " ") + "Z" if r.get("chegada_utc") else "",
            "dur_h":     r.get("dur_h", ""),
            "prioridade": r.get("prioridade", ""),
        })

    dados_json = json.dumps(registros, ensure_ascii=False)

    opcoes_aeronave = sorted({r["aeronave"] for r in registros if r["aeronave"] != "—"})
    opcoes_status   = ["cumprida", "nao_cumprida", "inspecao"]
    opcoes_prio     = sorted({r["prioridade"] for r in registros if r["prioridade"]})
    opcoes_base     = sorted({b for r in registros for b in (r["orig"], r["dest"]) if b})

    def opts(valores: list[str], label: str) -> str:
        html = f'<option value="">— {label} —</option>'
        for v in valores:
            html += f'<option value="{escape(v)}">{escape(v)}</option>'
        return html

    return f"""
<style>
  .filtros {{
    display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 14px; align-items: flex-end;
  }}
  .filtros label {{ font-size: 0.78rem; color: #555; display: flex; flex-direction: column; gap: 3px; }}
  .filtros select, .filtros input {{
    border: 1px solid #ccc; border-radius: 4px; padding: 5px 8px;
    font-size: 0.85rem; min-width: 130px; background: white;
  }}
  .filtros button {{
    padding: 6px 14px; border: none; border-radius: 4px; cursor: pointer;
    font-size: 0.85rem; background: #1a3a5c; color: white;
    align-self: flex-end;
  }}
  .filtros button:hover {{ background: #254f80; }}
  #contador {{ font-size: 0.82rem; color: #666; margin-bottom: 10px; }}
  #tabela-voos {{ width: 100%; border-collapse: collapse; font-size: 0.85rem; }}
  #tabela-voos thead th {{
    background: #1a3a5c; color: white; padding: 8px 10px;
    text-align: left; white-space: nowrap; cursor: pointer; user-select: none;
  }}
  #tabela-voos thead th:hover {{ background: #254f80; }}
  #tabela-voos thead th .sort-icon {{ margin-left: 4px; opacity: 0.5; }}
  #tabela-voos tbody tr:nth-child(even) {{ background: #f7f8fa; }}
  #tabela-voos tbody tr:hover {{ background: #e8f0fb; }}
  #tabela-voos td {{ padding: 7px 10px; border-bottom: 1px solid #eee; white-space: nowrap; }}
  .badge {{
    display: inline-block; padding: 2px 8px; border-radius: 10px;
    font-size: 0.75rem; font-weight: 600; text-transform: uppercase;
  }}
  .badge-cumprida    {{ background: #d4edda; color: #155724; }}
  .badge-nao_cumprida {{ background: #f8d7da; color: #721c24; }}
  .badge-inspecao    {{ background: #e2d9f3; color: #4a235a; }}
  .prio-1 {{ color: #d62728; font-weight: 700; }}
  .prio-2 {{ color: #ff7f0e; font-weight: 700; }}
  .prio-3 {{ color: #2ca02c; font-weight: 700; }}
</style>

<div class="filtros">
  <label>Aeronave
    <select id="f-aeronave">{opts(opcoes_aeronave, "Todas")}</select>
  </label>
  <label>Status
    <select id="f-status">{opts(opcoes_status, "Todos")}</select>
  </label>
  <label>Prioridade
    <select id="f-prio">{opts(opcoes_prio, "Todas")}</select>
  </label>
  <label>Base (orig/dest)
    <select id="f-base">{opts(opcoes_base, "Todas")}</select>
  </label>
  <label>Busca (OM, rota…)
    <input id="f-texto" type="text" placeholder="ex: SBMN, EVAM…">
  </label>
  <button onclick="limparFiltros()">Limpar</button>
</div>
<div id="contador"></div>
<table id="tabela-voos">
  <thead>
    <tr>
      <th onclick="ordenar(0)">Aeronave <span class="sort-icon">↕</span></th>
      <th onclick="ordenar(1)">Status <span class="sort-icon">↕</span></th>
      <th onclick="ordenar(2)">#Missão <span class="sort-icon">↕</span></th>
      <th onclick="ordenar(3)">OM <span class="sort-icon">↕</span></th>
      <th onclick="ordenar(4)">Origem <span class="sort-icon">↕</span></th>
      <th onclick="ordenar(5)">Destino <span class="sort-icon">↕</span></th>
      <th onclick="ordenar(6)">Partida (UTC) <span class="sort-icon">↕</span></th>
      <th onclick="ordenar(7)">Chegada (UTC) <span class="sort-icon">↕</span></th>
      <th onclick="ordenar(8)">Duração (h) <span class="sort-icon">↕</span></th>
      <th onclick="ordenar(9)">Prio <span class="sort-icon">↕</span></th>
    </tr>
  </thead>
  <tbody id="corpo-tabela"></tbody>
</table>

<script>
const DADOS = {dados_json};
let _colOrdem = -1, _colAsc = true;

function badgeStatus(s) {{
  const label = {{cumprida:'Cumprida', nao_cumprida:'Não cumprida', inspecao:'Inspeção'}}[s] || s;
  return `<span class="badge badge-${{s}}">${{label}}</span>`;
}}
function prio(p) {{
  if (!p) return '';
  const cls = ['1','2','3'].includes(p) ? `prio-${{p}}` : '';
  return `<span class="${{cls}}">${{p}}</span>`;
}}

function linhasFiltradas() {{
  const fa = document.getElementById('f-aeronave').value;
  const fs = document.getElementById('f-status').value;
  const fp = document.getElementById('f-prio').value;
  const fb = document.getElementById('f-base').value;
  const ft = document.getElementById('f-texto').value.toLowerCase();
  return DADOS.filter(r => {{
    if (fa && r.aeronave !== fa) return false;
    if (fs && r.status !== fs) return false;
    if (fp && r.prioridade !== fp) return false;
    if (fb && r.orig !== fb && r.dest !== fb) return false;
    if (ft && !JSON.stringify(r).toLowerCase().includes(ft)) return false;
    return true;
  }});
}}

function renderizar() {{
  let rows = linhasFiltradas();
  if (_colOrdem >= 0) {{
    const chaves = ['aeronave','status','ordem','om','orig','dest','partida','chegada','dur_h','prioridade'];
    const c = chaves[_colOrdem];
    rows = [...rows].sort((a,b) => {{
      const va = a[c] ?? '', vb = b[c] ?? '';
      return _colAsc ? String(va).localeCompare(String(vb), 'pt', {{numeric:true}})
                     : String(vb).localeCompare(String(va), 'pt', {{numeric:true}});
    }});
  }}
  document.getElementById('contador').textContent =
    `${{rows.length}} registro${{rows.length !== 1 ? 's' : ''}} exibido${{rows.length !== 1 ? 's' : ''}} de ${{DADOS.length}}`;
  document.getElementById('corpo-tabela').innerHTML = rows.map(r => `
    <tr>
      <td>${{r.aeronave}}</td>
      <td>${{badgeStatus(r.status)}}</td>
      <td>${{r.ordem}}</td>
      <td>${{r.om}}</td>
      <td>${{r.orig}}</td>
      <td>${{r.dest}}</td>
      <td>${{r.partida}}</td>
      <td>${{r.chegada}}</td>
      <td>${{r.dur_h}}</td>
      <td>${{prio(r.prioridade)}}</td>
    </tr>`).join('');
}}

function ordenar(col) {{
  if (_colOrdem === col) _colAsc = !_colAsc;
  else {{ _colOrdem = col; _colAsc = true; }}
  renderizar();
}}

function limparFiltros() {{
  ['f-aeronave','f-status','f-prio','f-base'].forEach(id => document.getElementById(id).value = '');
  document.getElementById('f-texto').value = '';
  renderizar();
}}

['f-aeronave','f-status','f-prio','f-base'].forEach(id =>
  document.getElementById(id).addEventListener('change', renderizar));
document.getElementById('f-texto').addEventListener('input', renderizar);

renderizar();
</script>"""


# ---------------------------------------------------------------------------
# HTML combinado
# ---------------------------------------------------------------------------

def gerar_planejamento(resultado: Path, saida: Path) -> None:
    linhas = carregar_resultado(resultado)

    gantt_div  = _construir_gantt(linhas)
    mapa_html  = _construir_mapa(linhas)
    tabela_div = _construir_tabela(linhas)

    html = f"""<!DOCTYPE html>
<html lang="pt-BR">
<head>
  <meta charset="utf-8">
  <title>Planejamento de Diagonal de Manutenção</title>
  <style>
    * {{ box-sizing: border-box; margin: 0; padding: 0; }}
    body {{ font-family: 'Segoe UI', Arial, sans-serif; background: #f0f2f5; color: #222; }}
    header {{
      background: #1a3a5c; color: white;
      padding: 18px 32px;
      border-bottom: 4px solid #c8a400;
    }}
    header h1 {{ font-size: 1.5rem; font-weight: 700; letter-spacing: 0.03em; }}
    header p {{ font-size: 0.85rem; opacity: 0.75; margin-top: 4px; }}
    .container {{ padding: 24px 32px; max-width: 1600px; margin: 0 auto; }}
    .section {{
      background: white; border-radius: 8px;
      box-shadow: 0 1px 4px rgba(0,0,0,0.12);
      margin-bottom: 28px; overflow: hidden;
    }}
    .section-title {{
      background: #f7f8fa; border-bottom: 1px solid #e0e0e0;
      padding: 12px 20px; font-size: 0.95rem; font-weight: 600;
      color: #1a3a5c; text-transform: uppercase; letter-spacing: 0.05em;
    }}
    .section-body {{ padding: 16px; }}
    iframe.mapa {{
      width: 100%; height: 560px; border: none; border-radius: 4px; display: block;
    }}
  </style>
</head>
<body>
  <header>
    <h1>Planejamento de Diagonal de Manutenção</h1>
    <p>Esquadrão Arara · C-105 · OAMRP v3</p>
  </header>
  <div class="container">
    <div class="section">
      <div class="section-title">Calendário de Emprego das Aeronaves</div>
      <div class="section-body">{gantt_div}</div>
    </div>
    <div class="section">
      <div class="section-title">Rotas Operacionais</div>
      <iframe class="mapa" srcdoc="{escape(mapa_html)}"></iframe>
    </div>
    <div class="section">
      <div class="section-title">Planejamento de Voos</div>
      <div class="section-body">{tabela_div}</div>
    </div>
  </div>
</body>
</html>"""

    saida.parent.mkdir(parents=True, exist_ok=True)
    saida.write_text(html, encoding="utf-8")
    print(f" Planejamento salvo: {saida}")
    _resumir_resultado(linhas)


def main() -> None:
    parser = argparse.ArgumentParser(description="Visualização OAMRP — Arara C-105")
    parser.add_argument("--resultado", type=Path, default=RESULTADO_PADRAO)
    parser.add_argument("--saida", type=Path, default=SAIDA_PADRAO)
    args = parser.parse_args()
    gerar_planejamento(resultado=args.resultado, saida=args.saida)


if __name__ == "__main__":
    main()
