# relatorio.py – Relatório “Evolução da Sua Obra” (versão com ícones)
import os, io
from datetime import datetime
from django.shortcuts import get_object_or_404
from django.http import JsonResponse
from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.db import connection
from django.db.models import Sum

from reportlab.lib.pagesizes import A4, landscape
from reportlab.lib.units import cm
from reportlab.platypus import (
    SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, PageBreak,
    Image as RLImage, Frame, PageTemplate, KeepTogether
)
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.lib import colors
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from PIL import Image as PILImage
import matplotlib.pyplot as plt

from obras.models import Obra, EtapaObra, Pagamento, Foto
from obras.uploads import atingiu_limite_hd

# ──────────────────────────────────────────────────────────────────────────
# Fontes - o texto permanece em DejaVuSans (sem emojis)
# ──────────────────────────────────────────────────────────────────────────
FONT_DIR = os.path.join(settings.BASE_DIR, 'static', 'fonts')
pdfmetrics.registerFont(TTFont('DejaVuSans',      os.path.join(FONT_DIR, 'DejaVuSans.ttf')))
pdfmetrics.registerFont(TTFont('DejaVuSans-Bold', os.path.join(FONT_DIR, 'DejaVuSans-Bold.ttf')))

# ──────────────────────────────────────────────────────────────────────────
# Diretório de ícones (PNG / SVG convertidos para PNG)
# ──────────────────────────────────────────────────────────────────────────
ICON_DIR = os.path.join(settings.BASE_DIR, 'static', 'icons')

def _ico(nome: str, size: int = 14) -> RLImage:
    """Retorna RLImage do ícone solicitado com tamanho indicado (quadrado)."""
    caminho = os.path.join(ICON_DIR, nome)
    return RLImage(caminho, width=size, height=size)

# ╔═══════════════════════════════════════════════════════════════════════╗
# ║  UTILITÁRIOS DE PDF (fotos + curva-S)                                 ║
# ╚═══════════════════════════════════════════════════════════════════════╝
def _adicionar_relatorio_fotografico(el, fotos, st, doc):
    if not fotos.exists():
        return
    el.append(Table([[ _ico("fotos.png",16), Paragraph("<b>Relatório Fotográfico</b>", st['subtitulo']) ]],
                    style=[('VALIGN',(0,0),(-1,-1),'MIDDLE')], colWidths=[18, doc.width-18]))
    el.append(Spacer(1, .3*cm))

    fotos_por_etapa = {}
    for f in fotos:
        chave = f.etapa.nome if f.etapa else "Sem etapa vinculada"
        fotos_por_etapa.setdefault(chave, []).append(f)

    for etapa, lista in fotos_por_etapa.items():
        el.append(Paragraph(f"<b>{etapa}</b>", st['normal']))
        el.append(Spacer(1, .25*cm))
        linha, cont = [], 0
        for foto in lista:
            try:
                with PILImage.open(foto.imagem.path) as img:
                    w, h = img.size
                    ratio = min((doc.width*.48)/w, (doc.height*.30)/h, 1)
                    linha.append(RLImage(foto.imagem.path, width=w*ratio, height=h*ratio))
                    cont += 1
            except Exception:
                continue
            if cont == 2 or foto == lista[-1]:
                el.append(Table([linha], colWidths=[doc.width*.48, doc.width*.48]))
                el.append(Spacer(1, .5*cm)); linha, cont = [], 0
        el.append(PageBreak())

def _adicionar_curva_s(el, st, datas, cumul, buf, val_pago, val_orc, doc):
    el.append(Table([[ _ico("pagamento.png",16),
                       Paragraph("<b>Curva S – Pagamentos Acumulados</b>", st['subtitulo']) ]],
                    style=[('VALIGN',(0,0),(-1,-1),'MIDDLE')], colWidths=[18, doc.width-18]))
    el.append(Spacer(1, .2*cm))
    if not datas:
        el.append(Paragraph("Nenhum pagamento registrado até o momento.", st['normal']))
        return
    el.append(RLImage(buf, width=doc.width, height=doc.width*.5))
    el.append(Spacer(1, .2*cm))
    el.append(Paragraph(
        f"Foram pagos <b>R$ {val_pago:,.2f}</b> de <b>R$ {val_orc:,.2f}</b> "
        f"(restam <b>R$ {val_orc-val_pago:,.2f}</b>).", st['explicacao']))

