package com.fuint.common.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.fuint.common.enums.StatusEnum;
import com.fuint.common.param.LookWorkPage;
import com.fuint.common.service.LookService;
import com.fuint.common.service.MemberService;
import com.fuint.common.service.SettingService;
import com.fuint.framework.exception.BusinessCheckException;
import com.fuint.framework.pagination.PaginationResponse;
import com.fuint.repository.mapper.MtLookCommentMapper;
import com.fuint.repository.mapper.MtLookLikeMapper;
import com.fuint.repository.mapper.MtLookWorkMapper;
import com.fuint.repository.model.MtLookComment;
import com.fuint.repository.model.MtLookLike;
import com.fuint.repository.model.MtLookWork;
import com.fuint.repository.model.MtUser;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import lombok.AllArgsConstructor;
import org.apache.commons.lang.StringUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 看看功能服务实现
 *
 * Created by Codex
 */
@Service
@AllArgsConstructor(onConstructor_ = {@Lazy})
public class LookServiceImpl implements LookService {

    private static final String TARGET_TYPE_WORK = "WORK";
    private static final String TARGET_TYPE_COMMENT = "COMMENT";

    private MtLookWorkMapper mtLookWorkMapper;

    private MtLookCommentMapper mtLookCommentMapper;

    private MtLookLikeMapper mtLookLikeMapper;

    private MemberService memberService;

    private SettingService settingService;

    @Override
    public PaginationResponse<Map<String, Object>> queryWorkListForAdmin(LookWorkPage page) {
        Page<MtLookWork> pageHelper = PageHelper.startPage(page.getPage(), page.getPageSize());

        LambdaQueryWrapper<MtLookWork> wrapper = Wrappers.lambdaQuery();
        wrapper.ne(MtLookWork::getStatus, StatusEnum.DISABLE.getKey());

        if (StringUtils.isNotBlank(page.getTitle())) {
            wrapper.like(MtLookWork::getTitle, page.getTitle());
        }
        if (StringUtils.isNotBlank(page.getStatus())) {
            wrapper.eq(MtLookWork::getStatus, page.getStatus());
        }
        if (page.getMerchantId() != null && page.getMerchantId() > 0) {
            wrapper.eq(MtLookWork::getMerchantId, page.getMerchantId());
        }
        if (page.getStoreId() != null && page.getStoreId() > 0) {
            wrapper.eq(MtLookWork::getStoreId, page.getStoreId());
        }
        wrapper.orderByDesc(MtLookWork::getId);

        List<MtLookWork> list = mtLookWorkMapper.selectList(wrapper);
        List<Map<String, Object>> dataList = toWorkListResult(list, null, true);

        PageRequest pageRequest = PageRequest.of(page.getPage(), page.getPageSize());
        PageImpl pageImpl = new PageImpl(dataList, pageRequest, pageHelper.getTotal());
        PaginationResponse<Map<String, Object>> paginationResponse = new PaginationResponse(pageImpl, Map.class);
        paginationResponse.setTotalPages(pageHelper.getPages());
        paginationResponse.setTotalElements(pageHelper.getTotal());
        paginationResponse.setContent(dataList);
        return paginationResponse;
    }

    @Override
    public PaginationResponse<Map<String, Object>> queryWorkListForClient(Integer merchantId,
                                                                           Integer storeId,
                                                                           Integer userId,
                                                                           Integer page,
                                                                           Integer pageSize,
                                                                           boolean onlyMine) {
        int currentPage = page == null || page < 1 ? 1 : page;
        int size = pageSize == null || pageSize < 1 ? 10 : pageSize;

        Page<MtLookWork> pageHelper = PageHelper.startPage(currentPage, size);
        LambdaQueryWrapper<MtLookWork> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(MtLookWork::getMerchantId, merchantId)
                .ne(MtLookWork::getStatus, StatusEnum.DISABLE.getKey());

        if (onlyMine && userId != null && userId > 0) {
            wrapper.eq(MtLookWork::getUserId, userId)
                    .ne(MtLookWork::getStatus, StatusEnum.DISABLE.getKey());
        } else {
            wrapper.eq(MtLookWork::getStatus, StatusEnum.ENABLED.getKey());
        }

        if (storeId != null && storeId > 0) {
            wrapper.and(wq -> wq.eq(MtLookWork::getStoreId, 0).or().eq(MtLookWork::getStoreId, storeId));
        }

        wrapper.orderByDesc(MtLookWork::getId);
        List<MtLookWork> list = mtLookWorkMapper.selectList(wrapper);
        List<Map<String, Object>> dataList = toWorkListResult(list, userId, false);

        PageRequest pageRequest = PageRequest.of(currentPage, size);
        PageImpl pageImpl = new PageImpl(dataList, pageRequest, pageHelper.getTotal());
        PaginationResponse<Map<String, Object>> paginationResponse = new PaginationResponse(pageImpl, Map.class);
        paginationResponse.setTotalPages(pageHelper.getPages());
        paginationResponse.setTotalElements(pageHelper.getTotal());
        paginationResponse.setContent(dataList);
        return paginationResponse;
    }

