// Package trust — PDF evidence export.
// Wraps GenerateEvidencePackage() output in a professional compliance report PDF
// suitable for regulatory handoff.
//
// Requires: github.com/jung-kurt/gofpdf/v2
package trust

import (
	"fmt"
	"strings"
	"time"

	"github.com/jung-kurt/gofpdf/v2"
)

// PDFOptions configures the PDF report layout.
type PDFOptions struct {
	Title       string // report title (default: "AIR Blackbox — Compliance Evidence Report")
	Subtitle    string // subtitle line (default: "Generated by AIR Blackbox Gateway")
	CompanyName string // organization name shown on cover
	LogoPath    string // optional path to logo image (PNG/JPG)
}

// ExportPDF renders an EvidencePackage into a compliance report PDF and writes
// it to the given path. Returns an error if rendering or file write fails.
func ExportPDF(pkg *EvidencePackage, path string, opts PDFOptions) error {
	if opts.Title == "" {
		opts.Title = "AIR Blackbox — Compliance Evidence Report"
	}
	if opts.Subtitle == "" {
		opts.Subtitle = "Generated by AIR Blackbox Gateway"
	}

	pdf := gofpdf.New("P", "mm", "A4", "")
	pdf.SetAutoPageBreak(true, 20)

	// Colors.
	headerBg := [3]int{30, 41, 59}    // dark slate
	passBg := [3]int{220, 252, 231}    // green tint
	failBg := [3]int{254, 226, 226}    // red tint
	partialBg := [3]int{254, 243, 199} // yellow tint

	// ---- Cover Page ----
	pdf.AddPage()
	renderCover(pdf, opts, pkg, headerBg)

	// ---- Executive Summary ----
	pdf.AddPage()
	renderSectionHeader(pdf, "1. Executive Summary", headerBg)
	renderExecutiveSummary(pdf, pkg)

	// ---- Compliance Controls ----
	if pkg.ComplianceReport != nil && len(pkg.ComplianceReport.Controls) > 0 {
		pdf.AddPage()
		renderSectionHeader(pdf, "2. Compliance Controls", headerBg)
		renderControlsTable(pdf, pkg.ComplianceReport, passBg, failBg, partialBg)
	}

	// ---- Audit Chain Summary ----
	pdf.AddPage()
	renderSectionHeader(pdf, "3. Audit Chain", headerBg)
	renderAuditChainSummary(pdf, pkg)

	// ---- Audit Entries (abbreviated) ----
	if len(pkg.AuditEntries) > 0 {
		renderSectionHeader(pdf, "4. Audit Entries (Recent)", headerBg)
		renderAuditEntries(pdf, pkg)
	}

	// ---- Attestation ----
	pdf.AddPage()
	renderSectionHeader(pdf, "5. Attestation & Verification", headerBg)
	renderAttestation(pdf, pkg)

	// ---- Footer on all pages ----
	addFooters(pdf, opts)

	return pdf.OutputFileAndClose(path)
}

// ---- Render helpers ----

func renderCover(pdf *gofpdf.Fpdf, opts PDFOptions, pkg *EvidencePackage, headerBg [3]int) {
	w, h := pdf.GetPageSize()

	// Background band.
	pdf.SetFillColor(headerBg[0], headerBg[1], headerBg[2])
	pdf.Rect(0, 0, w, 100, "F")

	// Title.
	pdf.SetTextColor(255, 255, 255)
	pdf.SetFont("Helvetica", "B", 28)
	pdf.SetXY(20, 30)
	pdf.CellFormat(w-40, 14, opts.Title, "", 1, "L", false, 0, "")

	// Subtitle.
	pdf.SetFont("Helvetica", "", 14)
	pdf.SetXY(20, 50)
	pdf.CellFormat(w-40, 10, opts.Subtitle, "", 1, "L", false, 0, "")

	// Company name.
	if opts.CompanyName != "" {
		pdf.SetXY(20, 65)
		pdf.CellFormat(w-40, 10, "Organization: "+opts.CompanyName, "", 1, "L", false, 0, "")
	}

	// Metadata block below the band.
	pdf.SetTextColor(60, 60, 60)
	pdf.SetFont("Helvetica", "", 11)
	y := 115.0

	metaLines := []string{
		fmt.Sprintf("Gateway ID: %s", pkg.GatewayID),
		fmt.Sprintf("Exported: %s", pkg.ExportedAt.Format(time.RFC3339)),
		fmt.Sprintf("Chain Length: %d records", pkg.ChainLength),
		fmt.Sprintf("Chain Integrity: %s", boolLabel(pkg.ChainValid, "VALID", "BROKEN")),
	}
	if !pkg.TimeRange.Earliest.IsZero() {
		metaLines = append(metaLines, fmt.Sprintf("Time Range: %s — %s",
			pkg.TimeRange.Earliest.Format("2006-01-02 15:04 UTC"),
			pkg.TimeRange.Latest.Format("2006-01-02 15:04 UTC")))
	}

	for _, line := range metaLines {
		pdf.SetXY(20, y)
		pdf.CellFormat(w-40, 7, line, "", 1, "L", false, 0, "")
		y += 8
	}

	// Attestation hash at bottom.
	pdf.SetFont("Courier", "", 8)
	pdf.SetTextColor(120, 120, 120)
	pdf.SetXY(20, h-40)
	pdf.CellFormat(w-40, 5, "Attestation (HMAC-SHA256):", "", 1, "L", false, 0, "")
	pdf.SetXY(20, h-35)
	pdf.CellFormat(w-40, 5, pkg.Attestation, "", 1, "L", false, 0, "")
}

