// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
// Code generated by Microsoft (R) TypeSpec Code Generator.

package tsptest.armstreamstyleserialization.models;

import com.azure.core.annotation.Immutable;
import com.azure.core.util.CoreUtils;
import com.azure.core.util.logging.ClientLogger;
import com.azure.json.JsonReader;
import com.azure.json.JsonSerializable;
import com.azure.json.JsonToken;
import com.azure.json.JsonWriter;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDate;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * The Builtin model.
 */
@Immutable
public final class Builtin implements JsonSerializable<Builtin> {
    /*
     * The boolean property.
     */
    private boolean booleanProperty;

    /*
     * The string property.
     */
    private String string;

    /*
     * The bytes property.
     */
    private byte[] bytes;

    /*
     * The int property.
     */
    private int intProperty;

    /*
     * The safeint property.
     */
    private long safeint;

    /*
     * The decimal property.
     */
    private BigDecimal decimal;

    /*
     * The long property.
     */
    private long longProperty;

    /*
     * The float property.
     */
    private double floatProperty;

    /*
     * The double property.
     */
    private double doubleProperty;

    /*
     * The duration property.
     */
    private Duration duration;

    /*
     * The date property.
     */
    private LocalDate date;

    /*
     * The dateTime property.
     */
    private OffsetDateTime dateTime;

    /*
     * The stringList property.
     */
    private List<String> stringList;

    /*
     * The bytesDict property.
     */
    private Map<String, byte[]> bytesDict;

    /*
     * The url property.
     */
    private String url;

    /*
     * The nullableFloatDict property.
     */
    private Map<String, Double> nullableFloatDict;

    /*
     * The encoded property.
     */
    private Encoded encoded;

    /*
     * The uuid property.
     */
    private String uuid;

    /**
     * Creates an instance of Builtin class.
     */
    private Builtin() {
    }

    /**
     * Get the booleanProperty property: The boolean property.
     * 
     * @return the booleanProperty value.
     */
    public boolean booleanProperty() {
        return this.booleanProperty;
    }

    /**
     * Get the string property: The string property.
     * 
     * @return the string value.
     */
    public String string() {
        return this.string;
    }

    /**
     * Get the bytes property: The bytes property.
     * 
     * @return the bytes value.
     */
    public byte[] bytes() {
        return CoreUtils.clone(this.bytes);
    }

    /**
     * Get the intProperty property: The int property.
     * 
     * @return the intProperty value.
     */
    public int intProperty() {
        return this.intProperty;
    }

    /**
     * Get the safeint property: The safeint property.
     * 
     * @return the safeint value.
     */
    public long safeint() {
        return this.safeint;
    }

    /**
     * Get the decimal property: The decimal property.
     * 
     * @return the decimal value.
     */
    public BigDecimal decimal() {
        return this.decimal;
    }

    /**
     * Get the longProperty property: The long property.
     * 
     * @return the longProperty value.
     */
    public long longProperty() {
        return this.longProperty;
    }

    /**
     * Get the floatProperty property: The float property.
     * 
     * @return the floatProperty value.
     */
    public double floatProperty() {
        return this.floatProperty;
    }

    /**
     * Get the doubleProperty property: The double property.
     * 
     * @return the doubleProperty value.
     */
    public double doubleProperty() {
        return this.doubleProperty;
    }

    /**
     * Get the duration property: The duration property.
     * 
     * @return the duration value.
     */
    public Duration duration() {
        return this.duration;
    }

    /**
     * Get the date property: The date property.
     * 
     * @return the date value.
     */
    public LocalDate date() {
        return this.date;
    }

    /**
     * Get the dateTime property: The dateTime property.
     * 
     * @return the dateTime value.
     */
    public OffsetDateTime dateTime() {
        return this.dateTime;
    }

    /**
     * Get the stringList property: The stringList property.
     * 
     * @return the stringList value.
     */
    public List<String> stringList() {
        return this.stringList;
    }

