package dev.lions.unionflow.server.service.audit;

import com.lowagie.text.Document;
import com.lowagie.text.Element;
import com.lowagie.text.Font;
import com.lowagie.text.FontFactory;
import com.lowagie.text.PageSize;
import com.lowagie.text.Paragraph;
import com.lowagie.text.Phrase;
import com.lowagie.text.pdf.PdfPCell;
import com.lowagie.text.pdf.PdfPTable;
import com.lowagie.text.pdf.PdfWriter;
import dev.lions.unionflow.server.api.dto.audit.response.AuditTrailOperationResponse;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import java.awt.Color;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.UUID;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVPrinter;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.jboss.logging.Logger;

/**
 * Export massif audit trail (Sprint 16.B) — formats CSV / XLSX / PDF.
 *
 * <p>Pour transmission BCEAO / ARTCI / CENTIF en cas d'inspection.
 * Les exports respectent les filtres scope passés à {@link AuditTrailQueryService}.
 *
 * @since 2026-04-25 (Sprint 16.B — transparency operations)
 */
@ApplicationScoped
public class AuditTrailExportService {

  private static final Logger LOG = Logger.getLogger(AuditTrailExportService.class);
  private static final DateTimeFormatter DT_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
  private static final String[] HEADERS = {
      "Timestamp", "Acteur (email)", "Rôle", "Org active", "Action", "Entité",
      "Entity ID", "Description", "SoD OK", "Violations SoD", "IP", "Request ID"
  };

  @Inject AuditTrailQueryService queryService;
  @Inject dev.lions.unionflow.server.security.AuditTrailService auditWrite;

  /** CSV (UTF-8 BOM, RFC 4180). */
  public byte[] exportCsv(String scope, UUID orgId, UUID userId, int limit) {
    List<AuditTrailOperationResponse> ops = queryService.listerRecentes(scope, orgId, userId, limit);
    try (ByteArrayOutputStream out = new ByteArrayOutputStream();
         OutputStreamWriter writer = new OutputStreamWriter(out, StandardCharsets.UTF_8)) {
      // BOM UTF-8 pour Excel
      out.write(0xEF); out.write(0xBB); out.write(0xBF);
      try (CSVPrinter printer = new CSVPrinter(writer,
          CSVFormat.DEFAULT.builder().setHeader(HEADERS).build())) {
        for (AuditTrailOperationResponse o : ops) {
          printer.printRecord(
              fmt(o.operationAt()), nz(o.userEmail()), nz(o.roleActif()),
              o.organisationActiveId(), nz(o.actionType()), nz(o.entityType()),
              o.entityId(), nz(o.description()),
              o.sodCheckPassed() == null ? "" : o.sodCheckPassed().toString(),
              nz(o.sodViolations()), nz(o.ipAddress()), o.requestId());
        }
      }
      writer.flush();
      auditWrite.logSimple("AuditTrailExport", null, "EXPORT",
          "Export CSV audit-trail (" + ops.size() + " ops, scope=" + scope + ")");
      return out.toByteArray();
    } catch (IOException e) {
      throw new IllegalStateException("Export CSV échoué", e);
    }
  }

  /** XLSX via Apache POI. */
  public byte[] exportXlsx(String scope, UUID orgId, UUID userId, int limit) {
    List<AuditTrailOperationResponse> ops = queryService.listerRecentes(scope, orgId, userId, limit);
    try (XSSFWorkbook wb = new XSSFWorkbook();
         ByteArrayOutputStream out = new ByteArrayOutputStream()) {
      org.apache.poi.xssf.usermodel.XSSFSheet sheet = wb.createSheet("Audit Trail");

      CellStyle header = wb.createCellStyle();
      org.apache.poi.xssf.usermodel.XSSFFont fontH = wb.createFont();
      fontH.setBold(true);
      fontH.setColor(IndexedColors.WHITE.getIndex());
      header.setFont(fontH);
      header.setFillForegroundColor(IndexedColors.DARK_BLUE.getIndex());
      header.setFillPattern(org.apache.poi.ss.usermodel.FillPatternType.SOLID_FOREGROUND);

      Row headerRow = sheet.createRow(0);
      for (int i = 0; i < HEADERS.length; i++) {
        Cell cell = headerRow.createCell(i);
        cell.setCellValue(HEADERS[i]);
        cell.setCellStyle(header);
      }

      int r = 1;
      for (AuditTrailOperationResponse o : ops) {
        Row row = sheet.createRow(r++);
        row.createCell(0).setCellValue(fmt(o.operationAt()));
        row.createCell(1).setCellValue(nz(o.userEmail()));
        row.createCell(2).setCellValue(nz(o.roleActif()));
        row.createCell(3).setCellValue(o.organisationActiveId() == null ? "" : o.organisationActiveId().toString());
        row.createCell(4).setCellValue(nz(o.actionType()));
        row.createCell(5).setCellValue(nz(o.entityType()));
        row.createCell(6).setCellValue(o.entityId() == null ? "" : o.entityId().toString());
        row.createCell(7).setCellValue(nz(o.description()));
        row.createCell(8).setCellValue(o.sodCheckPassed() == null ? "" : o.sodCheckPassed().toString());
        row.createCell(9).setCellValue(nz(o.sodViolations()));
        row.createCell(10).setCellValue(nz(o.ipAddress()));
        row.createCell(11).setCellValue(o.requestId() == null ? "" : o.requestId().toString());
      }

      for (int i = 0; i < HEADERS.length; i++) sheet.autoSizeColumn(i);
      wb.write(out);
      auditWrite.logSimple("AuditTrailExport", null, "EXPORT",
          "Export XLSX audit-trail (" + ops.size() + " ops, scope=" + scope + ")");
      return out.toByteArray();
    } catch (IOException e) {
      throw new IllegalStateException("Export XLSX échoué", e);
    }
  }

