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

import dev.lions.unionflow.server.security.AuditTrailService;
import dev.lions.unionflow.server.service.centif.DosCentifService.DosCentifData;
import dev.lions.unionflow.server.service.centif.DosCentifService.DosOperation;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.time.format.DateTimeFormatter;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;

/**
 * Génération de DOS au format <strong>goAML XML</strong> (standard ONUDC) — anticipation de
 * l'adoption par la CENTIF Côte d'Ivoire.
 *
 * <p>goAML est l'application de l'Office des Nations Unies contre la Drogue et le Crime (ONUDC)
 * adoptée par 60+ FIU dans le monde (Belgique en 2024, Sénégal, etc.). La Côte d'Ivoire n'a pas
 * confirmé son adoption au 2026-04-25 mais la CENTIF coopère avec ONUDC. Préparer ce format
 * permettra une bascule sans douleur.
 *
 * <p>Schéma XML : sous-ensemble du <a
 * href="https://goaml.unodc.org/goaml/en/index.html">schéma goAML standard</a>. Implémentation
 * minimale conforme au noyau {@code Report} → {@code Transaction}.
 *
 * @since 2026-04-25 (P2-NEW-4)
 */
@ApplicationScoped
public class GoAmlXmlService {

  private static final DateTimeFormatter ISO = DateTimeFormatter.ISO_LOCAL_DATE;
  private static final DateTimeFormatter ISO_DT = DateTimeFormatter.ISO_LOCAL_DATE_TIME;

  @Inject AuditTrailService auditTrail;

  /** Génère un fichier XML goAML à partir des données DOS UnionFlow. */
  @Transactional
  public byte[] genererXml(DosCentifData data) throws IOException {
    if (data == null) throw new IllegalArgumentException("DosCentifData null");

    try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
      XMLStreamWriter w = XMLOutputFactory.newInstance().createXMLStreamWriter(out, "UTF-8");
      w.writeStartDocument("UTF-8", "1.0");

      w.writeStartElement("report");
      w.writeAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
      w.writeAttribute("xsi:noNamespaceSchemaLocation", "goAML_schema_5.0.1.xsd");

      writeElement(w, "rentity_id", data.numeroDosInterne());
      writeElement(w, "rentity_branch", data.institutionDenomination());
      writeElement(w, "submission_code", "E"); // E = Electronic
      writeElement(w, "report_code", "STR"); // STR = Suspicious Transaction Report
      writeElement(w, "submission_date",
          data.dateDeclaration() != null ? data.dateDeclaration().format(ISO_DT) : "");
      writeElement(w, "currency_code_local", "XOF");

      // Reporting person (anonymisé envers le procureur, identifié pour la CENTIF)
      w.writeStartElement("reporting_person");
      writeElement(w, "first_name", "[REDACTED]");
      writeElement(w, "last_name", "[REDACTED]");
      writeElement(w, "title", "Compliance Officer");
      writeElement(w, "phone", "");
      w.writeEndElement();

      // Location
      w.writeStartElement("location");
      writeElement(w, "address_type", "1");
      writeElement(w, "address", data.institutionAdresse() == null ? "—" : data.institutionAdresse());
      writeElement(w, "city", data.institutionVille() == null ? "—" : data.institutionVille());
      writeElement(w, "country_code", "CIV");
      w.writeEndElement();

      // Transactions
      if (data.operations() != null) {
        for (DosOperation op : data.operations()) {
          w.writeStartElement("transaction");
          writeElement(w, "transactionnumber", data.numeroDosInterne() + "-"
              + (op.date() != null ? op.date().format(ISO) : "n/a"));
          writeElement(w, "transaction_location", "");
          writeElement(w, "date_transaction", op.date() != null ? op.date().format(ISO) : "");
          writeElement(w, "transmode_code", op.typeOperation());
          writeElement(w, "amount_local", op.montant() != null ? op.montant().toPlainString() : "0");
          writeElement(w, "amount_other_currency", op.montant() != null ? op.montant().toPlainString() : "0");

          // Bénéficiaire (simplifié — goAML attend des structures plus riches)
          w.writeStartElement("t_to_my_client");
          writeElement(w, "to_funds_code", "K"); // K = others / cash equivalent
          w.writeStartElement("to_account");
          writeElement(w, "account_name", op.beneficiaire() == null ? "—" : op.beneficiaire());
          writeElement(w, "currency_code", op.devise() == null ? "XOF" : op.devise());
          w.writeEndElement();
          w.writeEndElement();

          w.writeEndElement(); // transaction
        }
      }

      writeElement(w, "report_indicators", data.motifsSoupcon() == null ? "—" : data.motifsSoupcon());
      writeElement(w, "reason", data.motifsSoupcon() == null ? "—" : data.motifsSoupcon());
      writeElement(w, "action", data.mesuresConservatoires() == null ? "—" : data.mesuresConservatoires());

      w.writeEndElement(); // report
      w.writeEndDocument();
      w.flush();
      w.close();

      auditTrail.logSimple("AlerteAml", data.alerteId(), "EXPORT",
          "Génération DOS goAML XML — N° " + data.numeroDosInterne());
      return out.toByteArray();
    } catch (XMLStreamException e) {
      throw new IOException("Erreur génération XML goAML : " + e.getMessage(), e);
    }
  }

  private void writeElement(XMLStreamWriter w, String name, String value) throws XMLStreamException {
    w.writeStartElement(name);
    w.writeCharacters(value == null ? "" : value);
    w.writeEndElement();
  }
}
