package eu.dnetlib.uoaadmintoolslibrary.controllers;

import eu.dnetlib.uoaadmintoolslibrary.entities.*;
import eu.dnetlib.uoaadmintoolslibrary.entities.fullEntities.*;
import eu.dnetlib.uoaadmintoolslibrary.handlers.ContentNotFoundException;
import eu.dnetlib.uoaadmintoolslibrary.handlers.MismatchingContentException;
import eu.dnetlib.uoaadmintoolslibrary.responses.SingleValueWrapperResponse;
import eu.dnetlib.uoaadmintoolslibrary.services.*;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.security.access.prepost.PreAuthorize;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

@RestController
@RequestMapping(value = "{portalType}")
@CrossOrigin(origins = "*")
public class AdminPortalRelationsController {
    private final Logger log = Logger.getLogger(this.getClass());

    @Autowired
    private PortalService portalService;

    @Autowired
    private DivHelpContentService divHelpContentService;

    @Autowired
    private DivIdService divIdService;

    @Autowired
    private PageService pageService;

    @Autowired
    private PageHelpContentService pageHelpContentService;

    // ENTITIES

    @RequestMapping(value = {"/{pid}/entities"}, method = RequestMethod.GET)
    public List<PortalEntity> getEntitiesForCommunity(@PathVariable PortalType portalType,
                                                      @PathVariable(value = "pid") String pid) {
        //@RequestParam(value="entity", required=false) String entity) {
        Portal portal = portalService.getPortal(pid);
        portalService.checkPortalInfo(pid, portalType.name(), portal, pid, "pid");
        return portalService.getEntitiesForPortal(pid, null);
    }

    @PreAuthorize("hasAnyAuthority(" +
            "@AuthorizationService.PORTAL_ADMIN, " +
            "@AuthorizationService.curator(#portalType), @AuthorizationService.manager(#portalType, #pid))")
    @RequestMapping(value = {"/{pid}/entity/toggle"}, method = RequestMethod.POST)
    public Portal toggleEntity(@PathVariable PortalType portalType,
                               @PathVariable(value = "pid") String pid,
                               @RequestBody List<String> entityIds, @RequestParam String status) throws Exception {
        return portalService.toggleEntity(pid, entityIds, status);
    }

    // DIV HELP CONTENTS

    // not used by portals
//    //    @RequestMapping(value = {"/community/{pid}/divhelpcontent", "/explore/{pid}/divhelpcontent", "/connect/{pid}/divhelpcontent"}, method = RequestMethod.GET)
//    @RequestMapping(value = {"/{pid}/divhelpcontent/test"}, method = RequestMethod.GET)
//    public Map<String, List<DivHelpContentResponse>> getDivHelpContentsByPositionAdmin(@PathVariable PortalType portalType,
//                                                                                       @PathVariable(value = "pid") String pid,
//                                                                                       @RequestParam(required=false) String page,
//                                                                                       @RequestParam(required=false) String active) {
//        return portalService.getDivHelpContentsByPosition(pid, page, active);
//    }

    // not used by portals
    @PreAuthorize("hasAnyAuthority(@AuthorizationService.PORTAL_ADMIN)")
    @RequestMapping(value = "/{pid}/divhelpcontent", method = RequestMethod.GET)
    public List<DivHelpContentResponse> getDivHelpContents(@PathVariable PortalType portalType,
                                                           @PathVariable(value = "pid") String pid) {
        return divHelpContentService.getDivHelpContents(pid, null, null, null);
    }

