// This file is auto-generated by alef — DO NOT EDIT.
// alef:hash:4e15143f4af1ae8bafbdb1506ef057da924484c66a19483966333558ad437e75
// To regenerate: alef generate
// To verify freshness: alef verify --exit-code
// Issues & docs: https://github.com/kreuzberg-dev/alef
#nullable enable

using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace Kreuzberg;

/// <summary>
/// Format-specific metadata (discriminated union).
///
/// Only one format type can exist per extraction result. This provides
/// type-safe, clean metadata without nested optionals.
/// </summary>
    [JsonConverter(typeof(FormatMetadataJsonConverter))]
public abstract record FormatMetadata
{
    public sealed record Pdf(
        PdfMetadata Value
    ) : FormatMetadata;

    public sealed record Docx(
        DocxMetadata Value
    ) : FormatMetadata;

    public sealed record Excel(
        ExcelMetadata Value
    ) : FormatMetadata;

    public sealed record Email(
        EmailMetadata Value
    ) : FormatMetadata;

    public sealed record Pptx(
        PptxMetadata Value
    ) : FormatMetadata;

    public sealed record Archive(
        ArchiveMetadata Value
    ) : FormatMetadata;

    public sealed record Image(
        ImageMetadata Value
    ) : FormatMetadata;

    public sealed record Xml(
        XmlMetadata Value
    ) : FormatMetadata;

    public sealed record Text(
        TextMetadata Value
    ) : FormatMetadata;

    public sealed record Html(
        HtmlMetadata Value
    ) : FormatMetadata;

    public sealed record Ocr(
        OcrMetadata Value
    ) : FormatMetadata;

    public sealed record Csv(
        CsvMetadata Value
    ) : FormatMetadata;

    public sealed record Bibtex(
        BibtexMetadata Value
    ) : FormatMetadata;

    public sealed record Citation(
        CitationMetadata Value
    ) : FormatMetadata;

    public sealed record FictionBook(
        FictionBookMetadata Value
    ) : FormatMetadata;

    public sealed record Dbf(
        DbfMetadata Value
    ) : FormatMetadata;

    public sealed record Jats(
        JatsMetadata Value
    ) : FormatMetadata;

    public sealed record Epub(
        EpubMetadata Value
    ) : FormatMetadata;

    public sealed record Pst(
        PstMetadata Value
    ) : FormatMetadata;

    public sealed record Code(
        object Value
    ) : FormatMetadata;

    /// <summary>Returns the Pdf data if this is a Pdf variant, otherwise null.</summary>
    public PdfMetadata? AsPdf => this is Pdf e ? e.Value : null;

    /// <summary>Returns the Docx data if this is a Docx variant, otherwise null.</summary>
    public DocxMetadata? AsDocx => this is Docx e ? e.Value : null;

    /// <summary>Returns the Excel data if this is a Excel variant, otherwise null.</summary>
    public ExcelMetadata? AsExcel => this is Excel e ? e.Value : null;

    /// <summary>Returns the Email data if this is a Email variant, otherwise null.</summary>
    public EmailMetadata? AsEmail => this is Email e ? e.Value : null;

    /// <summary>Returns the Pptx data if this is a Pptx variant, otherwise null.</summary>
    public PptxMetadata? AsPptx => this is Pptx e ? e.Value : null;

    /// <summary>Returns the Archive data if this is a Archive variant, otherwise null.</summary>
    public ArchiveMetadata? AsArchive => this is Archive e ? e.Value : null;

    /// <summary>Returns the Image data if this is a Image variant, otherwise null.</summary>
    public ImageMetadata? AsImage => this is Image e ? e.Value : null;

    /// <summary>Returns the Xml data if this is a Xml variant, otherwise null.</summary>
    public XmlMetadata? AsXml => this is Xml e ? e.Value : null;

    /// <summary>Returns the Text data if this is a Text variant, otherwise null.</summary>
    public TextMetadata? AsText => this is Text e ? e.Value : null;

    /// <summary>Returns the Html data if this is a Html variant, otherwise null.</summary>
    public HtmlMetadata? AsHtml => this is Html e ? e.Value : null;

    /// <summary>Returns the Ocr data if this is a Ocr variant, otherwise null.</summary>
    public OcrMetadata? AsOcr => this is Ocr e ? e.Value : null;

    /// <summary>Returns the Csv data if this is a Csv variant, otherwise null.</summary>
    public CsvMetadata? AsCsv => this is Csv e ? e.Value : null;

    /// <summary>Returns the Bibtex data if this is a Bibtex variant, otherwise null.</summary>
    public BibtexMetadata? AsBibtex => this is Bibtex e ? e.Value : null;

    /// <summary>Returns the Citation data if this is a Citation variant, otherwise null.</summary>
    public CitationMetadata? AsCitation => this is Citation e ? e.Value : null;

    /// <summary>Returns the FictionBook data if this is a FictionBook variant, otherwise null.</summary>
    public FictionBookMetadata? AsFictionBook => this is FictionBook e ? e.Value : null;

