package iace
import (
"archive/zip"
"bytes"
"encoding/json"
"fmt"
"strings"
"time"
)
// ExportDOCX generates a minimal DOCX file containing the CE technical file sections
func (e *DocumentExporter) ExportDOCX(
project *Project,
sections []TechFileSection,
) ([]byte, error) {
if project == nil {
return nil, fmt.Errorf("project must not be nil")
}
var buf bytes.Buffer
zw := zip.NewWriter(&buf)
contentTypes := `
`
if err := addZipEntry(zw, "[Content_Types].xml", contentTypes); err != nil {
return nil, fmt.Errorf("failed to write [Content_Types].xml: %w", err)
}
rels := `
`
if err := addZipEntry(zw, "_rels/.rels", rels); err != nil {
return nil, fmt.Errorf("failed to write _rels/.rels: %w", err)
}
docRels := `
`
if err := addZipEntry(zw, "word/_rels/document.xml.rels", docRels); err != nil {
return nil, fmt.Errorf("failed to write word/_rels/document.xml.rels: %w", err)
}
docXML := e.buildDocumentXML(project, sections)
if err := addZipEntry(zw, "word/document.xml", docXML); err != nil {
return nil, fmt.Errorf("failed to write word/document.xml: %w", err)
}
if err := zw.Close(); err != nil {
return nil, fmt.Errorf("failed to close ZIP: %w", err)
}
return buf.Bytes(), nil
}
func (e *DocumentExporter) buildDocumentXML(project *Project, sections []TechFileSection) string {
var body strings.Builder
body.WriteString(docxHeading(fmt.Sprintf("CE-Akte: %s", project.MachineName), 1))
metaLines := []string{
fmt.Sprintf("Hersteller: %s", project.Manufacturer),
fmt.Sprintf("Maschinentyp: %s", project.MachineType),
}
if project.CEMarkingTarget != "" {
metaLines = append(metaLines, fmt.Sprintf("CE-Kennzeichnungsziel: %s", project.CEMarkingTarget))
}
metaLines = append(metaLines,
fmt.Sprintf("Status: %s", project.Status),
fmt.Sprintf("Datum: %s", time.Now().Format("02.01.2006")),
)
for _, line := range metaLines {
body.WriteString(docxParagraph(line, false))
}
if project.Description != "" {
body.WriteString(docxParagraph("", false))
body.WriteString(docxParagraph(project.Description, true))
}
for _, section := range sections {
body.WriteString(docxHeading(section.Title, 2))
body.WriteString(docxParagraph(
fmt.Sprintf("Typ: %s | Status: %s | Version: %d",
section.SectionType, string(section.Status), section.Version),
true,
))
if section.Content != "" {
for _, line := range strings.Split(section.Content, "\n") {
body.WriteString(docxParagraph(line, false))
}
} else {
body.WriteString(docxParagraph("(Kein Inhalt vorhanden)", true))
}
}
body.WriteString(docxParagraph("", false))
body.WriteString(docxParagraph(
fmt.Sprintf("Generiert am %s mit BreakPilot AI Compliance SDK",
time.Now().Format("02.01.2006 15:04")),
true,
))
return fmt.Sprintf(`
%s
`, body.String())
}
// ExportJSON returns a JSON representation of the project export data
func (e *DocumentExporter) ExportJSON(
project *Project,
sections []TechFileSection,
hazards []Hazard,
assessments []RiskAssessment,
mitigations []Mitigation,
classifications []RegulatoryClassification,
) ([]byte, error) {
if project == nil {
return nil, fmt.Errorf("project must not be nil")
}
payload := map[string]interface{}{
"project": project,
"sections": sections,
"hazards": hazards,
"assessments": assessments,
"mitigations": mitigations,
"classifications": classifications,
"exported_at": time.Now().UTC().Format(time.RFC3339),
"format_version": "1.0",
}
data, err := json.MarshalIndent(payload, "", " ")
if err != nil {
return nil, fmt.Errorf("failed to marshal JSON: %w", err)
}
return data, nil
}