func renderSectionHeader(pdf *gofpdf.Fpdf, title string, bg [3]int) {
	w, _ := pdf.GetPageSize()
	pdf.Ln(4)
	pdf.SetFillColor(bg[0], bg[1], bg[2])
	pdf.SetTextColor(255, 255, 255)
	pdf.SetFont("Helvetica", "B", 14)
	pdf.CellFormat(w-40, 10, "  "+title, "", 1, "L", true, 0, "")
	pdf.Ln(4)
	pdf.SetTextColor(40, 40, 40)
}

func renderExecutiveSummary(pdf *gofpdf.Fpdf, pkg *EvidencePackage) {
	pdf.SetFont("Helvetica", "", 11)

	lines := []string{
		fmt.Sprintf("This report contains %d cryptographically signed audit records exported from gateway %q.", pkg.ChainLength, pkg.GatewayID),
		"",
	}

	if pkg.ChainValid {
		lines = append(lines, "The HMAC-SHA256 audit chain is intact. No records have been modified since signing.")
	} else {
		lines = append(lines, fmt.Sprintf("WARNING: The audit chain is broken at entry %d. Records after this point may have been tampered with.", pkg.ChainBrokenAt))
	}

	if pkg.ComplianceReport != nil {
		s := pkg.ComplianceReport.Summary
		lines = append(lines, "",
			fmt.Sprintf("Compliance evaluation: %d controls assessed across %s.",
				s.TotalControls, strings.Join(pkg.ComplianceReport.Frameworks, ", ")),
			fmt.Sprintf("  Passing: %d  |  Failing: %d  |  Partial: %d  |  Pass Rate: %.0f%%",
				s.Passing, s.Failing, s.Partial, s.PassRate),
		)
	}

	for _, line := range lines {
		if line == "" {
			pdf.Ln(4)
			continue
		}
		pdf.SetX(20)
		pdf.MultiCell(170, 6, line, "", "L", false)
	}
}

func renderControlsTable(pdf *gofpdf.Fpdf, report *ComplianceReport, passBg, failBg, partialBg [3]int) {
	pdf.SetFont("Helvetica", "B", 9)
	pdf.SetFillColor(220, 220, 220)
	pdf.SetX(15)

	colWidths := []float64{20, 22, 45, 15, 78}
	headers := []string{"ID", "Framework", "Control", "Status", "Evidence"}

	for i, h := range headers {
		pdf.CellFormat(colWidths[i], 7, h, "1", 0, "C", true, 0, "")
	}
	pdf.Ln(-1)

	pdf.SetFont("Helvetica", "", 8)

	for _, c := range report.Controls {
		// Set row background based on status.
		switch c.Status {
		case ControlPass:
			pdf.SetFillColor(passBg[0], passBg[1], passBg[2])
		case ControlFail:
			pdf.SetFillColor(failBg[0], failBg[1], failBg[2])
		case ControlPartial:
			pdf.SetFillColor(partialBg[0], partialBg[1], partialBg[2])
		}

		// Truncate evidence to fit in the cell.
		evidence := c.Evidence
		if len(evidence) > 90 {
			evidence = evidence[:87] + "..."
		}

		pdf.SetX(15)
		rowH := 6.0
		pdf.CellFormat(colWidths[0], rowH, c.ID, "1", 0, "L", true, 0, "")
		pdf.CellFormat(colWidths[1], rowH, c.Framework, "1", 0, "C", true, 0, "")
		pdf.CellFormat(colWidths[2], rowH, truncate(c.Name, 28), "1", 0, "L", true, 0, "")
		pdf.CellFormat(colWidths[3], rowH, strings.ToUpper(string(c.Status)), "1", 0, "C", true, 0, "")
		pdf.CellFormat(colWidths[4], rowH, evidence, "1", 0, "L", true, 0, "")
		pdf.Ln(-1)

		// Page break check.
		if pdf.GetY() > 265 {
			pdf.AddPage()
			renderSectionHeader(pdf, "2. Compliance Controls (continued)", [3]int{30, 41, 59})
		}
	}
}