    /// <summary>Returns the Dbf data if this is a Dbf variant, otherwise null.</summary>
    public DbfMetadata? AsDbf => this is Dbf e ? e.Value : null;

    /// <summary>Returns the Jats data if this is a Jats variant, otherwise null.</summary>
    public JatsMetadata? AsJats => this is Jats e ? e.Value : null;

    /// <summary>Returns the Epub data if this is a Epub variant, otherwise null.</summary>
    public EpubMetadata? AsEpub => this is Epub e ? e.Value : null;

    /// <summary>Returns the Pst data if this is a Pst variant, otherwise null.</summary>
    public PstMetadata? AsPst => this is Pst e ? e.Value : null;

    /// <summary>Returns the Code data if this is a Code variant, otherwise null.</summary>
    public object? AsCode => this is Code e ? e.Value : null;

}

/// <summary>
/// Custom converter for FormatMetadata sealed union with flattened variant fields.
/// </summary>
/// <remarks>
/// Handles JSON objects with a discriminator field (format_type) and variant-specific
/// fields at the same level. System.Text.Json's [JsonPolymorphic] cannot handle
/// this layout, so we manually deserialize here.
/// </remarks>
public sealed class FormatMetadataJsonConverter : JsonConverter<FormatMetadata>
{
    public override FormatMetadata Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        if (reader.TokenType != JsonTokenType.StartObject)
        {
            throw new JsonException($"Expected JSON object, got {reader.TokenType}");
        }

        using var doc = JsonDocument.ParseValue(ref reader);
        var root = doc.RootElement;

        if (!root.TryGetProperty("format_type", out var tagElement))
        {
            throw new JsonException($"Missing discriminator field: format_type");
        }

        var tagValue = tagElement.GetString();
        if (tagValue == null)
        {
            throw new JsonException("Discriminator field is null");
        }

        // Tuple-variant records (`Variant(InnerStruct value)`) expect a single
        // "Value" field holding the inner struct's JSON, so wrap the remaining
        // fields under "Value". Struct-variant records (`Variant { field1,
        // field2 }`) have positional record components annotated with
        // [JsonPropertyName(...)] for each named field, so pass the remaining
        // fields through directly without the wrap.
        using var ms = new MemoryStream();
        using var writer = new Utf8JsonWriter(ms);
        writer.WriteStartObject();
        foreach (var prop in root.EnumerateObject())
        {
            if (prop.Name != "format_type")
            {
                writer.WritePropertyName(prop.Name);
                prop.Value.WriteTo(writer);
            }
        }
        writer.WriteEndObject();
        writer.Flush();
        ms.Position = 0;
        var flatJson = ms.ToArray();

        using var msWrapped = new MemoryStream();
        using var writerWrapped = new Utf8JsonWriter(msWrapped);
        writerWrapped.WriteStartObject();
        writerWrapped.WritePropertyName("Value");
        writerWrapped.WriteStartObject();
        foreach (var prop in root.EnumerateObject())
        {
            if (prop.Name != "format_type")
            {
                writerWrapped.WritePropertyName(prop.Name);
                prop.Value.WriteTo(writerWrapped);
            }
        }
        writerWrapped.WriteEndObject();
        writerWrapped.WriteEndObject();
        writerWrapped.Flush();
        msWrapped.Position = 0;
        var wrappedJson = msWrapped.ToArray();