    /**
     * Get the bytesDict property: The bytesDict property.
     * 
     * @return the bytesDict value.
     */
    public Map<String, byte[]> bytesDict() {
        return this.bytesDict;
    }

    /**
     * Get the url property: The url property.
     * 
     * @return the url value.
     */
    public String url() {
        return this.url;
    }

    /**
     * Get the nullableFloatDict property: The nullableFloatDict property.
     * 
     * @return the nullableFloatDict value.
     */
    public Map<String, Double> nullableFloatDict() {
        return this.nullableFloatDict;
    }

    /**
     * Get the encoded property: The encoded property.
     * 
     * @return the encoded value.
     */
    public Encoded encoded() {
        return this.encoded;
    }

    /**
     * Get the uuid property: The uuid property.
     * 
     * @return the uuid value.
     */
    public String uuid() {
        return this.uuid;
    }

    /**
     * Validates the instance.
     * 
     * @throws IllegalArgumentException thrown if the instance is not valid.
     */
    public void validate() {
        if (string() == null) {
            throw LOGGER.atError()
                .log(new IllegalArgumentException("Missing required property string in model Builtin"));
        }
        if (bytes() == null) {
            throw LOGGER.atError()
                .log(new IllegalArgumentException("Missing required property bytes in model Builtin"));
        }
        if (decimal() == null) {
            throw LOGGER.atError()
                .log(new IllegalArgumentException("Missing required property decimal in model Builtin"));
        }
        if (duration() == null) {
            throw LOGGER.atError()
                .log(new IllegalArgumentException("Missing required property duration in model Builtin"));
        }
        if (date() == null) {
            throw LOGGER.atError().log(new IllegalArgumentException("Missing required property date in model Builtin"));
        }
        if (dateTime() == null) {
            throw LOGGER.atError()
                .log(new IllegalArgumentException("Missing required property dateTime in model Builtin"));
        }
        if (stringList() == null) {
            throw LOGGER.atError()
                .log(new IllegalArgumentException("Missing required property stringList in model Builtin"));
        }
        if (bytesDict() == null) {
            throw LOGGER.atError()
                .log(new IllegalArgumentException("Missing required property bytesDict in model Builtin"));
        }
        if (url() == null) {
            throw LOGGER.atError().log(new IllegalArgumentException("Missing required property url in model Builtin"));
        }
        if (nullableFloatDict() == null) {
            throw LOGGER.atError()
                .log(new IllegalArgumentException("Missing required property nullableFloatDict in model Builtin"));
        }
        if (encoded() == null) {
            throw LOGGER.atError()
                .log(new IllegalArgumentException("Missing required property encoded in model Builtin"));
        } else {
            encoded().validate();
        }
        if (uuid() == null) {
            throw LOGGER.atError().log(new IllegalArgumentException("Missing required property uuid in model Builtin"));
        }
    }

    private static final ClientLogger LOGGER = new ClientLogger(Builtin.class);

    /**
     * {@inheritDoc}
     */
    @Override
    public JsonWriter toJson(JsonWriter jsonWriter) throws IOException {
        jsonWriter.writeStartObject();
        jsonWriter.writeBooleanField("boolean", this.booleanProperty);
        jsonWriter.writeStringField("string", this.string);
        jsonWriter.writeBinaryField("bytes", this.bytes);
        jsonWriter.writeIntField("int", this.intProperty);
        jsonWriter.writeLongField("safeint", this.safeint);
        jsonWriter.writeNumberField("decimal", this.decimal);
        jsonWriter.writeLongField("long", this.longProperty);
        jsonWriter.writeDoubleField("float", this.floatProperty);
        jsonWriter.writeDoubleField("double", this.doubleProperty);
        jsonWriter.writeStringField("duration", CoreUtils.durationToStringWithDays(this.duration));
        jsonWriter.writeStringField("date", Objects.toString(this.date, null));
        jsonWriter.writeStringField("dateTime",
            this.dateTime == null ? null : DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(this.dateTime));
        jsonWriter.writeArrayField("stringList", this.stringList, (writer, element) -> writer.writeString(element));
        jsonWriter.writeMapField("bytesDict", this.bytesDict, (writer, element) -> writer.writeBinary(element));
        jsonWriter.writeStringField("url", this.url);
        jsonWriter.writeMapField("nullableFloatDict", this.nullableFloatDict,
            (writer, element) -> writer.writeNumber(element));
        jsonWriter.writeJsonField("encoded", this.encoded);
        jsonWriter.writeStringField("uuid", this.uuid);
        return jsonWriter.writeEndObject();
    }

