#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Gera imagens 3D renderizadas do casco e compila o PDF do Painel 3D Interativo
do Saveiro Costeiro Tradicional 7,00m (Antônio Manoel Costa - Grupo 4).
"""
import os
import numpy as np
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm

from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Image, Table, TableStyle, PageBreak, HRFlowable
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import cm as rcm
from reportlab.pdfgen import canvas

class NumberedCanvas(canvas.Canvas):
    def __init__(self, *args, **kwargs):
        super(NumberedCanvas, self).__init__(*args, **kwargs)
        self._saved_page_states = []

    def showPage(self):
        self._saved_page_states.append(dict(self.__dict__))
        self._startPage()

    def save(self):
        num_pages = len(self._saved_page_states)
        for state in self._saved_page_states:
            self.__dict__.update(state)
            self.draw_page_decorations(num_pages)
            super(NumberedCanvas, self).showPage()
        super(NumberedCanvas, self).save()

    def draw_page_decorations(self, page_count):
        self.saveState()
        if self._pageNumber > 1:
            self.setFont("Helvetica-Bold", 8)
            self.setFillColor(colors.HexColor("#0B2545"))
            self.drawString(45, 804, "BRANA | ESCOLA DE ENGENHARIA NAVAL & ESTALEIRO ESCOLA EMBRIÃO")
            self.setFont("Helvetica", 8)
            self.setFillColor(colors.HexColor("#64748B"))
            self.drawRightString(550, 804, "Saveiro Costeiro Tradicional 7,00m • Painel 3D & Hidrostática")
            self.setStrokeColor(colors.HexColor("#CBD5E1"))
            self.setLineWidth(0.5)
            self.line(45, 796, 550, 796)

        self.setFont("Helvetica", 8)
        self.setFillColor(colors.HexColor("#64748B"))
        self.drawString(45, 32, "Aluno: Antônio Manoel Costa (Grupo 4) • Orientação: Profa. Magdalena (Mada) — Brana/EEE")
        page_text = f"Página {self._pageNumber} de {page_count}"
        self.drawRightString(550, 32, page_text)
        self.setStrokeColor(colors.HexColor("#CBD5E1"))
        self.setLineWidth(0.5)
        self.line(45, 44, 550, 44)
        self.restoreState()

pasta = "/home/magdalena/eee/alunos/antonio-manoel-costa"
os.makedirs(pasta, exist_ok=True)

# -------------------------------------------------------------
# Definição geométrica do casco 7,00m (Cm = 0.90)
# -------------------------------------------------------------
# LOA = 7.00m, BOA = 2.72m (meia-boca max = 1.36m em x=2.80m)
# Pontal = 1.05m a meia-nau, 1.25m na proa, 1.05m na popa
# Quilha: 0.12m popa, 0.0m meia-nau, 1.25m proa

def geo_casco_7m(nx=100, nu=50):
    x = np.linspace(0, 7.00, nx)
    u = np.linspace(0, 1.0, nu)
    X = np.zeros((nu, nx))
    Y = np.zeros((nu, nx))
    Z = np.zeros((nu, nx))
    
    for i, xi in enumerate(x):
        xn = xi / 7.00
        # Altura da quilha zk e borda zs
        if xi < 2.80:
            zk = 0.12 * (1.0 - xi / 2.80)**2
            zs = 1.05 - 0.10 * (xi / 2.80)
            ys_max = 0.825 + (1.36 - 0.825) * np.sin(np.pi * xi / (2 * 2.80))
            p = 2.20 + (2.45 - 2.20) * (xi / 2.80)
        else:
            rel = (xi - 2.80) / (7.00 - 2.80)
            zk = 0.0 + 1.25 * (rel**2.2)
            zs = 0.95 + (1.25 - 0.95) * (rel**1.6)
            ys_max = 1.36 * np.cos(np.pi * rel / 2.0)**0.85
            p = 2.45 - (2.45 - 1.85) * rel
        
        span = max(1e-4, zs - zk)
        for j, uj in enumerate(u):
            X[j, i] = xi
            Z[j, i] = zk + span * uj
            if ys_max > 1e-4 and uj > 1e-4:
                val = max(0.0, 1.0 - (1.0 - uj)**p)
                Y[j, i] = ys_max * (val**(1.0 / p))
            else:
                Y[j, i] = 0.0
                
    return X, Y, Z

X, Y, Z = geo_casco_7m(120, 60)

# -------------------------------------------------------------
# Figura 1: Perspectiva 3D Isométrica
# -------------------------------------------------------------
fig = plt.figure(figsize=(10, 5.5), dpi=250)
ax = fig.add_subplot(111, projection='3d')
fig.patch.set_facecolor('#FFFFFF')
ax.set_facecolor('#F8FAFC')

norm = plt.Normalize(0, 1.36)
colors_map = cm.Blues(norm(Y))
ax.plot_surface(X, Y, Z, facecolors=colors_map, shade=True, alpha=0.90, rstride=2, cstride=2, linewidth=0.2, edgecolor='#1E293B')
ax.plot_surface(X, -Y, Z, facecolors=colors_map, shade=True, alpha=0.90, rstride=2, cstride=2, linewidth=0.2, edgecolor='#1E293B')

# Espelho de popa
u_popa = np.linspace(0, 1, 30)
y_popa = 0.825 * (1.0 - (1.0 - u_popa)**2.20)**(1.0/2.20)
z_popa = 0.12 + (1.05 - 0.12) * u_popa
ax.plot(np.zeros_like(y_popa), y_popa, z_popa, color='#B45309', lw=2.5)
ax.plot(np.zeros_like(y_popa), -y_popa, z_popa, color='#B45309', lw=2.5)
ax.plot([0, 0], [-0.825, 0.825], [1.05, 1.05], color='#B45309', lw=2.5)

# Linha d'água WL 0.35m
ax.contour(X, Y, Z, levels=[0.35], colors='#EF4444', linewidths=2.5, linestyles='--')
ax.contour(X, -Y, Z, levels=[0.35], colors='#EF4444', linewidths=2.5, linestyles='--')

ax.set_xlabel('X (m)', fontsize=9, labelpad=8)
ax.set_ylabel('Y (m)', fontsize=9, labelpad=8)
ax.set_zlabel('Z (m)', fontsize=9, labelpad=8)
ax.set_xlim(0, 7.2)
ax.set_ylim(-1.6, 1.6)
ax.set_zlim(-0.1, 1.4)
ax.view_init(elev=24, azim=-125)
ax.set_title("Saveiro Costeiro Tradicional 7,00m • Modelo 3D Superfície (LOA 7,00m | BOA 2,72m)", fontsize=11, fontweight='bold', color='#0B2545', pad=12)

img1_path = os.path.join(pasta, "casco_3d_isometrico.png")
plt.tight_layout()
plt.savefig(img1_path, dpi=250)
plt.close()

# -------------------------------------------------------------
# Figura 2: Multi-vistas 3D (Perfil, Topo, Balizas)
# -------------------------------------------------------------
fig2, ((ax_p, ax_t), (ax_f, ax_iso)) = plt.subplots(2, 2, figsize=(10, 7.5), dpi=250)
fig2.patch.set_facecolor('#FFFFFF')

# Perfil
ax_p.set_facecolor('#F8FAFC')
ax_p.plot(X[0, :], Z[0, :], color='#0B2545', lw=2.0, label='Quilha')
ax_p.plot(X[-1, :], Z[-1, :], color='#134074', lw=2.0, label='Borda (Convés)')
ax_p.axhline(0.35, color='#EF4444', ls='--', lw=1.2, label='WL 0,35m')
ax_p.fill_between(X[0, :], Z[0, :], Z[-1, :], color='#E2E8F0', alpha=0.6)
for st in np.linspace(0, 7.00, 7):
    ax_p.axvline(st, color='#94A3B8', ls=':', lw=0.8)
ax_p.set_title("Perfil Longitudinal (Elevação)", fontsize=9.5, fontweight='bold', color='#0B2545')
ax_p.set_xlabel("X (m)", fontsize=8)
ax_p.set_ylabel("Z (m)", fontsize=8)
ax_p.set_xlim(-0.2, 7.2)
ax_p.set_ylim(-0.1, 1.4)
ax_p.grid(True, ls=':', color='#CBD5E1')
ax_p.legend(fontsize=7, loc='upper left')

# Topo
ax_t.set_facecolor('#F8FAFC')
ax_t.plot(X[-1, :], Y[-1, :], color='#0B2545', lw=2.0, label='Convés')
ax_t.plot(X[-1, :], -Y[-1, :], color='#0B2545', lw=2.0)
ax_t.axhline(0, color='#1E293B', lw=1.0)
ax_t.fill_between(X[-1, :], -Y[-1, :], Y[-1, :], color='#E2E8F0', alpha=0.6)
for st in np.linspace(0, 7.00, 7):
    ax_t.axvline(st, color='#94A3B8', ls=':', lw=0.8)
ax_t.set_title("Plano de Meia-Boca (Convés)", fontsize=9.5, fontweight='bold', color='#0B2545')
ax_t.set_xlabel("X (m)", fontsize=8)
ax_t.set_ylabel("Y (m)", fontsize=8)
ax_t.set_xlim(-0.2, 7.2)
ax_t.set_ylim(-1.6, 1.6)
ax_t.grid(True, ls=':', color='#CBD5E1')

# Balizas
ax_f.set_facecolor('#F8FAFC')
for i in np.linspace(0, X.shape[1]-1, 7, dtype=int):
    st_x = X[0, i]
    if st_x <= 2.80:
        ax_f.plot(-Y[:, i], Z[:, i], color='#0284C7', lw=1.6)
    else:
        ax_f.plot(Y[:, i], Z[:, i], color='#16A34A', lw=1.6)
ax_f.axvline(0, color='#1E293B', lw=1.2)
ax_f.axhline(0.35, color='#EF4444', ls='--', lw=1.0)
ax_f.set_title("Balizas Transversais (Ré à esq / Vante à dir)", fontsize=9.5, fontweight='bold', color='#0B2545')
ax_f.set_xlabel("Y (m)", fontsize=8)
ax_f.set_ylabel("Z (m)", fontsize=8)
ax_f.set_xlim(-1.6, 1.6)
ax_f.set_ylim(-0.1, 1.4)
ax_f.grid(True, ls=':', color='#CBD5E1')

# Curva Hidrostática de Áreas Seccionais
ax_iso.set_facecolor('#F8FAFC')
areas_sec = []
xs_sec = np.linspace(0, 7.00, 50)
for xi in xs_sec:
    idx = np.argmin(np.abs(X[0, :] - xi))
    zk = Z[0, idx]
    zs = Z[-1, idx]
    ym = Y[-1, idx]
    if zk < 0.35:
        # Área submersa até WL 0.35
        h_sub = min(zs, 0.35) - zk
        # trapézio com Cm = 0.90
        a = ym * 2.0 * h_sub * 0.90
        areas_sec.append(max(0.0, a))
    else:
        areas_sec.append(0.0)

ax_iso.plot(xs_sec, areas_sec, color='#B45309', lw=2.2, label='Área Seccional (m²)')
ax_iso.fill_between(xs_sec, 0, areas_sec, color='#FEF3C7', alpha=0.8)
ax_iso.set_title("Curva de Áreas Seccionais (Sac - WL 0,35m)", fontsize=9.5, fontweight='bold', color='#0B2545')
ax_iso.set_xlabel("X (m)", fontsize=8)
ax_iso.set_ylabel("Área Submersa (m²)", fontsize=8)
ax_iso.set_xlim(-0.2, 7.2)
ax_iso.set_ylim(0, max(areas_sec)*1.25)
ax_iso.grid(True, ls=':', color='#CBD5E1')
ax_iso.legend(fontsize=7.5, loc='upper right')

plt.tight_layout()
img2_path = os.path.join(pasta, "casco_3d_vistas.png")
plt.savefig(img2_path, dpi=250)
plt.close()

# -------------------------------------------------------------
# Compilação do Documento PDF do Painel 3D
# -------------------------------------------------------------
def gerar_pdf_painel():
    pdf_path = os.path.join(pasta, "Painel_3D_Interativo_Antonio_Manoel_Costa.pdf")
    doc = SimpleDocTemplate(
        pdf_path,
        pagesize=A4,
        leftMargin=45,
        rightMargin=45,
        topMargin=45,
        bottomMargin=45
    )

    styles = getSampleStyleSheet()

    c_primary = colors.HexColor("#0B2545")
    c_secondary = colors.HexColor("#134074")
    c_accent = colors.HexColor("#C59B27")
    c_dark = colors.HexColor("#1E293B")
    c_light_bg = colors.HexColor("#F8FAFC")

    title_style = ParagraphStyle(
        'DocTitle',
        parent=styles['Normal'],
        fontName='Helvetica-Bold',
        fontSize=15,
        leading=19,
        textColor=c_primary,
        alignment=1,
        spaceAfter=3
    )

    subtitle_style = ParagraphStyle(
        'DocSubtitle',
        parent=styles['Normal'],
        fontName='Helvetica-Bold',
        fontSize=9.5,
        leading=13,
        textColor=c_accent,
        alignment=1,
        spaceAfter=8
    )

    h1_style = ParagraphStyle(
        'Heading1_Custom',
        parent=styles['Normal'],
        fontName='Helvetica-Bold',
        fontSize=10.5,
        leading=14,
        textColor=c_primary,
        spaceBefore=7,
        spaceAfter=3,
        keepWithNext=True
    )

    body_style = ParagraphStyle(
        'Body_Custom',
        parent=styles['Normal'],
        fontName='Helvetica',
        fontSize=8,
        leading=11,
        textColor=c_dark,
        alignment=4,
        spaceAfter=3
    )

    cell_bold = ParagraphStyle(
        'CellBold',
        parent=styles['Normal'],
        fontName='Helvetica-Bold',
        fontSize=7.5,
        leading=9.5,
        textColor=c_primary
    )

    cell_norm = ParagraphStyle(
        'CellNorm',
        parent=styles['Normal'],
        fontName='Helvetica',
        fontSize=7.5,
        leading=9.5,
        textColor=c_dark
    )

    cell_center = ParagraphStyle(
        'CellCenter',
        parent=cell_norm,
        alignment=1
    )

    link_box_style = ParagraphStyle(
        'LinkBox',
        parent=styles['Normal'],
        fontName='Helvetica-Bold',
        fontSize=9,
        leading=12,
        textColor=c_primary,
        alignment=1
    )

    story = []

    # Cabeçalho
    story.append(Paragraph("PAINEL 3D INTERATIVO & GEOMETRIA DO CASCO", title_style))
    story.append(Paragraph("Saveiro Costeiro Tradicional 7,00 m • Metodologia BRANA / Estaleiro Escola Embrião", subtitle_style))
    story.append(HRFlowable(width="100%", thickness=1.5, color=c_accent, spaceBefore=0, spaceAfter=6))

    # Tabela de Acesso Web
    web_data = [
        [
            Paragraph("<b>ACESSO AO MODELO 3D INTERATIVO NO NAVEGADOR:</b><br/>"
                      "<font color='#0077B6'><u>http://eee.brana.com.br/alunos/antonio-manoel-costa/Casco-Redondo-3D-Antonio-Manoel-Costa.html</u></font><br/>"
                      "<i>(Permite orbitar 360°, dar zoom, inspecionar balizas e visualizar a hidrostática em tempo real)</i>", link_box_style)
        ]
    ]
    t_web = Table(web_data, colWidths=[505])
    t_web.setStyle(TableStyle([
        ('BACKGROUND', (0,0), (-1,-1), colors.HexColor("#FEF3C7")),
        ('BOX', (0,0), (-1,-1), 1.0, c_accent),
        ('PADDING', (0,0), (-1,-1), 6),
        ('ALIGN', (0,0), (-1,-1), 'CENTER'),
    ]))
    story.append(t_web)
    story.append(Spacer(1, 6))

    # Inclusão da Imagem Isométrica 3D
    if os.path.exists(img1_path):
        story.append(Image(img1_path, width=505, height=270))
        story.append(Spacer(1, 4))

    # Tabela Resumo Hidrostático
    story.append(Paragraph("1. Propriedades Hidrostáticas & Geométricas Principais (7,00 m)", h1_style))
    hidro_headers = [Paragraph("<b>Grandeza Hidrostática / Geométrica</b>", cell_bold), Paragraph("<b>Valor Calculado</b>", cell_bold), Paragraph("<b>Significado Prático de Projeto</b>", cell_bold)]
    hidro_data = [
        hidro_headers,
        [Paragraph("Comprimento Total (LOA) / Linha D'água (LWL)", cell_norm), Paragraph("7,00 m / 5,38 m", cell_center), Paragraph("Casco escalado a partir do croqui original milimetrado.", cell_norm)],
        [Paragraph("Boca Moldada Máxima (BOA)", cell_norm), Paragraph("2,72 m (B/L = 0,39)", cell_center), Paragraph("Altíssima estabilidade inicial (GM) para crianças e idosos.", cell_norm)],
        [Paragraph("Pontal (D) / Borda Livre Meia-Nau (FM)", cell_norm), Paragraph("1,05 m / 0,70 m", cell_center), Paragraph("Reserva de flutuabilidade e segurança contra vagas.", cell_norm)],
        [Paragraph("Calado Leve (T_leve) / Calado Bolina", cell_norm), Paragraph("0,35 m / 1,25 m", cell_center), Paragraph("Acesso à praia da Z1 e excelente orça na BTS.", cell_norm)],
        [Paragraph("Coeficiente de Seção Mestra (Cm)", cell_norm), Paragraph("0,90 (Fundo Firme)", cell_center), Paragraph("Fundo chato com bojo suave mantendo o cálculo do croqui.", cell_norm)],
        [Paragraph("Deslocamento de Projeto Estimado (Δ)", cell_norm), Paragraph("1.850 kg", cell_center), Paragraph("Suporta 10 a 12 passageiros com reserva de empuxo.", cell_norm)]
    ]
    t_hidro = Table(hidro_data, colWidths=[180, 115, 210])
    t_hidro.setStyle(TableStyle([
        ('BACKGROUND', (0,0), (-1,0), c_primary),
        ('GRID', (0,0), (-1,-1), 0.5, colors.HexColor("#CBD5E1")),
        ('ROWBACKGROUNDS', (0,1), (-1,-1), [colors.white, c_light_bg]),
        ('PADDING', (0,0), (-1,-1), 3),
        ('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
    ]))
    story.append(t_hidro)

    # Página 2: Vistas Técnicas e Curva de Áreas
    story.append(PageBreak())
    story.append(Paragraph("2. Projeções Ortográficas 3D & Curva de Áreas Seccionais", h1_style))
    story.append(Paragraph(
        "Abaixo são apresentadas as projeções ortográficas renderizadas diretamente da malha 3D e a distribuição longitudinal de volume (Curva de Áreas Seccionais na linha d'água leve de 0,35 m):",
        body_style
    ))

    if os.path.exists(img2_path):
        story.append(Image(img2_path, width=505, height=360))
        story.append(Spacer(1, 6))

    story.append(Paragraph("3. Conclusões da Modelagem Tridimensional", h1_style))
    story.append(Paragraph(
        "• <b>Alisamento Hidrodinâmico:</b> As curvas de água e as diagonais do casco não apresentam pontos de inflexão, assegurando esteira limpa e baixa resistência ao avanço.<br/>"
        "• <b>Sustentação na Popa:</b> A largura do espelho de 1,65 m gera sustentação dinâmica na popa quando a tripulação se concentra no cockpit para os petiscos e banho de mar.<br/>"
        "• <b>Compatibilidade Estrutural:</b> A malha tridimensional está 100% pronta para a geração das cavernas estruturais e cortes em madeira maciça no Estaleiro Escola.",
        body_style
    ))

    doc.build(story, canvasmaker=NumberedCanvas)
    print("PDF do Painel 3D gerado com sucesso em:", pdf_path)

if __name__ == "__main__":
    gerar_pdf_painel()