  /** PDF via OpenPDF (page A4 paysage pour les colonnes larges). */
  public byte[] exportPdf(String scope, UUID orgId, UUID userId, int limit) {
    List<AuditTrailOperationResponse> ops = queryService.listerRecentes(scope, orgId, userId, limit);
    try (Document doc = new Document(PageSize.A4.rotate());
         ByteArrayOutputStream out = new ByteArrayOutputStream()) {
      PdfWriter.getInstance(doc, out);
      doc.open();

      Font titleFont = FontFactory.getFont(FontFactory.HELVETICA_BOLD, 14, Color.BLACK);
      Font headerFont = FontFactory.getFont(FontFactory.HELVETICA_BOLD, 9, Color.WHITE);
      Font rowFont = FontFactory.getFont(FontFactory.HELVETICA, 8, Color.BLACK);

      Paragraph title = new Paragraph(
          "Audit Trail UnionFlow — Export " + LocalDateTime.now().format(DT_FMT)
              + "  (scope=" + scope + ", " + ops.size() + " opérations)", titleFont);
      title.setAlignment(Element.ALIGN_CENTER);
      title.setSpacingAfter(15);
      doc.add(title);

      PdfPTable table = new PdfPTable(7);
      table.setWidthPercentage(100);
      table.setWidths(new float[] {15, 18, 10, 12, 13, 12, 20});

      String[] cols = {"Quand", "Acteur", "Rôle", "Action", "Entité", "SoD", "Description"};
      Color headerBg = new Color(20, 80, 150);
      for (String c : cols) {
        PdfPCell cell = new PdfPCell(new Phrase(c, headerFont));
        cell.setBackgroundColor(headerBg);
        cell.setPadding(5);
        table.addCell(cell);
      }

      for (AuditTrailOperationResponse o : ops) {
        addCell(table, fmt(o.operationAt()), rowFont);
        addCell(table, nz(o.userEmail()), rowFont);
        addCell(table, nz(o.roleActif()), rowFont);
        addCell(table, nz(o.actionType()), rowFont);
        addCell(table, nz(o.entityType()), rowFont);
        addCell(table, o.sodCheckPassed() == null ? "—"
            : (o.sodCheckPassed() ? "OK" : "VIOLATION"), rowFont);
        addCell(table, truncate(nz(o.description()), 120), rowFont);
      }

      doc.add(table);
      doc.close();

      auditWrite.logSimple("AuditTrailExport", null, "EXPORT",
          "Export PDF audit-trail (" + ops.size() + " ops, scope=" + scope + ")");
      return out.toByteArray();
    } catch (IOException e) {
      throw new IllegalStateException("Export PDF échoué", e);
    }
  }

  // ── Helpers ───────────────────────────────────────────────────────────

  private void addCell(PdfPTable t, String content, Font f) {
    PdfPCell cell = new PdfPCell(new Phrase(content, f));
    cell.setPadding(3);
    t.addCell(cell);
  }

  static String fmt(LocalDateTime dt) { return dt == null ? "" : dt.format(DT_FMT); }
  static String nz(String s) { return s == null ? "" : s; }
  static String truncate(String s, int max) {
    if (s == null) return "";
    return s.length() <= max ? s : s.substring(0, max - 1) + "…";
  }
}
