package {{ base_package }}

import (
    {%- for import_item in imports %}
    "{{ import_item }}"
    {%- endfor %}
    {%- if json_annotation %}
    "encoding/json"
    {%- endif %}
    {%- if json_annotation or avro_annotation %}
    "compress/gzip"
    "bytes"
    "fmt"
    "io"
    "strings"
    {%- endif %}
    {%- if avro_annotation %}
    "github.com/hamba/avro/v2"
    {%- endif %}
    {%- for ref_pkg in referenced_packages %}
    "{{ ref_pkg }}"
    {%- endfor %}
)

{%- if doc %}
// {{ doc }}
{%- endif %}
type {{ struct_name }} struct {
    {%- for field in fields %}
    {{ field.name }} {{ field.type }}{% if json_annotation or avro_annotation %} `{%- if json_annotation -%}json:"{{ field.original_name }}"{%- endif -%}{%- if avro_annotation %} avro:"{{ field.original_name }}"{%- endif -%}`{% endif %}
    {%- endfor %}
}

{%- if base_interface %}

// Verify that {{ struct_name }} implements {{ base_interface }} interface
var _ {{ base_interface }} = (*{{ struct_name }})(nil)

{%- for field in fields %}

// Get{{ field.name }} returns the {{ field.original_name }} field
func (s *{{ struct_name }}) Get{{ field.name }}() {{ field.type }} {
    return s.{{ field.name }}
}

// Set{{ field.name }} sets the {{ field.original_name }} field
func (s *{{ struct_name }}) Set{{ field.name }}(value {{ field.type }}) {
    s.{{ field.name }} = value
}
{%- endfor %}
{%- endif %}

{%- if avro_annotation and avro_schema %}

// AvroSchema is the embedded Avro schema for {{ struct_name }}
const {{ struct_name }}AvroSchema = `{{ avro_schema }}`

// GetAvroSchema returns the parsed Avro schema for {{ struct_name }}
func (s *{{ struct_name }}) GetAvroSchema() (avro.Schema, error) {
    return avro.Parse({{ struct_name }}AvroSchema)
}
{%- endif %}

{%- if json_annotation or avro_annotation %}
func (s *{{ struct_name }}) ToByteArray(contentType string) ([]byte, error) {
    var result []byte
    var err error
    
    // Strip +gzip suffix to get the base media type
    mediaType := strings.Split(contentType, ";")[0]
    isGzipped := strings.HasSuffix(mediaType, "+gzip")
    if isGzipped {
        mediaType = strings.TrimSuffix(mediaType, "+gzip")
    }
    
    switch mediaType {
    {%- if json_annotation %}
    case "application/json":
        result, err = json.Marshal(s)
        if err != nil {
            return nil, err
        }
    {%- endif %}
    {%- if avro_annotation %}
    case "avro/binary", "application/vnd.apache.avro+avro":
        schema, err := s.GetAvroSchema()
        if err != nil {
            return nil, fmt.Errorf("failed to parse Avro schema: %w", err)
        }
        result, err = avro.Marshal(schema, s)
        if err != nil {
            return nil, fmt.Errorf("failed to marshal Avro: %w", err)
        }
    {%- endif %}
    default:
        return nil, fmt.Errorf("unsupported media type: %s", mediaType)
    }
    
    if isGzipped {
        var buf bytes.Buffer
        gzipWriter := gzip.NewWriter(&buf)
        _, err = gzipWriter.Write(result)
        if err != nil {
            return nil, err
        }
        err = gzipWriter.Close()
        if err != nil {
            return nil, err
        }
        result = buf.Bytes()
    }
    return result, nil
}

func {{ struct_name }}FromData(data interface{}, contentType string) (*{{ struct_name }}, error) {
    var err error
    var s {{ struct_name }}
    
    // Strip +gzip suffix to get the base media type
    mediaType := strings.Split(contentType, ";")[0]
    isGzipped := strings.HasSuffix(mediaType, "+gzip")
    if isGzipped {
        mediaType = strings.TrimSuffix(mediaType, "+gzip")
    }
    
    if isGzipped {
        var reader io.Reader
        switch v := data.(type) {
        case []byte:
            reader = bytes.NewReader(v)
        case io.Reader:
            reader = v
        default:
            return nil, fmt.Errorf("unsupported data type for gzip: %T", data)
        }
        gzipReader, err := gzip.NewReader(reader)
        if err != nil {
            return nil, err
        }
        defer gzipReader.Close()
        data, err = io.ReadAll(gzipReader)
        if err != nil {
            return nil, err
        }
    }
    
    switch mediaType {
    {%- if json_annotation %}
    case "application/json":
        switch v := data.(type) {
        case []byte:
            err = json.Unmarshal(v, &s)
        case string:
            err = json.Unmarshal([]byte(v), &s)
        case io.Reader:
            err = json.NewDecoder(v).Decode(&s)
        default:
            return nil, fmt.Errorf("unsupported data type for JSON: %T", data)
        }
    {%- endif %}
    {%- if avro_annotation %}
    case "avro/binary", "application/vnd.apache.avro+avro":
        var tempInstance {{ struct_name }}
        schema, schemaErr := tempInstance.GetAvroSchema()
        if schemaErr != nil {
            return nil, fmt.Errorf("failed to parse Avro schema: %w", schemaErr)
        }
        switch v := data.(type) {
        case []byte:
            err = avro.Unmarshal(schema, v, &s)
        default:
            return nil, fmt.Errorf("unsupported data type for Avro: %T", data)
        }
    {%- endif %}
    default:
        return nil, fmt.Errorf("unsupported media type: %s", mediaType)
    }
    if err != nil {
        return nil, err
    }
    return &s, nil
}
{%- endif %}

func (s *{{ struct_name }}) ToObject() interface{} {
    return s
}