        return tagValue switch
        {            "pdf" => JsonSerializer.Deserialize<FormatMetadata.Pdf>(wrappedJson, options) ?? throw new JsonException("Failed to deserialize variant"),            "docx" => JsonSerializer.Deserialize<FormatMetadata.Docx>(wrappedJson, options) ?? throw new JsonException("Failed to deserialize variant"),            "excel" => JsonSerializer.Deserialize<FormatMetadata.Excel>(wrappedJson, options) ?? throw new JsonException("Failed to deserialize variant"),            "email" => JsonSerializer.Deserialize<FormatMetadata.Email>(wrappedJson, options) ?? throw new JsonException("Failed to deserialize variant"),            "pptx" => JsonSerializer.Deserialize<FormatMetadata.Pptx>(wrappedJson, options) ?? throw new JsonException("Failed to deserialize variant"),            "archive" => JsonSerializer.Deserialize<FormatMetadata.Archive>(wrappedJson, options) ?? throw new JsonException("Failed to deserialize variant"),            "image" => JsonSerializer.Deserialize<FormatMetadata.Image>(wrappedJson, options) ?? throw new JsonException("Failed to deserialize variant"),            "xml" => JsonSerializer.Deserialize<FormatMetadata.Xml>(wrappedJson, options) ?? throw new JsonException("Failed to deserialize variant"),            "text" => JsonSerializer.Deserialize<FormatMetadata.Text>(wrappedJson, options) ?? throw new JsonException("Failed to deserialize variant"),            "html" => JsonSerializer.Deserialize<FormatMetadata.Html>(wrappedJson, options) ?? throw new JsonException("Failed to deserialize variant"),            "ocr" => JsonSerializer.Deserialize<FormatMetadata.Ocr>(wrappedJson, options) ?? throw new JsonException("Failed to deserialize variant"),            "csv" => JsonSerializer.Deserialize<FormatMetadata.Csv>(wrappedJson, options) ?? throw new JsonException("Failed to deserialize variant"),            "bibtex" => JsonSerializer.Deserialize<FormatMetadata.Bibtex>(wrappedJson, options) ?? throw new JsonException("Failed to deserialize variant"),            "citation" => JsonSerializer.Deserialize<FormatMetadata.Citation>(wrappedJson, options) ?? throw new JsonException("Failed to deserialize variant"),            "fiction_book" => JsonSerializer.Deserialize<FormatMetadata.FictionBook>(wrappedJson, options) ?? throw new JsonException("Failed to deserialize variant"),            "dbf" => JsonSerializer.Deserialize<FormatMetadata.Dbf>(wrappedJson, options) ?? throw new JsonException("Failed to deserialize variant"),            "jats" => JsonSerializer.Deserialize<FormatMetadata.Jats>(wrappedJson, options) ?? throw new JsonException("Failed to deserialize variant"),            "epub" => JsonSerializer.Deserialize<FormatMetadata.Epub>(wrappedJson, options) ?? throw new JsonException("Failed to deserialize variant"),            "pst" => JsonSerializer.Deserialize<FormatMetadata.Pst>(wrappedJson, options) ?? throw new JsonException("Failed to deserialize variant"),            "code" => JsonSerializer.Deserialize<FormatMetadata.Code>(wrappedJson, options) ?? throw new JsonException("Failed to deserialize variant"),            _ => throw new JsonException($"Unknown FormatMetadata discriminator: {tagValue}")
        };
    }

    public override void Write(Utf8JsonWriter writer, FormatMetadata value, JsonSerializerOptions options)
    {
        // Emit the discriminator tag plus the inner variant's fields flattened at
        // the same level — mirrors the Java sealed-union serializer pattern. Turn
        // `Message.User(UserMessage value)` into `{"format_type":"user","content":...}`
        // not `{"value":{...}}`. Without this, sending a chat request to FFI fails
        // with "missing field format_type" inside Rust serde.
        string tag;
        object? inner;
        switch (value)
        {            case FormatMetadata.Pdf v_pdf:
                tag = "pdf";                inner = v_pdf.Value;                break;            case FormatMetadata.Docx v_docx:
                tag = "docx";                inner = v_docx.Value;                break;            case FormatMetadata.Excel v_excel:
                tag = "excel";                inner = v_excel.Value;                break;            case FormatMetadata.Email v_email:
                tag = "email";                inner = v_email.Value;                break;            case FormatMetadata.Pptx v_pptx:
                tag = "pptx";                inner = v_pptx.Value;                break;            case FormatMetadata.Archive v_archive:
                tag = "archive";                inner = v_archive.Value;                break;            case FormatMetadata.Image v_image:
                tag = "image";                inner = v_image.Value;                break;            case FormatMetadata.Xml v_xml:
                tag = "xml";                inner = v_xml.Value;                break;            case FormatMetadata.Text v_text:
                tag = "text";                inner = v_text.Value;                break;            case FormatMetadata.Html v_html:
                tag = "html";                inner = v_html.Value;                break;            case FormatMetadata.Ocr v_ocr:
                tag = "ocr";                inner = v_ocr.Value;                break;            case FormatMetadata.Csv v_csv:
                tag = "csv";                inner = v_csv.Value;                break;            case FormatMetadata.Bibtex v_bibtex:
                tag = "bibtex";                inner = v_bibtex.Value;                break;            case FormatMetadata.Citation v_citation:
                tag = "citation";                inner = v_citation.Value;                break;            case FormatMetadata.FictionBook v_fictionbook:
                tag = "fiction_book";                inner = v_fictionbook.Value;                break;            case FormatMetadata.Dbf v_dbf:
                tag = "dbf";                inner = v_dbf.Value;                break;            case FormatMetadata.Jats v_jats:
                tag = "jats";                inner = v_jats.Value;                break;            case FormatMetadata.Epub v_epub:
                tag = "epub";                inner = v_epub.Value;                break;            case FormatMetadata.Pst v_pst:
                tag = "pst";                inner = v_pst.Value;                break;            case FormatMetadata.Code v_code:
                tag = "code";                inner = v_code.Value;                break;            default:
                throw new JsonException($"Unknown FormatMetadata variant: {value.GetType().Name}");
        }

        writer.WriteStartObject();
        writer.WriteString("format_type", tag);
        if (inner != null)
        {
            using var doc = JsonSerializer.SerializeToDocument(inner, inner.GetType(), options);
            if (doc.RootElement.ValueKind == JsonValueKind.Object)
            {
                foreach (var prop in doc.RootElement.EnumerateObject())
                {
                    writer.WritePropertyName(prop.Name);
                    prop.Value.WriteTo(writer);
                }
            }
        }
        writer.WriteEndObject();
    }
}