# ╔═══════════════════════════════════════════════════════════════════════╗
# ║  GERADOR PRINCIPAL                                                    ║
# ╚═══════════════════════════════════════════════════════════════════════╝
@login_required
def gerar_relatorio_pdf_api(request, obra_id):
    if not (request.user.is_authenticated and getattr(request.user, "tenant", None)):
        return JsonResponse({"error":"Usuário sem tenant."}, status=401)
    connection.set_schema(request.user.tenant.schema_name)
    if request.method != 'POST':
        return JsonResponse({"error":"Método não permitido."}, status=405)

    obra = get_object_or_404(Obra, id=obra_id)
    if atingiu_limite_hd(request.user):
        return JsonResponse({'error':'Limite de 800 MB excedido.'}, status=403)

    # diretório + versão
    rel_dir = os.path.join(settings.MEDIA_ROOT,'relatorios',
                           request.user.tenant.schema_name, request.user.username,
                           f'obra_{obra.id}')
    os.makedirs(rel_dir, exist_ok=True)
    prefixo = f'obra_{obra.id}_user_{request.user.id}_v'
    versoes = [int(f.replace(prefixo,'').replace('.pdf','')) for f in os.listdir(rel_dir)
               if f.startswith(prefixo) and f.endswith('.pdf') and f.replace(prefixo,'').replace('.pdf','').isdigit()]
    versao  = max(versoes)+1 if versoes else 0
    nome_pdf = f'{prefixo}{versao}.pdf'
    caminho_pdf = os.path.join(rel_dir, nome_pdf)

    # dados
    etapas     = EtapaObra.objects.filter(obra=obra).order_by('ordem')
    pagamentos = Pagamento.objects.filter(obra=obra).order_by('data')
    fotos      = Foto.objects.filter(obra=obra).order_by('etapa__id','-data_envio')

    val_orc = float(obra.orcamento_total or 0)
    val_pag = float(pagamentos.aggregate(s=Sum('valor'))['s'] or 0)
    dias    = (datetime.now().date() - obra.data_inicio).days if obra.data_inicio else 0

    # curva-S
    datas, cumul, soma = [], [], 0
    for p in pagamentos:
        soma += float(p.valor)
        datas.append(p.data.strftime('%d/%m/%Y')); cumul.append(soma)
    buf_chart = io.BytesIO()
    if datas:
        plt.switch_backend('AGG')
        plt.figure(figsize=(10,5))
        plt.plot(datas, cumul, marker='o')
        plt.title("Curva S – Pagamentos")
        plt.xlabel("Data"); plt.ylabel("R$ acumulado")
        plt.xticks(rotation=45, ha='right'); plt.grid(True, linestyle='--', alpha=.4)
        plt.tight_layout(); plt.savefig(buf_chart, format='png'); plt.close(); buf_chart.seek(0)

    # estilos
    s = getSampleStyleSheet()
    ST = {
        'titulo': ParagraphStyle('titulo', parent=s['Heading1'], fontName='DejaVuSans-Bold',
                                 alignment=TA_CENTER, fontSize=22, spaceAfter=20),
        'subtitulo': ParagraphStyle('subt', parent=s['Heading2'], fontName='DejaVuSans-Bold',
                                    alignment=TA_LEFT, fontSize=16, spaceAfter=12),
        'normal': ParagraphStyle('norm', parent=s['BodyText'], fontName='DejaVuSans',
                                 fontSize=12, spaceAfter=6),
        'menor': ParagraphStyle('menor', parent=s['Normal'], fontName='DejaVuSans',
                                fontSize=10, spaceAfter=4),
        'foto_desc': ParagraphStyle('foto', parent=s['Normal'], fontName='DejaVuSans',
                                    fontSize=9, textColor=colors.grey),
        'explicacao': ParagraphStyle('exp', parent=s['BodyText'], fontName='DejaVuSans',
                                     alignment=TA_JUSTIFY, fontSize=10, spaceAfter=10)
    }

    # rodapé
    def rodape(canvas, _doc):
        canvas.setFont('DejaVuSans',9)
        canvas.drawCentredString((doc.leftMargin+doc.width+doc.rightMargin)/2.0, 1*cm,
                                 f'Página {_doc.page}')

    # doc
    buf_pdf = io.BytesIO()
    doc = SimpleDocTemplate(buf_pdf, pagesize=landscape(A4),
                            leftMargin=2*cm, rightMargin=2*cm,
                            topMargin=2*cm, bottomMargin=2*cm)
    frame = Frame(doc.leftMargin, doc.bottomMargin, doc.width, doc.height, id='conteudo')

    EL = []  # elementos

    # CAPA ─ logo + título
    logo = os.path.join(settings.BASE_DIR, 'static', 'relatorio', 'grf_graph_logo.png')
    EL.append(Spacer(1,.7*cm))
    EL.append(RLImage(logo, width=250, height=75, hAlign='CENTER'))
    EL.append(Spacer(1,.3*cm))
    EL.append(Paragraph("<b>Relatório de Evolução da Sua Obra</b>", ST['titulo']))
    EL.append(Spacer(1,.15*cm))

    # CAPA ─ campos com ícones
    capa_campos = [
        ('localizacao.png', "Endereço", obra.endereco or "—"),
        ('calendario.png',  "Data de início", obra.data_inicio.strftime("%d/%m/%Y") if obra.data_inicio else "—"),
        ('orcamento.png',   "Orçamento total", f"R$ {val_orc:,.2f}"),
        ('pagamento.png',   "Já pago", f"R$ {val_pag:,.2f}"),
        ('pagamento.png',   "Saldo a pagar", f"R$ {val_orc-val_pag:,.2f}"),
        ('calendario.png',  "Dias decorridos", f"{dias} dias"),
        ('calendario.png',  "Emissão", datetime.now().strftime("%d/%m/%Y")),
    ]
    for ico, label, val in capa_campos:
        EL.append(Table([[ _ico(ico,16),
                           Paragraph(f"<b>{label}:</b>", ST['normal']),
                           Paragraph(val, ST['normal']) ]],
                        colWidths=[18, 120, doc.width-138],
                        style=[('VALIGN',(0,0),(-1,-1),'MIDDLE')]))
    EL.append(PageBreak())

    # ETAPAS ─ título
    EL.append(Table([[ _ico('etapas.png',18),
                       Paragraph("<b>Etapas da Obra</b>", ST['subtitulo']) ]],
                    colWidths=[20, doc.width-20],
                    style=[('VALIGN',(0,0),(-1,-1),'MIDDLE')]))
    EL.append(Spacer(1,.2*cm))

    # detalhes por etapa (texto + materiais com ícone de tijolo)
    status_emoji = {'concluida':"✅",'em_andamento':"🚧",'atrasada':"⏳",'nao_iniciada':"🕒"}
    for e in etapas:
        emoji = next((status_emoji[k] for k in status_emoji if k in (e.status or '').lower()), "⏳")
        bloco = [
            Paragraph(f"{emoji} <b>{e.nome}</b>", ST['normal']),
            Paragraph(f"👷 Profissional: {e.profissional or '—'}", ST['menor']),
            Paragraph(f"📑 Doc.: {e.documento_profissional or '—'}", ST['menor']),
            Paragraph(
                f"📅 Início: {e.data_inicio.strftime('%d/%m/%Y') if e.data_inicio else '—'} "
                f"| Prev. fim: {e.data_prevista_fim.strftime('%d/%m/%Y') if e.data_prevista_fim else '—'} "
                f"| Fim real: {e.data_fim.strftime('%d/%m/%Y') if e.data_fim else '—'}", ST['menor']),
        ]
        val_e = float(e.valor_orcado or 0)
        pagos_e = float(pagamentos.filter(etapa=e).aggregate(t=Sum('valor'))['t'] or 0)
        saldo_e = val_e - pagos_e
        bloco.append(Paragraph(
            f"💰 Orçado: R$ {val_e:,.2f} | Pago: R$ {pagos_e:,.2f} | Saldo: R$ {saldo_e:,.2f}",
            ST['menor']))
        # Materiais
        mats = pagamentos.filter(etapa=e, tipo='Material')
        if mats.exists():
            bloco.append(Spacer(1,.1*cm))
            bloco.append(Table([[ _ico('materiais.png',14),
                                  Paragraph("Materiais", ST['menor']) ]],
                                colWidths=[16, doc.width-16],
                                style=[('VALIGN',(0,0),(-1,-1),'MIDDLE')]))
            tbl = [["Material","Qtd.","Un.","Valor (R$)"]]
            for m in mats:
                tbl.append([m.material_outro or m.descricao or "—",
                            m.quantidade or "—",
                            m.unidade or "—",
                            f"{float(m.valor):,.2f}"])
            T = Table(tbl, repeatRows=1,
                      colWidths=[doc.width*.46, doc.width*.12, doc.width*.12, doc.width*.20])
            T.setStyle(TableStyle([
                ('BACKGROUND',(0,0),(-1,0),colors.HexColor("#D9D9D9")),
                ('GRID',(0,0),(-1,-1),.45,colors.grey),
                ('FONTNAME',(0,0),(-1,0),'DejaVuSans-Bold'),
                ('ALIGN',(3,1),(3,-1),'RIGHT'),
                ('ROWBACKGROUNDS',(0,1),(-1,-1),[colors.white, colors.whitesmoke])]))
            bloco.append(T)
        bloco.append(Spacer(1,.4*cm))
        EL.append(KeepTogether(bloco))
    EL.append(PageBreak())

    # HISTÓRICO DE PAGAMENTOS
    EL.append(Table([[ _ico('pagamento.png',18),
                       Paragraph("<b>Histórico de Pagamentos</b>", ST['subtitulo']) ]],
                    colWidths=[20, doc.width-20],
                    style=[('VALIGN',(0,0),(-1,-1),'MIDDLE')]))
    EL.append(Spacer(1,.2*cm))
    tab_pag = [["Data","Tipo","Referência","Valor (R$)"]]
    for p in pagamentos:
        ref = p.etapa.nome if p.etapa else p.descricao
        tab_pag.append([p.data.strftime('%d/%m/%Y'), p.tipo, ref, f"{float(p.valor):,.2f}"])
    TPG = Table(tab_pag, repeatRows=1,
                colWidths=[doc.width*.15, doc.width*.17, doc.width*.43, doc.width*.25])
    TPG.setStyle(TableStyle([
        ('BACKGROUND',(0,0),(-1,0),colors.HexColor("#D9D9D9")),
        ('GRID',(0,0),(-1,-1),.45,colors.grey),
        ('FONTNAME',(0,0),(-1,0),'DejaVuSans-Bold'),
        ('ALIGN',(3,1),(3,-1),'RIGHT'),
        ('ROWBACKGROUNDS',(0,1),(-1,-1),[colors.white, colors.whitesmoke])]))
    EL.append(TPG)
    EL.append(PageBreak())

    # FOTOS + CURVA-S
    _adicionar_relatorio_fotografico(EL, fotos, ST, doc)
    _adicionar_curva_s(EL, ST, datas, cumul, buf_chart, val_pag, val_orc, doc)

    # finalizar
    doc.addPageTemplates([PageTemplate(id='pages', frames=[frame], onPage=rodape)])
    doc.build(EL)

    buf_pdf.seek(0)
    with open(caminho_pdf,'wb') as f: f.write(buf_pdf.read())
    buf_pdf.close()

    url = os.path.join(settings.MEDIA_URL,'relatorios',
                       request.user.tenant.schema_name, request.user.username,
                       f'obra_{obra.id}', nome_pdf)
    return JsonResponse({"url":url, "versao":versao})
