package com.izouma.nineth.web;

import com.fasterxml.jackson.annotation.JsonView;
import com.izouma.nineth.domain.Collection;
import com.izouma.nineth.domain.CollectionPrivilege;
import com.izouma.nineth.domain.FileObject;
import com.izouma.nineth.dto.*;
import com.izouma.nineth.exception.BusinessException;
import com.izouma.nineth.repo.CollectionPrivilegeRepo;
import com.izouma.nineth.repo.CollectionRepo;
import com.izouma.nineth.repo.NewsRepo;
import com.izouma.nineth.service.CacheService;
import com.izouma.nineth.service.CollectionService;
import com.izouma.nineth.service.LikeService;
import com.izouma.nineth.utils.SecurityUtils;
import com.izouma.nineth.utils.excel.ExcelUtils;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/collection")
@AllArgsConstructor
public class CollectionController extends BaseController {
    private CollectionService       collectionService;
    private CollectionRepo          collectionRepo;
    private LikeService             likeService;
    private NewsRepo                newsRepo;
    private CacheService            cacheService;
    private CollectionPrivilegeRepo collectionPrivilegeRepo;

    @PreAuthorize("hasRole('ADMIN')")
    @PostMapping("/save")
    public Collection save(@RequestBody CollectionInfoDTO record) {
        Collection collection = collectionService.update(record);

        CollectionPrivilege collectionPrivilege = collectionPrivilegeRepo.findByCollectionId(record.getId());
        if (ObjectUtils.isEmpty(collectionPrivilege)) {
            collectionPrivilege = new CollectionPrivilege(record, record.getId());
            collectionPrivilege.setId(null);
            collectionPrivilegeRepo.save(collectionPrivilege);
            return collection;
        }

        collectionPrivilegeRepo.update(collectionPrivilege.getId(), record.getId(), record.getHeadBg(),
                record.getMaxCollection(), record.getShowroomBg(), record.isVip());
        return collection;
    }

    @PreAuthorize("hasRole('ADMIN')")
    @PostMapping("/create")
    public Collection create(@RequestBody CollectionInfoDTO record) {
        Collection collection = new Collection();
        BeanUtils.copyProperties(record, collection);
        collection = collectionService.create(collection);
        CollectionPrivilege collectionPrivilege = new CollectionPrivilege();
        BeanUtils.copyProperties(record, collectionPrivilege);
        collectionPrivilege.setCollectionId(collection.getId());
        collectionPrivilegeRepo.save(collectionPrivilege);
        return collection;
    }

    //@PreAuthorize("hasRole('ADMIN')")
    @PostMapping("/all")
    @JsonView(Collection.View.Basic.class)
    public Page<Collection> all(@RequestBody PageQuery pageQuery) {
        pageQuery.getQuery().putIfAbsent("companyId", 1);
        Page<Collection> page = collectionService.all(pageQuery).toPage();
        collectionService.queryUserDetail(page.getContent());
        return page;
    }

    @GetMapping("/get/{id}")
    public Collection get(@PathVariable Long id) {
        return collectionService.queryUserDetail(collectionRepo.findById(id)
                .orElseThrow(new BusinessException("无记录")), true, true);
    }

    @GetMapping("/getInfo/{id}")
    public CollectionInfoDTO getInfo(@PathVariable Long id) {
        return collectionRepo.findInfoById(id).orElseThrow(new BusinessException("无记录"));
    }

//    @PreAuthorize("hasRole('ADMIN')")
//    @PostMapping("/del/{id}")
//    public void del(@PathVariable Long id) {
//        collectionRepo.softDelete(id);
//    }

    @GetMapping("/excel")
    @ResponseBody
    public void excel(HttpServletResponse response, PageQuery pageQuery) throws IOException {
        List<Collection> data = collectionService.all(pageQuery).getContent();
        ExcelUtils.export(response, data);
    }

    @GetMapping("/{id}/like")
    @ApiOperation("点赞")
    @CacheEvict("collection")
    public void like(@PathVariable Long id) {
        likeService.like(SecurityUtils.getAuthenticatedUser().getId(), id);
    }

    @GetMapping("/{id}/unlike")
    @ApiOperation("取消点赞")
    @CacheEvict("collection")
    public void unlike(@PathVariable Long id) {
        likeService.unlike(SecurityUtils.getAuthenticatedUser().getId(), id);
    }

    @GetMapping("/myLikes")
    @ApiOperation("我收藏的")
    public List<CollectionDTO> myLikes() {
        return collectionService.toDTO(collectionRepo.userLikes(SecurityUtils.getAuthenticatedUser().getId()));
    }

    @PreAuthorize("hasRole('ADMIN')")
    @PostMapping("/createBlindBox")
    public Collection createBlindBox(@RequestBody CreateBlindBox createBlindBox) throws Exception {
        return collectionService.createBlindBox(createBlindBox);
    }

    @PostMapping("/appointment")
    public void appointment(@RequestParam Long id) {
        collectionService.appointment(id, SecurityUtils.getAuthenticatedUser().getId());
    }

