#!/usr/bin/perl
use strict;
use warnings;
use Path::Tiny;

my @fragments = qw(
    lib/Protobuf/Arena.xs.part
    lib/Protobuf/DescriptorPool.xs.part
    lib/Protobuf/UnknownFieldSet.xs.part
    lib/Protobuf/Message.xs.part
    lib/Protobuf/Internal.xs.part
    lib/Protobuf/Internal/Map.xs.part
    lib/Protobuf/Internal/Repeated.xs.part
    lib/Protobuf/Internal/MapIterator.xs.part
    lib/Protobuf/Descriptor/Field.xs.part
    lib/Protobuf/Descriptor/OneofDef.xs.part
    lib/Protobuf/Descriptor/File.xs.part
    lib/Protobuf/Descriptor/MessageDef.xs.part
    lib/Protobuf/Descriptor/Enum.xs.part
    lib/Protobuf/Descriptor/EnumValue.xs.part
);

my $header = <<'HEADER';
/*
 * GENERATED FILE - DO NOT EDIT
 * This file is generated by generate_xs.pl from .xs.part fragments.
 */

#define PERL_NO_GET_CONTEXT
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "xs/protobuf.h"
#include "xs/protobuf/arena.h"
#include "xs/protobuf/utils.h"
#include "xs/protobuf/registry.h"
#include "xs/protobuf/message.h"
#include "xs/all_descriptors.h"
#include "xs/descriptor/message.h"
#include "xs/unknown_fields/set.h"
#include "xs/message/meta.h"
#include "xs/map/map.h"
#include "xs/map/iterator.h"
#include "xs/repeated/repeated.h"

#define GET_FIELD_DEF_OR_CROAK(mdef, field_name, fdef_var) \
    const upb_FieldDef* fdef_var = upb_MessageDef_FindFieldByName(mdef, field_name); \
    if (!fdef_var) { \
        croak("Field '%s' not found in message '%s'", field_name, upb_MessageDef_FullName(mdef)); \
    }

HEADER

my $body = "";
foreach my $frag (@fragments) {
    if (-f "$frag") {
        my $content = path("$frag")->slurp_utf8;
        # NO COMMENTS AT ALL between fragments? xsubpp is extremely picky.
        $body .= "\n\n";
        $body .= $content;
    } else {
        warn "Warning: XS fragment $frag not found\n";
    }
}

my $footer = <<'FOOTER';

MODULE = Protobuf  PACKAGE = Protobuf
PROTOTYPES: ENABLE

BOOT:
    PerlUpb_DetectCpuFeatures();
    PerlUpb_Protobuf_InitModule(aTHX);

void
_install_fast_accessors(perl_class, mdef_sv)
    const char* perl_class
    SV* mdef_sv
    CODE:
        const upb_MessageDef* mdef = PerlUpb_MessageDef_GetMessage(aTHX_ mdef_sv);
        if (!mdef) croak("Invalid MessageDef");
        PerlUpb_InstallFastAccessors(aTHX_ perl_class, mdef);

FOOTER

path("Protobuf.xs")->spew_utf8($header . $body . $footer);
print "Successfully generated Protobuf.xs\n";
