package org.kar.karusic.api;

import java.io.InputStream;
import java.util.List;
import java.util.UUID;

import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.kar.archidata.annotation.AsyncType;
import org.kar.archidata.annotation.FormDataOptional;
import org.kar.archidata.annotation.TypeScriptProgress;
import org.kar.archidata.dataAccess.DBAccess;
import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.addOnSQL.AddOnDataJson;
import org.kar.archidata.dataAccess.options.CheckFunction;
import org.kar.archidata.tools.DataTools;
import org.kar.karusic.model.Album;
import org.kar.karusic.model.Album.AlbumChecker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.swagger.v3.oas.annotations.Operation;
import jakarta.annotation.security.RolesAllowed;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.PATCH;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

@Path("/album")
@Produces({ MediaType.APPLICATION_JSON })
public class AlbumResource {
	private static final Logger LOGGER = LoggerFactory.getLogger(AlbumResource.class);
	static final AlbumChecker CHECKER = new AlbumChecker();

	@GET
	@Path("{id}")
	@RolesAllowed("USER")
	@Operation(description = "Get a specific Album with his ID")
	public Album get(@PathParam("id") final Long id) throws Exception {
		return DataAccess.get(Album.class, id);
		// return this.morphiaService.getDatastore().find(Album.class).filter(Filters.eq("id", id)).first();
	}

	@GET
	@RolesAllowed("USER")
	@Operation(description = "Get all the available Albums")
	public List<Album> gets() throws Exception {
		return DataAccess.gets(Album.class);
		// final Query<Album> query = this.morphiaService.getDatastore().find(Album.class);
		// return query.stream().toList();
	}

	@POST
	@RolesAllowed("ADMIN")
	@Consumes(MediaType.APPLICATION_JSON)
	@Operation(description = "Add an album (when all the data already exist)")
	public Album post(final Album data) throws Exception {
		// TODO: how to manage the checker ???
		// final Album ret = this.morphiaService.getDatastore().save(data);
		// return ret;
		/* final MongoCollection<Track> trackCollection = db.getCollection("TTRACLK", Track.class); final InsertOneResult res = trackCollection.insertOne(plop); LOGGER.warn("plpop {}", res); final
		 * ObjectId ploppppp = res.getInsertedId().asObjectId().getValue(); LOGGER.warn("plpop 2522  {}", res.getInsertedId().asObjectId().getValue()); final Track ret =
		 * trackCollection.find(Filters.eq("_id", res.getInsertedId().asObjectId().getValue())) .first(); System.out.println("Grade found:\t" + ret); */
		return DataAccess.insert(data, new CheckFunction(CHECKER));
	}

	@PATCH
	@Path("{id}")
	@RolesAllowed("ADMIN")
	@Consumes(MediaType.APPLICATION_JSON)
	@Operation(description = "Update a specific album")
	public Album patch(@PathParam("id") final Long id, @AsyncType(Album.class) final String jsonRequest) throws Exception {
		// final Query<Album> query = this.morphiaService.getDatastore().find(Album.class).filter(Filters.eq("id", id));
		// final UpdateOperations<Album> ops = this.morphiaService.getDatastore().createUpdateOperations(Album.class)
		// .set("name", master.getName());
		// this.morphiaService.getDatastore().update(query, ops);
		// return Response.ok(master).build();

		DataAccess.updateWithJson(Album.class, id, jsonRequest, new CheckFunction(CHECKER));
		return DataAccess.get(Album.class, id);
	}

	// @PUT
	// @Path("{id}")
	// @RolesAllowed("ADMIN")
	// @Consumes(MediaType.APPLICATION_JSON)
	// @Operation(description = "Update a specific album")
	// public Album put(@PathParam("id") final Long id, final Album album)
	// throws Exception {
	// final Query<Album> query = this.morphiaService.getDatastore().find(Album.class).filter(Filters.eq("id", id));
	// final UpdateOperations<Album> ops = this.morphiaService.getDatastore().createUpdateOperations(Album.class)
	// .set("name", album.getName());
	// this.morphiaService.getDatastore().update(query, ops);
	// return Response.ok(album).build();
	// }

	@DELETE
	@Path("{id}")
	@RolesAllowed("ADMIN")
	@Operation(description = "Remove a specific album")
	public void remove(@PathParam("id") final Long id) throws Exception {
		DataAccess.delete(Album.class, id);
		// this.morphiaService.getDatastore().find(Album.class).filter(Filters.eq("id", id)).delete();
	}

	/* @POST
	 * @Path("{id}/track/{trackId}")
	 * @RolesAllowed("ADMIN")
	 * @Consumes({ MediaType.MULTIPART_FORM_DATA })
	 * @Operation(description = "Add a Track on a specific album") public Album addTrack(@PathParam("id") final Long id, @PathParam("trackId") final Long trackId) throws Exception {
	 * AddOnManyToMany.removeLink(this.dam, Album.class, id, "track", trackId); return this.dam.get(Album.class, id); } */
	@POST
	@Path("{id}/cover")
	@RolesAllowed("ADMIN")
	@Consumes({ MediaType.MULTIPART_FORM_DATA })
	@Operation(description = "Add a cover on a specific album")
	@TypeScriptProgress
	public Album uploadCover(@PathParam("id") final Long id, @FormDataOptional @FormDataParam("uri") final String uri, @FormDataOptional @FormDataParam("file") final InputStream fileInputStream,
			@FormDataOptional @FormDataParam("file") final FormDataContentDisposition fileMetaData) throws Exception {
		try (DBAccess db = DBAccess.createInterface()) {
			if (uri != null) {
				DataTools.uploadCoverFromUri(db, Album.class, id, uri);
			} else {
				DataTools.uploadCover(db, Album.class, id, fileInputStream, fileMetaData);
			}
			return db.get(Album.class, id);
		}
	}

	@DELETE
	@Path("{id}/cover/{coverId}")
	@RolesAllowed("ADMIN")
	@Operation(description = "Remove a cover on a specific album")
	public Album removeCover(@PathParam("id") final Long id, @PathParam("coverId") final UUID coverId) throws Exception {
		try (DBAccess db = DBAccess.createInterface()) {
			AddOnDataJson.removeLink(db, Album.class, "id", id, "covers", coverId);
			return db.get(Album.class, id);
		}
	}
}
