// 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.Fluent;
import com.azure.core.util.Base64Url;
import com.azure.core.util.CoreUtils;
import com.azure.core.util.DateTimeRfc1123;
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.time.Duration;
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Objects;

/**
 * The Encoded model.
 */
@Fluent
public final class Encoded implements JsonSerializable<Encoded> {
    private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];

    /*
     * The timeInSeconds property.
     */
    private Long timeInSeconds;

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

    /*
     * The timeInSecondsFraction property.
     */
    private Double timeInSecondsFraction;

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

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

    /*
     * The dateTimeRfc7231 property.
     */
    private DateTimeRfc1123 dateTimeRfc7231;

    /*
     * The unixTimestamp property.
     */
    private Long unixTimestamp;

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

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

    /*
     * The base64url property.
     */
    private Base64Url base64url;

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

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

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

    /**
     * Creates an instance of Encoded class.
     */
    public Encoded() {
    }

    /**
     * Get the timeInSeconds property: The timeInSeconds property.
     * 
     * @return the timeInSeconds value.
     */
    public Duration timeInSeconds() {
        if (this.timeInSeconds == null) {
            return null;
        }
        return Duration.ofSeconds(this.timeInSeconds);
    }

    /**
     * Set the timeInSeconds property: The timeInSeconds property.
     * 
     * @param timeInSeconds the timeInSeconds value to set.
     * @return the Encoded object itself.
     */
    public Encoded withTimeInSeconds(Duration timeInSeconds) {
        if (timeInSeconds == null) {
            this.timeInSeconds = null;
        } else {
            this.timeInSeconds = timeInSeconds.getSeconds();
        }
        return this;
    }

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

    /**
     * Set the timeInSecondsPrimitive property: The timeInSecondsPrimitive property.
     * 
     * @param timeInSecondsPrimitive the timeInSecondsPrimitive value to set.
     * @return the Encoded object itself.
     */
    public Encoded withTimeInSecondsPrimitive(Duration timeInSecondsPrimitive) {
        if (timeInSecondsPrimitive == null) {
            this.timeInSecondsPrimitive = 0L;
        } else {
            this.timeInSecondsPrimitive = timeInSecondsPrimitive.getSeconds();
        }
        return this;
    }

    /**
     * Get the timeInSecondsFraction property: The timeInSecondsFraction property.
     * 
     * @return the timeInSecondsFraction value.
     */
    public Duration timeInSecondsFraction() {
        if (this.timeInSecondsFraction == null) {
            return null;
        }
        return Duration.ofNanos((long) (this.timeInSecondsFraction * 1000_000_000L));
    }

    /**
     * Set the timeInSecondsFraction property: The timeInSecondsFraction property.
     * 
     * @param timeInSecondsFraction the timeInSecondsFraction value to set.
     * @return the Encoded object itself.
     */
    public Encoded withTimeInSecondsFraction(Duration timeInSecondsFraction) {
        if (timeInSecondsFraction == null) {
            this.timeInSecondsFraction = null;
        } else {
            this.timeInSecondsFraction = (double) timeInSecondsFraction.toNanos() / 1000_000_000L;
        }
        return this;
    }

    /**
     * Get the timeInSecondsFractionPrimitive property: The timeInSecondsFractionPrimitive property.
     * 
     * @return the timeInSecondsFractionPrimitive value.
     */
    public Duration timeInSecondsFractionPrimitive() {
        return Duration.ofNanos((long) (this.timeInSecondsFractionPrimitive * 1000_000_000L));
    }

    /**
     * Set the timeInSecondsFractionPrimitive property: The timeInSecondsFractionPrimitive property.
     * 
     * @param timeInSecondsFractionPrimitive the timeInSecondsFractionPrimitive value to set.
     * @return the Encoded object itself.
     */
    public Encoded withTimeInSecondsFractionPrimitive(Duration timeInSecondsFractionPrimitive) {
        if (timeInSecondsFractionPrimitive == null) {
            this.timeInSecondsFractionPrimitive = 0.0;
        } else {
            this.timeInSecondsFractionPrimitive = (double) timeInSecondsFractionPrimitive.toNanos() / 1000_000_000L;
        }
        return this;
    }

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

    /**
     * Set the dateTime property: The dateTime property.
     * 
     * @param dateTime the dateTime value to set.
     * @return the Encoded object itself.
     */
    public Encoded withDateTime(OffsetDateTime dateTime) {
        this.dateTime = dateTime;
        return this;
    }

    /**
     * Get the dateTimeRfc7231 property: The dateTimeRfc7231 property.
     * 
     * @return the dateTimeRfc7231 value.
     */
    public OffsetDateTime dateTimeRfc7231() {
        if (this.dateTimeRfc7231 == null) {
            return null;
        }
        return this.dateTimeRfc7231.getDateTime();
    }

    /**
     * Set the dateTimeRfc7231 property: The dateTimeRfc7231 property.
     * 
     * @param dateTimeRfc7231 the dateTimeRfc7231 value to set.
     * @return the Encoded object itself.
     */
    public Encoded withDateTimeRfc7231(OffsetDateTime dateTimeRfc7231) {
        if (dateTimeRfc7231 == null) {
            this.dateTimeRfc7231 = null;
        } else {
            this.dateTimeRfc7231 = new DateTimeRfc1123(dateTimeRfc7231);
        }
        return this;
    }

    /**
     * Get the unixTimestamp property: The unixTimestamp property.
     * 
     * @return the unixTimestamp value.
     */
    public OffsetDateTime unixTimestamp() {
        if (this.unixTimestamp == null) {
            return null;
        }
        return OffsetDateTime.ofInstant(Instant.ofEpochSecond(this.unixTimestamp), ZoneOffset.UTC);
    }

    /**
     * Set the unixTimestamp property: The unixTimestamp property.
     * 
     * @param unixTimestamp the unixTimestamp value to set.
     * @return the Encoded object itself.
     */
    public Encoded withUnixTimestamp(OffsetDateTime unixTimestamp) {
        if (unixTimestamp == null) {
            this.unixTimestamp = null;
        } else {
            this.unixTimestamp = unixTimestamp.toEpochSecond();
        }
        return this;
    }

    /**
     * Get the unixTimestampPrimitive property: The unixTimestampPrimitive property.
     * 
     * @return the unixTimestampPrimitive value.
     */
    public OffsetDateTime unixTimestampPrimitive() {
        return OffsetDateTime.ofInstant(Instant.ofEpochSecond(this.unixTimestampPrimitive), ZoneOffset.UTC);
    }

    /**
     * Set the unixTimestampPrimitive property: The unixTimestampPrimitive property.
     * 
     * @param unixTimestampPrimitive the unixTimestampPrimitive value to set.
     * @return the Encoded object itself.
     */
    public Encoded withUnixTimestampPrimitive(OffsetDateTime unixTimestampPrimitive) {
        if (unixTimestampPrimitive == null) {
            this.unixTimestampPrimitive = 0L;
        } else {
            this.unixTimestampPrimitive = unixTimestampPrimitive.toEpochSecond();
        }
        return this;
    }

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

    /**
     * Set the base64 property: The base64 property.
     * 
     * @param base64 the base64 value to set.
     * @return the Encoded object itself.
     */
    public Encoded withBase64(byte[] base64) {
        this.base64 = CoreUtils.clone(base64);
        return this;
    }

    /**
     * Get the base64url property: The base64url property.
     * 
     * @return the base64url value.
     */
    public byte[] base64url() {
        if (this.base64url == null) {
            return EMPTY_BYTE_ARRAY;
        }
        return this.base64url.decodedBytes();
    }

    /**
     * Set the base64url property: The base64url property.
     * 
     * @param base64url the base64url value to set.
     * @return the Encoded object itself.
     */
    public Encoded withBase64url(byte[] base64url) {
        if (base64url == null) {
            this.base64url = null;
        } else {
            this.base64url = Base64Url.encode(CoreUtils.clone(base64url));
        }
        return this;
    }

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

    /**
     * Set the unknownDurationFormat property: The unknownDurationFormat property.
     * 
     * @param unknownDurationFormat the unknownDurationFormat value to set.
     * @return the Encoded object itself.
     */
    public Encoded withUnknownDurationFormat(String unknownDurationFormat) {
        this.unknownDurationFormat = unknownDurationFormat;
        return this;
    }

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

    /**
     * Set the unknownDateTimeFormat property: The unknownDateTimeFormat property.
     * 
     * @param unknownDateTimeFormat the unknownDateTimeFormat value to set.
     * @return the Encoded object itself.
     */
    public Encoded withUnknownDateTimeFormat(String unknownDateTimeFormat) {
        this.unknownDateTimeFormat = unknownDateTimeFormat;
        return this;
    }

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

    /**
     * Set the unknownBytes property: The unknownBytes property.
     * 
     * @param unknownBytes the unknownBytes value to set.
     * @return the Encoded object itself.
     */
    public Encoded withUnknownBytes(String unknownBytes) {
        this.unknownBytes = unknownBytes;
        return this;
    }

    /**
     * Validates the instance.
     * 
     * @throws IllegalArgumentException thrown if the instance is not valid.
     */
    public void validate() {
        if (timeInSecondsPrimitive() == null) {
            throw LOGGER.atError()
                .log(new IllegalArgumentException("Missing required property timeInSecondsPrimitive in model Encoded"));
        }
        if (timeInSecondsFractionPrimitive() == null) {
            throw LOGGER.atError()
                .log(new IllegalArgumentException(
                    "Missing required property timeInSecondsFractionPrimitive in model Encoded"));
        }
        if (unixTimestampPrimitive() == null) {
            throw LOGGER.atError()
                .log(new IllegalArgumentException("Missing required property unixTimestampPrimitive in model Encoded"));
        }
    }

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

    /**
     * {@inheritDoc}
     */
    @Override
    public JsonWriter toJson(JsonWriter jsonWriter) throws IOException {
        jsonWriter.writeStartObject();
        jsonWriter.writeLongField("timeInSecondsPrimitive", this.timeInSecondsPrimitive);
        jsonWriter.writeDoubleField("timeInSecondsFractionPrimitive", this.timeInSecondsFractionPrimitive);
        jsonWriter.writeLongField("unixTimestampPrimitive", this.unixTimestampPrimitive);
        jsonWriter.writeNumberField("timeInSeconds", this.timeInSeconds);
        jsonWriter.writeNumberField("timeInSecondsFraction", this.timeInSecondsFraction);
        jsonWriter.writeStringField("dateTime",
            this.dateTime == null ? null : DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(this.dateTime));
        jsonWriter.writeStringField("dateTimeRfc7231", Objects.toString(this.dateTimeRfc7231, null));
        jsonWriter.writeNumberField("unixTimestamp", this.unixTimestamp);
        jsonWriter.writeBinaryField("base64", this.base64);
        jsonWriter.writeStringField("base64url", Objects.toString(this.base64url, null));
        jsonWriter.writeStringField("unknownDurationFormat", this.unknownDurationFormat);
        jsonWriter.writeStringField("unknownDateTimeFormat", this.unknownDateTimeFormat);
        jsonWriter.writeStringField("unknownBytes", this.unknownBytes);
        return jsonWriter.writeEndObject();
    }

    /**
     * Reads an instance of Encoded from the JsonReader.
     * 
     * @param jsonReader The JsonReader being read.
     * @return An instance of Encoded 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 Encoded.
     */
    public static Encoded fromJson(JsonReader jsonReader) throws IOException {
        return jsonReader.readObject(reader -> {
            Encoded deserializedEncoded = new Encoded();
            while (reader.nextToken() != JsonToken.END_OBJECT) {
                String fieldName = reader.getFieldName();
                reader.nextToken();

                if ("timeInSecondsPrimitive".equals(fieldName)) {
                    deserializedEncoded.timeInSecondsPrimitive = reader.getLong();
                } else if ("timeInSecondsFractionPrimitive".equals(fieldName)) {
                    deserializedEncoded.timeInSecondsFractionPrimitive = reader.getDouble();
                } else if ("unixTimestampPrimitive".equals(fieldName)) {
                    deserializedEncoded.unixTimestampPrimitive = reader.getLong();
                } else if ("timeInSeconds".equals(fieldName)) {
                    deserializedEncoded.timeInSeconds = reader.getNullable(JsonReader::getLong);
                } else if ("timeInSecondsFraction".equals(fieldName)) {
                    deserializedEncoded.timeInSecondsFraction = reader.getNullable(JsonReader::getDouble);
                } else if ("dateTime".equals(fieldName)) {
                    deserializedEncoded.dateTime = reader
                        .getNullable(nonNullReader -> CoreUtils.parseBestOffsetDateTime(nonNullReader.getString()));
                } else if ("dateTimeRfc7231".equals(fieldName)) {
                    deserializedEncoded.dateTimeRfc7231
                        = reader.getNullable(nonNullReader -> new DateTimeRfc1123(nonNullReader.getString()));
                } else if ("unixTimestamp".equals(fieldName)) {
                    deserializedEncoded.unixTimestamp = reader.getNullable(JsonReader::getLong);
                } else if ("base64".equals(fieldName)) {
                    deserializedEncoded.base64 = reader.getBinary();
                } else if ("base64url".equals(fieldName)) {
                    deserializedEncoded.base64url
                        = reader.getNullable(nonNullReader -> new Base64Url(nonNullReader.getString()));
                } else if ("unknownDurationFormat".equals(fieldName)) {
                    deserializedEncoded.unknownDurationFormat = reader.getString();
                } else if ("unknownDateTimeFormat".equals(fieldName)) {
                    deserializedEncoded.unknownDateTimeFormat = reader.getString();
                } else if ("unknownBytes".equals(fieldName)) {
                    deserializedEncoded.unknownBytes = reader.getString();
                } else {
                    reader.skipChildren();
                }
            }

            return deserializedEncoded;
        });
    }
}