    /**
     * Reads an instance of Builtin from the JsonReader.
     * 
     * @param jsonReader The JsonReader being read.
     * @return An instance of Builtin if the JsonReader was pointing to an instance of it, or null if it was pointing to
     * JSON null.
     * @throws IllegalStateException If the deserialized JSON object was missing any required properties.
     * @throws IOException If an error occurs while reading the Builtin.
     */
    public static Builtin fromJson(JsonReader jsonReader) throws IOException {
        return jsonReader.readObject(reader -> {
            Builtin deserializedBuiltin = new Builtin();
            while (reader.nextToken() != JsonToken.END_OBJECT) {
                String fieldName = reader.getFieldName();
                reader.nextToken();

                if ("boolean".equals(fieldName)) {
                    deserializedBuiltin.booleanProperty = reader.getBoolean();
                } else if ("string".equals(fieldName)) {
                    deserializedBuiltin.string = reader.getString();
                } else if ("bytes".equals(fieldName)) {
                    deserializedBuiltin.bytes = reader.getBinary();
                } else if ("int".equals(fieldName)) {
                    deserializedBuiltin.intProperty = reader.getInt();
                } else if ("safeint".equals(fieldName)) {
                    deserializedBuiltin.safeint = reader.getLong();
                } else if ("decimal".equals(fieldName)) {
                    deserializedBuiltin.decimal
                        = reader.getNullable(nonNullReader -> new BigDecimal(nonNullReader.getString()));
                } else if ("long".equals(fieldName)) {
                    deserializedBuiltin.longProperty = reader.getLong();
                } else if ("float".equals(fieldName)) {
                    deserializedBuiltin.floatProperty = reader.getDouble();
                } else if ("double".equals(fieldName)) {
                    deserializedBuiltin.doubleProperty = reader.getDouble();
                } else if ("duration".equals(fieldName)) {
                    deserializedBuiltin.duration
                        = reader.getNullable(nonNullReader -> Duration.parse(nonNullReader.getString()));
                } else if ("date".equals(fieldName)) {
                    deserializedBuiltin.date
                        = reader.getNullable(nonNullReader -> LocalDate.parse(nonNullReader.getString()));
                } else if ("dateTime".equals(fieldName)) {
                    deserializedBuiltin.dateTime = reader
                        .getNullable(nonNullReader -> CoreUtils.parseBestOffsetDateTime(nonNullReader.getString()));
                } else if ("stringList".equals(fieldName)) {
                    List<String> stringList = reader.readArray(reader1 -> reader1.getString());
                    deserializedBuiltin.stringList = stringList;
                } else if ("bytesDict".equals(fieldName)) {
                    Map<String, byte[]> bytesDict = reader.readMap(reader1 -> reader1.getBinary());
                    deserializedBuiltin.bytesDict = bytesDict;
                } else if ("url".equals(fieldName)) {
                    deserializedBuiltin.url = reader.getString();
                } else if ("nullableFloatDict".equals(fieldName)) {
                    Map<String, Double> nullableFloatDict
                        = reader.readMap(reader1 -> reader1.getNullable(JsonReader::getDouble));
                    deserializedBuiltin.nullableFloatDict = nullableFloatDict;
                } else if ("encoded".equals(fieldName)) {
                    deserializedBuiltin.encoded = Encoded.fromJson(reader);
                } else if ("uuid".equals(fieldName)) {
                    deserializedBuiltin.uuid = reader.getString();
                } else {
                    reader.skipChildren();
                }
            }

            return deserializedBuiltin;
        });
    }
}