    @RequestMapping(value = "/{pid}/divhelpcontent/{id}", method = RequestMethod.GET)
    public DivHelpContent getDivHelpContent(@PathVariable PortalType portalType,
                                            @PathVariable(value = "pid") String pid,
                                            @PathVariable(value = "id") String id) {
        DivHelpContent divHelpContent = divHelpContentService.getDivHelpContent(id);
        if(divHelpContent == null) {
            throw new ContentNotFoundException("DivHelpContent with id: "+id+" not found");
        }

        Portal portal = portalService.getPortalById(divHelpContent.getPortal());
        portalService.checkPortalInfo(pid, portalType.name(), portal, divHelpContent.getPortal(), "id");
        return divHelpContent;
    }

//    @RequestMapping(value = "/{pid}/{pageId}/divhelpcontent", method = RequestMethod.GET)
//    public List<DivHelpContent> getDivHelpContentsByPageId(@PathVariable PortalType portalType,
//                                                             @PathVariable(value = "pid") String pid,
//                                                             @PathVariable(value =  "pageId") String pageId) {
//        return divHelpContentService.getDivHelpContentsBasic(pid, portalType.name(), pageId);
//    }

    @RequestMapping(value = "/{pid}/{pageId}/divhelpcontent", method = RequestMethod.GET)
    public List<DivHelpContentResponse> getDivHelpContentsByPageId(@PathVariable PortalType portalType,
                                                           @PathVariable(value = "pid") String pid,
                                                           @PathVariable(value =  "pageId") String pageId) {
        Page page = pageService.getPage(pageId);
        if(page == null) {
            throw new ContentNotFoundException("Page with id: "+pageId+" not found");
        }
        return divHelpContentService.getDivHelpContents(pid, page.getRoute(), null, null);
    }

    @RequestMapping(value = "/{pid}/divhelpcontent/page/count", method = RequestMethod.GET)
    public Map<String, Integer> countDivHelpContentsForPages(@PathVariable PortalType portalType,
                                                              @PathVariable(value = "pid") String pid) {
        Map<String, Integer> mapCount = new HashMap<String, Integer>();

        List<Page> pages = pageService.getAllPages(pid, null, null);
        for(Page page : pages){
            List<DivHelpContent> divHelpContents = divHelpContentService.getDivHelpContentsBasic(pid, portalType.name(), page.getId());
            if (divHelpContents == null) {
                mapCount.put(page.getId(), 0);
            } else {
                mapCount.put(page.getId(), divHelpContents.size());
            }
        }
        return mapCount;
    }

    @PreAuthorize("hasAnyAuthority(" +
            "@AuthorizationService.PORTAL_ADMIN, " +
            "@AuthorizationService.curator(#portalType), @AuthorizationService.manager(#portalType, #pid))")
    @RequestMapping(value = "/{pid}/divhelpcontent/save", method = RequestMethod.POST)
    public DivHelpContent saveDivHelpContent(@PathVariable PortalType portalType,
                                             @PathVariable(value = "pid") String pid,
                                             @RequestBody DivHelpContent divHelpContent) {
        Portal portal = portalService.getPortal(divHelpContent.getPortal());
        portalService.checkPortalInfo(pid, portalType.name(), portal, divHelpContent.getPortal(), "pid");
        divHelpContent.setPortal(portal.getId());
        return divHelpContentService.insertOrUpdateDivHelpContent(divHelpContent);
    }

        @PreAuthorize("hasAnyAuthority(" +
            "@AuthorizationService.PORTAL_ADMIN, " +
            "@AuthorizationService.curator(#portalType), @AuthorizationService.manager(#portalType, #pid))")
    @RequestMapping(value = "/{pid}/divhelpcontent/update", method = RequestMethod.POST)
    public DivHelpContent updateDivHelpContent(@PathVariable PortalType portalType,
                                               @PathVariable(value = "pid") String pid,
                                               @RequestBody DivHelpContent divHelpContent) {
        Portal portal = portalService.getPortalById(divHelpContent.getPortal());
        portalService.checkPortalInfo(pid, portalType.name(), portal, divHelpContent.getPortal(), "id");
        return divHelpContentService.insertOrUpdateDivHelpContent(divHelpContent);
    }