    //    @GetMapping("/recommend")
//    @Cacheable("recommend")
    public List<CollectionDTO> recommend(@RequestParam String type) {
        return collectionRepo.recommend(type).stream().map(rc -> {
            if (StringUtils.isNotBlank(rc.getRecommend().getPic())) {
                rc.getCollection().setPic(Collections.singletonList(new FileObject(null, rc.getRecommend()
                        .getPic(), null, null)));
            }
            CollectionDTO collectionDTO = new CollectionDTO();
            BeanUtils.copyProperties(rc.getCollection(), collectionDTO);

            // 减少数据量
            collectionDTO.setDetail(null);
            collectionDTO.setPrivileges(null);
            collectionDTO.setProperties(null);

            return collectionDTO;
        }).collect(Collectors.toList());
    }

    @GetMapping("/recommend")
    @Cacheable("recommend")
    public Object recommendAll(@RequestParam(required = false) String type) {
        if (StringUtils.isNotEmpty(type)) {
            return collectionService.recommendLegacy(type);
        }

        List<RecommendDTO> recommedDTOS = new ArrayList<>();

        List<RecommendDTO> collectionDTOS = collectionRepo.recommend("LIST").stream().map(rc -> {
            if (StringUtils.isNotBlank(rc.getRecommend().getPic())) {
                rc.getCollection().setPic(Collections.singletonList(new FileObject(null, rc.getRecommend()
                        .getPic(), null, null)));
            }
            CollectionDTO collectionDTO = new CollectionDTO();
            BeanUtils.copyProperties(rc.getCollection(), collectionDTO);

            // 减少数据量
            collectionDTO.setDetail(null);
            collectionDTO.setPrivileges(null);
            collectionDTO.setProperties(null);

            return new RecommendDTO(rc.getRecommend().getSort(), collectionDTO, "collection", rc.getRecommend()
                    .getCreatedAt());
        }).collect(Collectors.toList());

        List<RecommendDTO> news = newsRepo.recommend("LIST").stream().map(rn -> {
            if (StringUtils.isNotBlank(rn.getRecommend().getPic())) {
                rn.getNews().setPic(rn.getRecommend().getPic());
            }
            return new RecommendDTO(rn.getRecommend().getSort(), rn.getNews(), "news", rn.getRecommend()
                    .getCreatedAt());
        }).collect(Collectors.toList());

        recommedDTOS.addAll(collectionDTOS);
        recommedDTOS.addAll(news);
        recommedDTOS.sort((a, b) -> b.getSort().compareTo(a.getSort()));
        return recommedDTOS;
    }


    @PreAuthorize("hasRole('ADMIN')")
    @GetMapping("/clearRecommend")
    public String clearRecommend() {
        cacheService.clearRecommend();
        return "ok";
    }

    @PreAuthorize("hasAnyRole('ADMIN','COMPANY')")
    @PostMapping("/onShelf")
    public void onShelf(Long id, boolean onShelf, boolean salable) {
        Collection collection = collectionRepo.findById(id).orElseThrow(new BusinessException("藏品不存在"));
        collection.setOnShelf(onShelf);
        collection.setSalable(salable);
        collectionRepo.save(collection);
    }

    @GetMapping("/byTag")
    @JsonView(Collection.View.Basic.class)
    public Page<Collection> byTag(@RequestParam Long tagId,
                                  @RequestParam(required = false, defaultValue = "0") List<Long> excludeUserId,
                                  Pageable pageable) {
        return collectionService.byTag(tagId, excludeUserId, pageable);
    }

    @PreAuthorize("hasAnyRole('ADMIN','COMPANY')")
    @PostMapping("/onShelfOasis")
    public List<Collection> onShelfOasis(@RequestBody List<Long> oasisIds) {
        return collectionService.setOasisOnShelf(oasisIds);
    }

    @PreAuthorize("hasAnyRole('ADMIN','COMPANY')")
    @PostMapping("/setScancodeOasis")
    public List<Collection> setScancodeOasis(@RequestBody List<Long> oasisIds) {
        return collectionService.setOasisScancode(oasisIds);
    }

    @GetMapping("/count/{search}")
    public Map<String, String> countNum(@PathVariable String search) {
        PageQuery pageQuery = new PageQuery();
        pageQuery.setPage(0);
        pageQuery.setSize(1);
        pageQuery.getQuery().put("onShelf", true);
        pageQuery.getQuery().put("source", "TRANSFER");
        pageQuery.getQuery().put("del", false);
        pageQuery.setSearch(search);
        pageQuery.getQuery().put("salable", false);
        long onlyShowNum = collectionService.all(pageQuery).getTotal();
        pageQuery.getQuery().put("salable", true);
        long consignmentNum = collectionService.all(pageQuery).getTotal();
        pageQuery.getQuery().remove("salable");
        pageQuery.getQuery().put("inPaying", true);
        long transactingNum = collectionService.all(pageQuery).getTotal();
        Map<String, String> map = new HashMap<>();
        map.put("onlyShowNum", String.valueOf(onlyShowNum));
        map.put("consignmentNum", String.valueOf(consignmentNum));
        map.put("transactingNum", String.valueOf(transactingNum));
        return map;
    }
}

