#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Build the bachelor-thesis presentation, preserving the 11_ SEAA-RO.pptx design
(logo, decorative squares, styled text boxes) by editing the title slide in place
and cloning the styled content slide for each new slide."""
import copy
from pptx import Presentation
from pptx.util import Inches, Pt
from pptx.enum.text import PP_ALIGN
from pptx.dml.color import RGBColor
from pptx.oxml.ns import qn
from pptx.oxml import parse_xml  # noqa
from lxml import etree
from pptx.opc.constants import RELATIONSHIP_TYPE as RT

TEMPLATE = "11_ SEAA-RO.pptx"
OUT = "Prezentare_Licenta_Gourmet_Hungaricum.pptx"

def el(tag):
    return etree.SubElement  # unused helper placeholder

def new_el(tag):
    return etree.Element(qn(tag))

# ---- content (Romanian, analysis-weighted) ----
TITLE = "Contabilitatea financiară a societății Gourmet Hungaricum S.R.L."
NAME_LINES = ["Absolvent: Valer Ion NEDELEA",
              "Coordonator științific: Conf. univ. dr. Titus SUCIU",
              "SEAA — Brașov, 2026"]

SLIDES = [
 ("Prezentarea societății", [
   "Gourmet Hungaricum S.R.L. — restaurant cu bucătărie tradițională maghiară și transilvăneană, în Brașov",
   "Obiect de activitate: restaurante (CAEN 5610) — servire la masă, meniu pe categorii",
   "Cifra de afaceri 2025: 2.543.426 lei (+17,85% față de 2024)",
   "Patrimoniu de circa 1,33 mil. lei, format preponderent din active imobilizate (spațiu, dotări de bucătărie)"]),
 ("Contabilitatea financiară a societății", [
   "Contabilitate în partidă dublă, conform Legii contabilității 82/1991 și OMFP 1802/2014",
   "Situații financiare anuale: bilanțul prescurtat (F10) și contul de profit și pierdere (F20)",
   "Rezultatul exercițiului se reflectă în capitalurile proprii (autofinanțare)",
   "Diagnosticul economico-financiar se face pe datele oficiale 2024 și 2025"]),
 ("Contul de profit și pierdere", [
   "Cifra de afaceri: +17,85% → 2.543.426 lei",
   "Cheltuieli totale: +9,67% (cresc mai lent decât veniturile)",
   "Rezultat net: de la −42.711 lei (2024) la +81.854 lei (2025)",
   "Rata cheltuielilor de exploatare: 101,85% → 96,92%"]),
 ("Rentabilitatea", [
   "Toți indicatorii de rentabilitate au trecut din zona negativă în cea pozitivă",
   "Rata rentabilității financiare: 13,55%",
   "Redresarea vine din decalajul venituri–cheltuieli, nu dintr-un eveniment izolat"]),
 ("Structura financiară și solvabilitatea", [
   "Activele acoperă datoriile totale de circa 1,7 ori",
   "Grad de îndatorare: 58,3%; autonomie financiară: 41,7%",
   "Datoriile pe termen lung reduse cu peste 40%",
   "Consolidare pe seama profitului reinvestit (autofinanțare)"]),
 ("Lichiditatea — punctul vulnerabil", [
   "Lichiditate curentă 0,153 · rapidă 0,064 · imediată 0,036 — sub pragurile normale",
   "Fond de rulment negativ: −645.272 lei",
   "Active imobilizate finanțate parțial din resurse pe termen scurt",
   "Fragilitate structurală, nu conjuncturală"]),
 ("Gestiunea resurselor", [
   "Durata medie de încasare a creanțelor: circa 3 zile (foarte bună)",
   "Cheltuieli cu personalul: +21,10% (30,39% din total)",
   "Stocuri: +84,53% → rotație încetinită"]),
 ("Sinteza diagnosticului", [
   "19 indicatori evaluați pentru exercițiul 2025",
   "Calificative: 3 OPTIM, 11 ACCEPTABIL, 5 DEFICITAR",
   "Tablou de bord în Microsoft Access, în logică de semafor",
   "Diagnostic actualizabil prin adăugarea unui nou an de date"]),
 ("Concluzii și propuneri", [
   "Redresare cu temei real: performanța operațională a revenit pe pozitiv",
   "Atenția se mută pe lichiditate și pe echilibrul structural",
   "Restructurarea datoriilor pe termen lung și optimizarea stocurilor",
   "Corelarea costurilor cu personalul cu productivitatea; monitorizare trimestrială"]),
]

prs = Presentation(TEMPLATE)
slides = prs.slides

# ---- helpers ----
def clone_slide(src):
    new = slides.add_slide(src.slide_layout)
    for sh in list(new.shapes):              # drop auto placeholders
        sh._element.getparent().remove(sh._element)
    for sh in src.shapes:                    # copy every demo shape (logo, squares, body)
        new.shapes._spTree.append(copy.deepcopy(sh._element))
    rmap = {}                                # remap image relationships
    for rId, rel in src.part.rels.items():
        if rel.reltype == RT.IMAGE:
            rmap[rId] = new.part.relate_to(rel._target, RT.IMAGE)
    for blip in new.shapes._spTree.iter(qn('a:blip')):
        for attr in ('r:embed', 'r:link'):
            v = blip.get(qn(attr))
            if v in rmap:
                blip.set(qn(attr), rmap[v])
    return new

def _set_para_text(p, text):
    runs = p.findall(qn('a:r'))
    for r in runs[1:]:
        p.remove(r)
    if runs:
        t = runs[0].find(qn('a:t'))
        if t is None:
            t = new_el('a:t'); runs[0].append(t)
        t.text = text
    else:
        r = new_el('a:r'); t = new_el('a:t'); t.text = text; r.append(t); p.append(r)

def _no_bullet(p):
    pPr = p.find(qn('a:pPr'))
    if pPr is None:
        pPr = new_el('a:pPr'); p.insert(0, pPr)
    pos = None
    for tag in ('a:buChar', 'a:buAutoNum', 'a:buBlip', 'a:buNone'):
        for e in pPr.findall(qn(tag)):
            if pos is None:
                pos = list(pPr).index(e)
            pPr.remove(e)
    bn = new_el('a:buNone')
    if pos is not None:
        pPr.insert(pos, bn); return
    for tag in ('a:tabLst', 'a:defRPr', 'a:extLst'):
        e = pPr.find(qn(tag))
        if e is not None:
            pPr.insert(list(pPr).index(e), bn); return
    pPr.append(bn)

def _runs_set(p, **attrs):
    for r in p.findall(qn('a:r')):
        rPr = r.find(qn('a:rPr'))
        if rPr is None:
            rPr = new_el('a:rPr'); r.insert(0, rPr)
        for k, v in attrs.items():
            rPr.set(k, v)

def body_txbody(slide):
    for sh in slide.shapes:
        if sh.shape_type == 17 and sh.has_text_frame:   # TEXT_BOX
            return sh.text_frame._txBody
    return None

def fill_lines(txBody, lines, heading_first=False, hsz="2400"):
    paras = txBody.findall(qn('a:p'))
    tmpl = copy.deepcopy(paras[0])
    for p in paras:
        txBody.remove(p)
    for i, ln in enumerate(lines):
        np = copy.deepcopy(tmpl)
        _set_para_text(np, ln)
        if heading_first and i == 0:
            _no_bullet(np); _runs_set(np, b="1", sz=hsz)
        txBody.append(np)

# ---- title slide (slide 0): edit in place ----
title_slide = slides[0]
for sh in title_slide.shapes:
    if sh.has_text_frame and "TITL" in sh.text_frame.text.upper():
        fill_lines(sh.text_frame._txBody, [TITLE]); _runs_set(sh.text_frame._txBody.find(qn('a:p')), sz="2600")
    elif sh.has_text_frame and "NUME" in sh.text_frame.text.upper():
        fill_lines(sh.text_frame._txBody, NAME_LINES)

# ---- content slides ----
content_src = slides[1]                 # the styled lorem content slide
# delete the two blank demo slides (idx 3 then 2) so they don't linger
sldIdLst = slides._sldIdLst
ids = list(sldIdLst)
for idx in (3, 2):
    prs.part.drop_rel(ids[idx].get(qn('r:id'))); sldIdLst.remove(ids[idx])

content_slides = [content_src] + [clone_slide(content_src) for _ in range(len(SLIDES) - 1)]
for slide, (heading, bullets) in zip(content_slides, SLIDES):
    fill_lines(body_txbody(slide), [heading] + bullets, heading_first=True)

# chart on the "Structura financiară și solvabilitatea" slide (index 4 in SLIDES)
def pic_fit(slide, path, L, T, W, H):
    p = slide.shapes.add_picture(path, L, T)
    sc = min(W / p.width, H / p.height)
    p.width = int(p.width * sc); p.height = int(p.height * sc)
    p.left = int(L + (W - p.width) / 2); p.top = int(T + (H - p.height) / 2)

pic_fit(content_slides[4],
        "Template-diploma-project-UnitBv/images/grafic-indicatori.png",
        Inches(2.1), Inches(3.55), Inches(5.8), Inches(3.5))

prs.save(OUT)
print("saved", OUT, "slides:", len(prs.slides._sldIdLst))