    // cannot handle MismatchingContent
    @PreAuthorize("hasAnyAuthority(" +
            "@AuthorizationService.PORTAL_ADMIN, " +
            "@AuthorizationService.curator(#portalType), @AuthorizationService.manager(#portalType, #pid))")
    @RequestMapping(value = "/{pid}/divhelpcontent/delete", method = RequestMethod.POST)
    public Boolean deleteDivHelpContents(@PathVariable PortalType portalType,
                                         @PathVariable(value = "pid") String pid,
                                         @RequestBody List<String> divHelpContents) throws Exception {
        return divHelpContentService.deleteDivHelpContents(divHelpContents, pid, portalType);
    }

    // cannot handle MismatchingContent
    @PreAuthorize("hasAnyAuthority(" +
            "@AuthorizationService.PORTAL_ADMIN, " +
            "@AuthorizationService.curator(#portalType), @AuthorizationService.manager(#portalType, #pid))")
    @RequestMapping(value = "/{pid}/divhelpcontent/toggle", method = RequestMethod.POST)
    public List<String> toggleDivHelpContent(@PathVariable PortalType portalType,
                                             @PathVariable(value = "pid") String pid,
                                             @RequestBody List<String> divHelpContents, @RequestParam String status) throws Exception {
        return divHelpContentService.toggleDivHelpContent(divHelpContents, status, pid, portalType);
    }


    // DIVIDS

    @RequestMapping(value = "/{pid}/div/full", method = RequestMethod.GET)
    public List<DivIdResponse> getDivIdsFull(@PathVariable PortalType portalType,
                                             @PathVariable(value = "pid") String pid,
                                             @RequestParam(required = false) String page) {
        return divIdService.getDivIdsFull(page, null, pid);
    }

    @RequestMapping(value = "/{pid}/div/{id}/full", method = RequestMethod.GET)
    public DivIdResponse getDivIdFull(@PathVariable PortalType portalType,
                                      @PathVariable(value = "pid") String pid,
                                      @PathVariable(value = "id") String id) {
        DivIdResponse divIdResponse = divIdService.getDivIdFull(id);
        if(divIdResponse == null) {
            throw new ContentNotFoundException("DivId with id: "+id+" not found");
        }
        if(!divIdResponse.getPortalType().equals(portalType.name())) {
            throw new MismatchingContentException("["+portalType+ " - "+ pid+"] Conflicting portal info: type: "+divIdResponse.getPortalType());
        }
        return divIdResponse;
    }

    @RequestMapping(value = "/{pid}/div/pages", method = RequestMethod.GET)
    public Set<String> getDivIdsPages(@PathVariable PortalType portalType,
                                      @PathVariable(value = "pid") String pid) {
        return divIdService.getDivIdsPages(pid);
    }

    // PAGES

    // used
    @RequestMapping(value = {"/{pid}/pages"}, method = RequestMethod.GET)
    public List<PortalPage> getPagesForPortalByType(@PathVariable PortalType portalType,
                                                    @PathVariable(value = "pid") String pid,
                                                    @RequestParam(value="page_type", required=false) String page_type,
                                                    @RequestParam(value="page_route", required=false) String page_route,
                                                    @RequestParam(value="div", required = false) String div,
                                                    @RequestParam(value="with_positions", required = false) String with_positions) {
        return portalService.getPagesForPortalByType(pid, page_type, page_route, div, with_positions);
    }

    // not used by portals
//    @RequestMapping(value = "/{pid}/page", method = RequestMethod.GET)
//    public List<Page> getAllPages(@PathVariable PortalType portalType,
//                                  @PathVariable(value = "pid") String pid,
//                                  @RequestParam(value="page_route", required=false) String page_route,
//                                  @RequestParam(value="with_positions", required=false) String with_positions) {
//        return pageService.getAllPages(pid, page_route, with_positions);
//    }

//    // not used by portals
//    @RequestMapping(value = {"/{id}/page"}, method = RequestMethod.POST)
//    public Portal insertOrUpdatePage(@PathVariable PortalType portalType,
//                                     @PathVariable(value = "id") String id, @RequestBody PortalPage page) {
//        return portalService.insertOrUpdatePage(id, page);
//    }

