package ru.yandex.qe.dispenser.ws;

import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;

import io.swagger.annotations.Api;
import io.swagger.annotations.Authorization;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;

import ru.yandex.qe.dispenser.api.v1.DiMetaValueSet;
import ru.yandex.qe.dispenser.api.v1.DiProjectServiceMeta;
import ru.yandex.qe.dispenser.api.v1.response.DiListResponse;
import ru.yandex.qe.dispenser.domain.Project;
import ru.yandex.qe.dispenser.domain.ProjectServiceMeta;
import ru.yandex.qe.dispenser.domain.Service;
import ru.yandex.qe.dispenser.domain.dao.project.ProjectDao;
import ru.yandex.qe.dispenser.domain.hierarchy.Hierarchy;
import ru.yandex.qe.dispenser.swagger.DispenserSecurityDefinition;
import ru.yandex.qe.dispenser.swagger.SwaggerTags;

@Controller
@Path("/v1/project-metas")
@Produces(ServiceBase.APPLICATION_JSON_UTF_8)
@org.springframework.stereotype.Service("project-meta")
@Api(tags = {SwaggerTags.DISPENSER_API}, authorizations = {@Authorization(value = DispenserSecurityDefinition.AUTHORIZATION_SCHEME_NAME)})
public class ProjectMetaService extends ServiceBase {

    @Autowired
    private ProjectDao projectDao;

    @GET
    @NotNull
    @Path("/{" + ServiceService.SERVICE_KEY + "}/{" + ProjectService.PROJECT_KEY + "}")
    public DiMetaValueSet getProjectMeta(@PathParam(ServiceService.SERVICE_KEY) @NotNull final Service service,
                                         @PathParam(ProjectService.PROJECT_KEY) @NotNull final Project project) {
        ServiceEndpointUtils.memoizeService(service);
        final DiMetaValueSet meta = projectDao.getProjectMeta(project, service);
        return meta != null ? meta : DiMetaValueSet.EMPTY;
    }

    @GET
    @NotNull
    public DiListResponse<DiProjectServiceMeta> getProjectMetas(@QueryParam("service") @NotNull final Set<Service> services,
                                                                @QueryParam("project") final @NotNull Set<Project> projects) {
        ServiceEndpointUtils.memoizeService(services);
        final Set<Project> filterProjects = projects.isEmpty() ? Hierarchy.get().getProjectReader().getAllReal() : projects;
        final Set<Service> filterServices = services.isEmpty() ? Hierarchy.get().getServiceReader().getAll() : services;

        final Set<ProjectServiceMeta> allMetas = projectDao.getAllProjectMetas();
        for (final Project p : filterProjects) {
            for (final Service s : filterServices) {
                allMetas.add(ProjectServiceMeta.emtpy(p, s));
            }
        }

        final List<DiProjectServiceMeta> result = allMetas.stream()
                .filter(m -> filterProjects.contains(m.getProject()))
                .filter(m -> filterServices.contains(m.getService()))
                .map(ProjectServiceMeta::toView)
                .collect(Collectors.toList());
        return new DiListResponse<>(result);
    }

    @POST // TODO: PUT
    @Access(serviceAdmin = true)
    @Consumes(MediaType.APPLICATION_JSON)
    @Path("/{" + ServiceService.SERVICE_KEY + "}/{" + ProjectService.PROJECT_KEY + "}")
    public DiMetaValueSet putProjectMeta(@PathParam(ServiceService.SERVICE_KEY) @NotNull final Service service,
                                         @PathParam(ProjectService.PROJECT_KEY) @NotNull final Project project,
                                         @RequestBody @NotNull final DiMetaValueSet projectMeta) {
        ServiceEndpointUtils.memoizeService(service);
        projectDao.putProjectMeta(new ProjectServiceMeta(project, service, projectMeta));
        return projectMeta;
    }
}