func renderAuditChainSummary(pdf *gofpdf.Fpdf, pkg *EvidencePackage) {
	pdf.SetFont("Helvetica", "", 11)
	pdf.SetX(20)

	pdf.MultiCell(170, 6, fmt.Sprintf(
		"The audit chain contains %d entries signed with HMAC-SHA256. Each entry includes the hash of the previous entry, forming a tamper-evident sequence. Modifying any record invalidates all subsequent signatures.",
		pkg.ChainLength), "", "L", false)

	pdf.Ln(4)
	pdf.SetX(20)

	if pkg.ChainValid {
		pdf.SetTextColor(21, 128, 61) // green
		pdf.SetFont("Helvetica", "B", 12)
		pdf.CellFormat(170, 8, "CHAIN STATUS: VALID", "", 1, "L", false, 0, "")
	} else {
		pdf.SetTextColor(185, 28, 28) // red
		pdf.SetFont("Helvetica", "B", 12)
		pdf.CellFormat(170, 8, fmt.Sprintf("CHAIN STATUS: BROKEN AT ENTRY %d", pkg.ChainBrokenAt), "", 1, "L", false, 0, "")
	}
	pdf.SetTextColor(40, 40, 40)
}

func renderAuditEntries(pdf *gofpdf.Fpdf, pkg *EvidencePackage) {
	pdf.SetFont("Helvetica", "", 9)

	// Show up to 25 most recent entries.
	entries := pkg.AuditEntries
	start := 0
	if len(entries) > 25 {
		start = len(entries) - 25
		pdf.SetX(20)
		pdf.MultiCell(170, 5, fmt.Sprintf("Showing last 25 of %d entries.", len(entries)), "", "L", false)
		pdf.Ln(2)
	}

	pdf.SetFont("Helvetica", "B", 8)
	pdf.SetFillColor(220, 220, 220)
	pdf.SetX(15)

	cols := []float64{15, 35, 55, 75}
	hdr := []string{"#", "Run ID", "Record Hash", "Timestamp"}
	for i, h := range hdr {
		pdf.CellFormat(cols[i], 6, h, "1", 0, "C", true, 0, "")
	}
	pdf.Ln(-1)

	pdf.SetFont("Courier", "", 7)
	for _, e := range entries[start:] {
		pdf.SetX(15)
		pdf.CellFormat(cols[0], 5, fmt.Sprintf("%d", e.Sequence), "1", 0, "R", false, 0, "")
		pdf.CellFormat(cols[1], 5, truncate(e.RunID, 20), "1", 0, "L", false, 0, "")
		pdf.CellFormat(cols[2], 5, truncate(e.RecordHash, 32), "1", 0, "L", false, 0, "")
		pdf.CellFormat(cols[3], 5, e.Timestamp.Format("2006-01-02 15:04:05"), "1", 0, "L", false, 0, "")
		pdf.Ln(-1)

		if pdf.GetY() > 265 {
			pdf.AddPage()
		}
	}
}

func renderAttestation(pdf *gofpdf.Fpdf, pkg *EvidencePackage) {
	pdf.SetFont("Helvetica", "", 11)
	pdf.SetX(20)
	pdf.MultiCell(170, 6,
		"This evidence package is signed with HMAC-SHA256. The attestation hash below covers every field in this report. To verify the package has not been modified:",
		"", "L", false)

	pdf.Ln(4)
	pdf.SetFont("Helvetica", "", 10)
	pdf.SetX(25)
	pdf.MultiCell(165, 6,
		"1. Export the evidence package as JSON (air-blackbox evidence export)\n2. Clear the attestation field\n3. Recompute HMAC-SHA256 of the JSON with the gateway secret\n4. Compare with the attestation below",
		"", "L", false)

	pdf.Ln(6)
	pdf.SetFont("Courier", "B", 10)
	pdf.SetX(20)
	pdf.CellFormat(170, 8, "Attestation:", "", 1, "L", false, 0, "")
	pdf.SetFont("Courier", "", 9)
	pdf.SetX(20)
	pdf.MultiCell(170, 5, pkg.Attestation, "", "L", false)

	pdf.Ln(8)
	pdf.SetFont("Helvetica", "I", 9)
	pdf.SetTextColor(120, 120, 120)
	pdf.SetX(20)
	pdf.MultiCell(170, 5,
		"This report was generated by AIR Blackbox (airblackbox.ai). It checks technical requirements — it is not legal advice. Consult your compliance counsel for legal interpretation.",
		"", "L", false)
}

func addFooters(pdf *gofpdf.Fpdf, opts PDFOptions) {
	totalPages := pdf.PageCount()
	for i := 1; i <= totalPages; i++ {
		pdf.SetPage(i)
		w, h := pdf.GetPageSize()

		pdf.SetFont("Helvetica", "", 8)
		pdf.SetTextColor(150, 150, 150)

		// Left: branding.
		pdf.SetXY(15, h-12)
		pdf.CellFormat(80, 5, "AIR Blackbox — airblackbox.ai", "", 0, "L", false, 0, "")

		// Right: page number.
		pdf.SetXY(w-50, h-12)
		pdf.CellFormat(35, 5, fmt.Sprintf("Page %d of %d", i, totalPages), "", 0, "R", false, 0, "")
	}
}

// ---- Utility ----

func boolLabel(b bool, yes, no string) string {
	if b {
		return yes
	}
	return no
}

func truncate(s string, max int) string {
	if len(s) <= max {
		return s
	}
	return s[:max-3] + "..."
}