    // used
    @PreAuthorize("hasAnyAuthority(" +
            "@AuthorizationService.PORTAL_ADMIN, " +
            "@AuthorizationService.curator(#portalType), @AuthorizationService.manager(#portalType, #pid))")
    @RequestMapping(value = {"/{pid}/page/toggle"}, method = RequestMethod.POST)
    public Portal togglePage(@PathVariable PortalType portalType,
                             @PathVariable(value = "pid") String pid,
                             @RequestBody List<String> pageIds, @RequestParam String status) throws Exception {
        return portalService.togglePage(pid, portalType.name(), pageIds, status);
    }

    @RequestMapping(value = "/{pid}/page", method = RequestMethod.GET)
    public Page getPageByRoute(@PathVariable PortalType portalType,
                               @PathVariable(value = "pid") String pid,
                               @RequestParam(value="page_route", required=true) String page_route) {
        List<Page> pageInArray = pageService.getAllPages(pid, page_route, null);
        if(pageInArray == null || pageInArray.size() == 0) {
            throw new ContentNotFoundException("No page with route: "+page_route + " found for portal with pid: "+pid);
        }
        return pageInArray.get(0);
    }

    @RequestMapping(value = "/{pid}/page/{id}", method = RequestMethod.GET)
    public Page getPage(@PathVariable PortalType portalType,
                        @PathVariable(value = "pid") String pid,
                        @PathVariable(value = "id") String id) {
        Page page = pageService.getPage(id);
        if(page == null) {
            throw new ContentNotFoundException("Page with id: "+id+" not found");
        }
        if(!page.getPortalType().equals(portalType.name())) {
            throw new MismatchingContentException("["+portalType+ " - "+ pid+"] Conflicting portal info: type: "+page.getPortalType());
        }
        return page;
    }

    // PAGE HELP CONTENTS

    // not used by portals
//    @RequestMapping(value = {"/{pid}/pagehelpcontent/test"}, method = RequestMethod.GET)
//    public Map<String, List<PageHelpContentResponse>> getPageHelpContentsByPositionAdmin(@PathVariable PortalType portalType,
//                                                                                         @PathVariable(value = "pid") String pid,
//                                                                                         @RequestParam(required=false) String page,
//                                                                                         @RequestParam(required=false) String active) {
//        return portalService.getPageHelpContentsByPosition(pid, page, active);
//    }

    // not used by portals
    @PreAuthorize("hasAnyAuthority(@AuthorizationService.PORTAL_ADMIN)")
    @RequestMapping(value = "/{pid}/pagehelpcontent", method = RequestMethod.GET)
    public List<PageHelpContentResponse> getPageHelpContents(@PathVariable PortalType portalType,
                                                             @PathVariable(value = "pid") String pid) {
        return pageHelpContentService.getPageHelpContents(pid, null, null, null, null, null);
    }

    // used
    @RequestMapping(value = "/{pid}/{pageId}/pagehelpcontent", method = RequestMethod.GET)
    public List<PageHelpContent> getPageHelpContentsByPageId(@PathVariable PortalType portalType,
                                                             @PathVariable(value = "pid") String pid,
                                                             @PathVariable(value =  "pageId") String pageId) {
        return pageHelpContentService.getPageHelpContentsBasic(pid, portalType.name(), pageId);
    }