    @Override
    public Map<String, Object> getWorkDetail(Integer workId, Integer userId) throws BusinessCheckException {
        MtLookWork work = mtLookWorkMapper.selectById(workId);
        if (work == null || StatusEnum.DISABLE.getKey().equals(work.getStatus())) {
            throw new BusinessCheckException("作品不存在");
        }
        if (StatusEnum.ENABLED.getKey().equals(work.getStatus()) || (userId != null && userId.equals(work.getUserId()))) {
            Map<String, Object> result = toWorkItemResult(work, userId, false);
            return result;
        }
        throw new BusinessCheckException("作品已下架");
    }

    @Override
    public Map<String, Object> getWorkDetailForAdmin(Integer workId) throws BusinessCheckException {
        MtLookWork work = mtLookWorkMapper.selectById(workId);
        if (work == null || StatusEnum.DISABLE.getKey().equals(work.getStatus())) {
            throw new BusinessCheckException("作品不存在");
        }
        return toWorkItemResult(work, null, true);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public MtLookWork saveWork(Integer merchantId,
                               Integer storeId,
                               Integer userId,
                               String title,
                               String description,
                               List<String> images,
                               String operator) throws BusinessCheckException {
        if (merchantId == null || merchantId <= 0) {
            throw new BusinessCheckException("商户信息异常");
        }
        if (userId == null || userId <= 0) {
            throw new BusinessCheckException("用户信息异常");
        }
        if (StringUtils.isBlank(title)) {
            throw new BusinessCheckException("作品标题不能为空");
        }
        if (StringUtils.isBlank(description)) {
            throw new BusinessCheckException("作品描述不能为空");
        }
        if (images == null || images.isEmpty()) {
            throw new BusinessCheckException("请至少上传1张作品图");
        }

        MtLookWork work = new MtLookWork();
        work.setMerchantId(merchantId);
        work.setStoreId(storeId == null ? 0 : storeId);
        work.setUserId(userId);
        work.setTitle(title);
        work.setDescription(description);
        work.setImages(joinImages(images));
        work.setCover(images.get(0));
        work.setLikeNum(0);
        work.setCommentNum(0);
        work.setStatus(StatusEnum.ENABLED.getKey());
        work.setOperator(StringUtils.isBlank(operator) ? String.valueOf(userId) : operator);
        work.setCreateTime(new Date());
        work.setUpdateTime(new Date());

        mtLookWorkMapper.insert(work);
        return work;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeWork(Integer workId, Integer userId, String operator) throws BusinessCheckException {
        MtLookWork work = mtLookWorkMapper.selectById(workId);
        if (work == null || StatusEnum.DISABLE.getKey().equals(work.getStatus())) {
            throw new BusinessCheckException("作品不存在");
        }
        if (userId == null || !userId.equals(work.getUserId())) {
            throw new BusinessCheckException("无权删除该作品");
        }

        MtLookWork update = new MtLookWork();
        update.setId(workId);
        update.setStatus(StatusEnum.DISABLE.getKey());
        update.setOperator(StringUtils.isBlank(operator) ? String.valueOf(userId) : operator);
        update.setUpdateTime(new Date());
        mtLookWorkMapper.updateById(update);
    }

    @Override
    public PaginationResponse<Map<String, Object>> queryCommentList(Integer workId,
                                                                     Integer page,
                                                                     Integer pageSize,
                                                                     Integer userId) throws BusinessCheckException {
        MtLookWork work = mtLookWorkMapper.selectById(workId);
        if (work == null || StatusEnum.DISABLE.getKey().equals(work.getStatus())) {
            throw new BusinessCheckException("作品不存在");
        }

        int currentPage = page == null || page < 1 ? 1 : page;
        int size = pageSize == null || pageSize < 1 ? 20 : pageSize;

        Page<MtLookComment> pageHelper = PageHelper.startPage(currentPage, size);
        LambdaQueryWrapper<MtLookComment> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(MtLookComment::getWorkId, workId)
                .eq(MtLookComment::getStatus, StatusEnum.ENABLED.getKey())
                .orderByDesc(MtLookComment::getId);
        List<MtLookComment> list = mtLookCommentMapper.selectList(wrapper);
        List<Map<String, Object>> dataList = toCommentListResult(list, userId);

        PageRequest pageRequest = PageRequest.of(currentPage, size);
        PageImpl pageImpl = new PageImpl(dataList, pageRequest, pageHelper.getTotal());
        PaginationResponse<Map<String, Object>> paginationResponse = new PaginationResponse(pageImpl, Map.class);
        paginationResponse.setTotalPages(pageHelper.getPages());
        paginationResponse.setTotalElements(pageHelper.getTotal());
        paginationResponse.setContent(dataList);
        return paginationResponse;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> saveComment(Integer workId,
                                           Integer userId,
                                           String content,
                                           List<String> images,
                                           String operator) throws BusinessCheckException {
        MtLookWork work = mtLookWorkMapper.selectById(workId);
        if (work == null || !StatusEnum.ENABLED.getKey().equals(work.getStatus())) {
            throw new BusinessCheckException("作品不存在或已下架");
        }
        if (StringUtils.isBlank(content) && (images == null || images.isEmpty())) {
            throw new BusinessCheckException("请输入留言内容或上传图片");
        }
        if (userId == null || userId <= 0) {
            throw new BusinessCheckException("用户信息异常");
        }

        MtLookComment comment = new MtLookComment();
        comment.setMerchantId(work.getMerchantId());
        comment.setStoreId(work.getStoreId());
        comment.setWorkId(workId);
        comment.setUserId(userId);
        comment.setContent(StringUtils.isBlank(content) ? "" : content);
        comment.setImages(joinImages(images));
        comment.setLikeNum(0);
        comment.setStatus(StatusEnum.ENABLED.getKey());
        comment.setOperator(StringUtils.isBlank(operator) ? String.valueOf(userId) : operator);
        comment.setCreateTime(new Date());
        comment.setUpdateTime(new Date());

        mtLookCommentMapper.insert(comment);
        mtLookWorkMapper.incrCommentNum(workId);
        return toCommentItemResult(comment, userId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> toggleWorkLike(Integer workId,
                                              Integer userId,
                                              Integer merchantId,
                                              Integer storeId) throws BusinessCheckException {
        if (userId == null || userId <= 0) {
            throw new BusinessCheckException("请先登录");
        }
        MtLookWork work = mtLookWorkMapper.selectById(workId);
        if (work == null || !StatusEnum.ENABLED.getKey().equals(work.getStatus())) {
            throw new BusinessCheckException("作品不存在或已下架");
        }
        if (merchantId != null && merchantId > 0 && !merchantId.equals(work.getMerchantId())) {
            throw new BusinessCheckException("作品不存在");
        }
        if (storeId != null && storeId > 0 && work.getStoreId() != null && work.getStoreId() > 0 && !storeId.equals(work.getStoreId())) {
            throw new BusinessCheckException("作品不存在");
        }

        MtLookLike like = queryLike(userId, TARGET_TYPE_WORK, workId);
        boolean liked;
        if (like == null) {
            like = new MtLookLike();
            like.setMerchantId(work.getMerchantId());
            like.setStoreId(work.getStoreId());
            like.setUserId(userId);
            like.setTargetType(TARGET_TYPE_WORK);
            like.setTargetId(workId);
            like.setStatus(StatusEnum.ENABLED.getKey());
            like.setCreateTime(new Date());
            like.setUpdateTime(new Date());
            mtLookLikeMapper.insert(like);
            mtLookWorkMapper.incrLikeNum(workId);
            liked = true;
        } else if (StatusEnum.ENABLED.getKey().equals(like.getStatus())) {
            like.setStatus(StatusEnum.FORBIDDEN.getKey());
            like.setUpdateTime(new Date());
            mtLookLikeMapper.updateById(like);
            mtLookWorkMapper.decrLikeNum(workId);
            liked = false;
        } else {
            like.setStatus(StatusEnum.ENABLED.getKey());
            like.setUpdateTime(new Date());
            mtLookLikeMapper.updateById(like);
            mtLookWorkMapper.incrLikeNum(workId);
            liked = true;
        }

        MtLookWork latest = mtLookWorkMapper.selectById(workId);
        Map<String, Object> result = new HashMap<>();
        result.put("liked", liked);
        result.put("likeCount", latest.getLikeNum() == null ? 0 : latest.getLikeNum());
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> toggleCommentLike(Integer commentId,
                                                 Integer userId,
                                                 Integer merchantId,
                                                 Integer storeId) throws BusinessCheckException {
        if (userId == null || userId <= 0) {
            throw new BusinessCheckException("请先登录");
        }
        MtLookComment comment = mtLookCommentMapper.selectById(commentId);
        if (comment == null || !StatusEnum.ENABLED.getKey().equals(comment.getStatus())) {
            throw new BusinessCheckException("评论不存在");
        }
        MtLookWork work = mtLookWorkMapper.selectById(comment.getWorkId());
        if (work == null || !StatusEnum.ENABLED.getKey().equals(work.getStatus())) {
            throw new BusinessCheckException("作品不存在或已下架");
        }
        if (merchantId != null && merchantId > 0 && !merchantId.equals(comment.getMerchantId())) {
            throw new BusinessCheckException("评论不存在");
        }
        if (storeId != null && storeId > 0 && comment.getStoreId() != null && comment.getStoreId() > 0 && !storeId.equals(comment.getStoreId())) {
            throw new BusinessCheckException("评论不存在");
        }

        MtLookLike like = queryLike(userId, TARGET_TYPE_COMMENT, commentId);
        boolean liked;
        if (like == null) {
            like = new MtLookLike();
            like.setMerchantId(comment.getMerchantId());
            like.setStoreId(comment.getStoreId());
            like.setUserId(userId);
            like.setTargetType(TARGET_TYPE_COMMENT);
            like.setTargetId(commentId);
            like.setStatus(StatusEnum.ENABLED.getKey());
            like.setCreateTime(new Date());
            like.setUpdateTime(new Date());
            mtLookLikeMapper.insert(like);
            mtLookCommentMapper.incrLikeNum(commentId);
            liked = true;
        } else if (StatusEnum.ENABLED.getKey().equals(like.getStatus())) {
            like.setStatus(StatusEnum.FORBIDDEN.getKey());
            like.setUpdateTime(new Date());
            mtLookLikeMapper.updateById(like);
            mtLookCommentMapper.decrLikeNum(commentId);
            liked = false;
        } else {
            like.setStatus(StatusEnum.ENABLED.getKey());
            like.setUpdateTime(new Date());
            mtLookLikeMapper.updateById(like);
            mtLookCommentMapper.incrLikeNum(commentId);
            liked = true;
        }

        MtLookComment latest = mtLookCommentMapper.selectById(commentId);
        Map<String, Object> result = new HashMap<>();
        result.put("liked", liked);
        result.put("likeCount", latest.getLikeNum() == null ? 0 : latest.getLikeNum());
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateWorkStatus(Integer workId, String status, String operator, Integer merchantId) throws BusinessCheckException {
        MtLookWork work = mtLookWorkMapper.selectById(workId);
        if (work == null || StatusEnum.DISABLE.getKey().equals(work.getStatus())) {
            throw new BusinessCheckException("作品不存在");
        }
        if (merchantId != null && merchantId > 0 && !merchantId.equals(work.getMerchantId())) {
            throw new BusinessCheckException("无权操作该作品");
        }

        MtLookWork update = new MtLookWork();
        update.setId(workId);
        update.setStatus(status);
        update.setOperator(operator);
        update.setUpdateTime(new Date());
        mtLookWorkMapper.updateById(update);
    }

    private MtLookLike queryLike(Integer userId, String targetType, Integer targetId) {
        LambdaQueryWrapper<MtLookLike> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(MtLookLike::getUserId, userId)
                .eq(MtLookLike::getTargetType, targetType)
                .eq(MtLookLike::getTargetId, targetId)
                .ne(MtLookLike::getStatus, StatusEnum.DISABLE.getKey())
                .last("limit 1");
        return mtLookLikeMapper.selectOne(wrapper);
    }

    private List<Map<String, Object>> toWorkListResult(List<MtLookWork> list, Integer userId, boolean adminMode) {
        List<Map<String, Object>> result = new ArrayList<>();
        for (MtLookWork item : list) {
            result.add(toWorkItemResult(item, userId, adminMode));
        }
        return result;
    }

    private Map<String, Object> toWorkItemResult(MtLookWork item, Integer userId, boolean adminMode) {
        Map<String, Object> result = new HashMap<>();
        result.put("id", item.getId());
        result.put("merchantId", item.getMerchantId());
        result.put("storeId", item.getStoreId());
        result.put("userId", item.getUserId());
        result.put("title", item.getTitle());
        result.put("desc", item.getDescription());
        result.put("description", item.getDescription());
        result.put("cover", resolveImage(item.getCover()));
        result.put("images", splitImages(item.getImages()).stream().map(this::resolveImage).collect(Collectors.toList()));
        result.put("likes", item.getLikeNum() == null ? 0 : item.getLikeNum());
        result.put("comments", item.getCommentNum() == null ? 0 : item.getCommentNum());
        result.put("status", item.getStatus());
        result.put("createTime", item.getCreateTime());
        result.put("updateTime", item.getUpdateTime());
        result.put("operator", item.getOperator());

        MtUser user = null;
        try {
            user = memberService.queryMemberById(item.getUserId());
        } catch (BusinessCheckException e) {
            // ignore
        }
        result.put("author", user == null ? "手作玩家" : user.getName());
        result.put("authorAvatar", user == null ? "" : user.getAvatar());

        if (!adminMode && userId != null && userId > 0) {
            MtLookLike like = queryLike(userId, TARGET_TYPE_WORK, item.getId());
            result.put("isLiked", like != null && StatusEnum.ENABLED.getKey().equals(like.getStatus()));
        } else {
            result.put("isLiked", false);
        }
        return result;
    }

    private List<Map<String, Object>> toCommentListResult(List<MtLookComment> list, Integer userId) {
        List<Map<String, Object>> result = new ArrayList<>();
        for (MtLookComment item : list) {
            result.add(toCommentItemResult(item, userId));
        }
        return result;
    }

    private Map<String, Object> toCommentItemResult(MtLookComment item, Integer userId) {
        Map<String, Object> result = new HashMap<>();
        result.put("id", item.getId());
        result.put("workId", item.getWorkId());
        result.put("authorId", item.getUserId());
        result.put("content", item.getContent());
        result.put("images", splitImages(item.getImages()).stream().map(this::resolveImage).collect(Collectors.toList()));
        result.put("likeCount", item.getLikeNum() == null ? 0 : item.getLikeNum());
        result.put("createTime", item.getCreateTime());

        MtUser user = null;
        try {
            user = memberService.queryMemberById(item.getUserId());
        } catch (BusinessCheckException e) {
            // ignore
        }
        result.put("author", user == null ? "匿名用户" : user.getName());
        result.put("authorAvatar", user == null ? "" : user.getAvatar());

        if (userId != null && userId > 0) {
            MtLookLike like = queryLike(userId, TARGET_TYPE_COMMENT, item.getId());
            result.put("isLiked", like != null && StatusEnum.ENABLED.getKey().equals(like.getStatus()));
        } else {
            result.put("isLiked", false);
        }
        return result;
    }

    private String joinImages(List<String> images) {
        if (images == null || images.isEmpty()) {
            return "";
        }
        List<String> valid = images.stream().filter(StringUtils::isNotBlank).collect(Collectors.toList());
        return String.join(",", valid);
    }

    private List<String> splitImages(String images) {
        if (StringUtils.isBlank(images)) {
            return new ArrayList<>();
        }
        return Arrays.stream(images.split(",")).filter(StringUtils::isNotBlank).collect(Collectors.toList());
    }

    private String resolveImage(String path) {
        if (StringUtils.isBlank(path)) {
            return "";
        }
        if (path.startsWith("http://") || path.startsWith("https://")) {
            return path;
        }
        String base = settingService.getUploadBasePath();
        if (StringUtils.isBlank(base)) {
            return path;
        }
        if (base.endsWith("/") && path.startsWith("/")) {
            return base + path.substring(1);
        }
        if (!base.endsWith("/") && !path.startsWith("/")) {
            return base + "/" + path;
        }
        return base + path;
    }
}
