/*
 * Copyright (c) 2021 OBiBa. All rights reserved.
 *
 * This program and the accompanying materials
 * are made available under the terms of the GNU Public License v3.0.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.obiba.opal.web.ws.provider;

import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;

import jakarta.ws.rs.Produces;
import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.MultivaluedMap;
import jakarta.ws.rs.ext.MessageBodyWriter;
import jakarta.ws.rs.ext.Provider;

import org.obiba.opal.web.ws.util.JsonIoUtil;
import org.springframework.stereotype.Component;

import com.google.protobuf.Message;
import com.googlecode.protobuf.format.JsonFormat;

@Component
@Provider
@Produces({ "application/x-protobuf+json", "application/json" })
public class ProtobufJsonWriterProvider extends AbstractProtobufProvider implements MessageBodyWriter<Object> {

  @Override
  public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
    return Message.class.isAssignableFrom(type) || isWrapped(type, genericType, annotations, mediaType);
  }

  @Override
  public long getSize(Object t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
    return -1;
  }

  @Override
  @SuppressWarnings({ "unchecked", "PMD.ExcessiveParameterList" })
  public void writeTo(Object t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType,
      MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream)
      throws IOException, WebApplicationException {
    try(OutputStreamWriter output = new OutputStreamWriter(entityStream, "UTF-8")) {
      if(isWrapped(type, genericType, annotations, mediaType)) {
        // JsonFormat does not provide a printList method
        JsonIoUtil
            .printCollection(sort(extractMessageType(type, genericType, annotations, mediaType), (Iterable<Message>) t),
                output);
      } else {
        JsonFormat.print((Message) t, output);
      }
      output.flush();
    }
  }

}
