"""Importa a aba VOOS do Quadro de Voo 2025 para a base de validação.""" from __future__ import annotations import argparse import re import sys from datetime import time, timedelta from pathlib import Path import pandas as pd BASE_DIR = Path(__file__).resolve().parents[1] sys.path.insert(0, str(BASE_DIR)) from src.planejador_missao.utils import normalizar_texto COLUNAS_VALIDACAO = ["slot_id", "data", "aeronave", "tipo_escala", "tripulante", "funcao", "oi", "horas_voadas", "sbv"] def _horas(valor: object) -> float: if pd.isna(valor): return 0.0 if isinstance(valor, timedelta): return round(valor.total_seconds() / 3600, 2) if isinstance(valor, time): return round(valor.hour + valor.minute / 60 + valor.second / 3600, 2) if isinstance(valor, str): texto = valor.strip() if not texto or texto == "-": return 0.0 partes = texto.split(":") if len(partes) >= 2: return round(float(partes[0]) + float(partes[1]) / 60, 2) return float(texto.replace(",", ".")) if isinstance(valor, (int, float)): return round(float(valor) * 24, 2) if 0 < float(valor) < 1 else float(valor) return 0.0 def _aeronave(valor: object) -> str: texto = normalizar_texto(valor) match = re.search(r"(\d{4})", texto) if not match: return "" numero = match.group(1) if numero.startswith("20"): return "C97" if numero.startswith("23"): return "C95" if numero.startswith("27"): return "C98" return "" def _tripulantes(valor: object) -> list[str]: partes = re.split(r"\s*/\s*", str(valor)) trips = [] for parte in partes: texto = normalizar_texto(parte) texto = re.sub(r"\([^)]*\)", " ", texto) texto = re.sub(r"[^A-Z0-9]+", " ", texto).strip() if texto and texto != "NAN": trips.append(texto) return trips[:2] def importar(origem: Path, destino: Path) -> pd.DataFrame: raw = pd.read_excel(origem, sheet_name="VOOS", header=None) linhas = [] slot_id = 0 for _, row in raw.iterrows(): data = pd.to_datetime(row[2], errors="coerce") if pd.isna(data) or data.year != 2025: continue if normalizar_texto(row[41]) != "REALIZADO": continue aeronave = _aeronave(row[37]) if not aeronave: continue slot_id += 1 tipo_escala = normalizar_texto(row[1]) horas_voadas = _horas(row[30]) oi = normalizar_texto(row[35]) if not oi or oi == "-": oi = normalizar_texto(row[32]) for idx, tripulante in enumerate(_tripulantes(row[8]), start=1): linhas.append( { "slot_id": slot_id, "data": data.date().isoformat(), "aeronave": aeronave, "tipo_escala": tipo_escala, "tripulante": tripulante, "funcao": "PILOTO" if idx == 1 else "COPILOTO", "oi": oi, "horas_voadas": horas_voadas, "sbv": 0, } ) df = pd.DataFrame(linhas, columns=COLUNAS_VALIDACAO) destino.parent.mkdir(parents=True, exist_ok=True) df.to_csv(destino, index=False) return df def main() -> None: parser = argparse.ArgumentParser(description="Importa voos realizados de 2025 para a validação.") parser.add_argument( "--origem", type=Path, default=BASE_DIR / "dados" / "Quadro de Voo 2025 (2).xlsx", help="Planilha com aba VOOS.", ) parser.add_argument( "--destino", type=Path, default=BASE_DIR / "dados" / "validacao" / "voos_2025.csv", help="CSV de validação gerado.", ) args = parser.parse_args() df = importar(args.origem, args.destino) print(f"Arquivo gerado: {args.destino}") print(f"Registros exportados: {len(df)}") print(f"Voos/slots exportados: {df['slot_id'].nunique() if not df.empty else 0}") print(f"Tripulantes exportados: {df['tripulante'].nunique() if not df.empty else 0}") if __name__ == "__main__": main()