    // used
    @RequestMapping(value = "/{pid}/pagehelpcontent/page/count", method = RequestMethod.GET)
    public Map<String, Integer> countPageHelpContentsForPages(@PathVariable PortalType portalType,
                                                              @PathVariable(value = "pid") String pid) {
        Map<String, Integer> mapCount = new HashMap<String, Integer>();

        List<Page> pages = pageService.getAllPages(pid, null, null);
        for(Page page : pages){
            List<PageHelpContent> pageHelpContents = pageHelpContentService.getPageHelpContentsBasic(pid, portalType.name(), page.getId());
            if (pageHelpContents == null) {
                mapCount.put(page.getId(), 0);
            } else {
                mapCount.put(page.getId(), pageHelpContents.size());
            }
        }
        return mapCount;
    }

//    @RequestMapping(value = "/{pid}/pagehelpcontent/{id}", method = RequestMethod.GET)
//    public PageHelpContent getPageHelpContent(@PathVariable PortalType portalType,
//                                              @PathVariable(value = "pid") String pid,
//                                              @PathVariable(value = "id") String id) {
//        PageHelpContent pageHelpContent = pageHelpContentService.getPageHelpContent(id);
//        if(pageHelpContent == null) {
//            throw new ContentNotFoundException("PageHelpContent with id: "+id+" not found");
//        }
//
//        Portal portal = portalService.getPortalById(pageHelpContent.getPortal());
//        portalService.checkPortalInfo(pid, portalType.name(), portal, pageHelpContent.getPortal(), "id");
//        return pageHelpContent;
//    }

    @PreAuthorize("hasAnyAuthority(" +
            "@AuthorizationService.PORTAL_ADMIN, " +
            "@AuthorizationService.curator(#portalType), @AuthorizationService.manager(#portalType, #pid))")
    @RequestMapping(value = "/{pid}/pagehelpcontent/save", method = RequestMethod.POST)
    public PageHelpContent insertPageHelpContent(@PathVariable PortalType portalType,
                                                 @PathVariable(value = "pid") String pid,
                                                 @RequestBody PageHelpContent pageHelpContent) {
        Portal portal = portalService.getPortal(pageHelpContent.getPortal());
        portalService.checkPortalInfo(pid, portalType.name(), portal, pageHelpContent.getPortal(), "pid");
        pageHelpContent.setPortal(portal.getId());
        return pageHelpContentService.insertOrUpdatePageHelpContent(pageHelpContent);
    }

    @PreAuthorize("hasAnyAuthority(" +
            "@AuthorizationService.PORTAL_ADMIN, " +
            "@AuthorizationService.curator(#portalType), @AuthorizationService.manager(#portalType, #pid))")
    @RequestMapping(value = "/{pid}/pagehelpcontent/update", method = RequestMethod.POST)
    public PageHelpContent updatePageHelpContent(@PathVariable PortalType portalType,
                                                 @PathVariable(value = "pid") String pid,
                                                 @RequestBody PageHelpContent pageHelpContent) {
        Portal portal = portalService.getPortalById(pageHelpContent.getPortal());
        portalService.checkPortalInfo(pid, portalType.name(), portal, pageHelpContent.getPortal(), "id");
        return pageHelpContentService.insertOrUpdatePageHelpContent(pageHelpContent);
    }

    // cannot handle MismatchingContent
    @PreAuthorize("hasAnyAuthority(" +
            "@AuthorizationService.PORTAL_ADMIN, " +
            "@AuthorizationService.curator(#portalType), @AuthorizationService.manager(#portalType, #pid))")
    @RequestMapping(value = "/{pid}/pagehelpcontent/delete", method = RequestMethod.POST)
    public Boolean deletePageHelpContents(@PathVariable PortalType portalType,
                                          @PathVariable(value = "pid") String pid,
                                          @RequestBody List<String> pageHelpContents) throws Exception {
        return pageHelpContentService.deletePageHelpContents(pageHelpContents, pid, portalType);
    }

    // cannot handle MismatchingContent
    @PreAuthorize("hasAnyAuthority(" +
            "@AuthorizationService.PORTAL_ADMIN, " +
            "@AuthorizationService.curator(#portalType), @AuthorizationService.manager(#portalType, #pid))")
    @RequestMapping(value = "/{pid}/pagehelpcontent/toggle", method = RequestMethod.POST)
    public List<String> togglePageHelpContent(@PathVariable PortalType portalType,
                                              @PathVariable(value = "pid") String pid,
                                              @RequestBody List<String> pageHelpContents, @RequestParam String status) throws Exception {
        return pageHelpContentService.togglePageHelpContent(pageHelpContents, status, pid, portalType);
    }

}