package com.ruoyi.app.mendian;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.app.order.dto.OrderCreatItem;
import com.ruoyi.app.order.dto.OrderCreateInput;
import com.ruoyi.app.order.dto.OrderPushBodyDto;
import com.ruoyi.app.service.UserService;
import com.ruoyi.app.utils.DateUtil;
import com.ruoyi.app.utils.ImageCompressUtils;
import com.ruoyi.app.user.dto.StoreOutput;
import com.ruoyi.app.utils.PayPush;
import com.ruoyi.common.annotation.Anonymous;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.manager.AsyncManager;
import com.ruoyi.system.domain.*;
import com.ruoyi.system.domain.vo.StoreOperatOutput;
import com.ruoyi.system.mapper.PosStoreMapper;
import com.ruoyi.system.mapper.SysConfigMapper;
import com.ruoyi.system.service.*;
import com.ruoyi.system.utils.Auth;
import com.ruoyi.system.utils.AuthContext;
import com.ruoyi.system.utils.JwtUtil;
import io.swagger.models.auth.In;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import jakarta.servlet.http.HttpServletResponse;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * posstoreController
 *
 * @author ruoyi
 * @date 2023-05-14
 */
@RestController
@RequestMapping("/chanting/store")
public class PosStoreController extends BaseController {
    @Autowired
    private IPosStoreService posStoreService;

    @Autowired
    private PosStoreMapper posStoreMapper;
    @Autowired
    private IPosCollectService posCollectService;
    @Autowired
    private IPosFenleiService posFenleiService;

    @Autowired
    private IInfoUserService infoUserService;
    @Autowired
    private IOperatingHoursService operatingHoursService;
    @Autowired
    private PosStoreEnrichService posStoreEnrichService;
    @Autowired
    private SysConfigMapper sysConfigMapper;
    @Autowired
    private IOrderParentService orderParentService;
    @Autowired
    private IPosOrderService posOrderService;
    @Autowired
    private IPosStoreEzpayService posStoreEzpayService;
    @Autowired
    private UserService userService;
    @Autowired
    private MerchantStoreAccessService merchantStoreAccessService;
    @Autowired
    private IMerchantSubaccountStoreService merchantSubaccountStoreService;




    /**
     * 根据评分查旬门店
     *
     * @param longitude
     * @param latitude
     * @param page
     * @param juli
     * @param type
     * @return
     */
    @Anonymous
    @GetMapping("/getPfStore")
    public AjaxResult getPfStore(@RequestParam BigDecimal longitude,
                                 @RequestParam BigDecimal latitude,
                                 @RequestParam Integer page,
                                 @RequestParam Integer juli,
                                 @RequestParam Integer type) {
        if (type == 0) {
            List<PosStore> list = posStoreMapper.getPingfStore(longitude, latitude, (page - 1) * 10, juli);
            return success(list);
        } else if (type == 1) {
            List<PosStore> list = posStoreMapper.getReduStore(longitude, latitude, (page - 1) * 10, juli);
            return success(list);
        } else {
            List<PosStore> list = posStoreMapper.getNewStore(longitude, latitude, (page - 1) * 10, juli);
            return success(list);
        }
    }

    //删除我的门店
    @Anonymous
    @Auth(session = true)
    @Transactional(rollbackFor = Exception.class)
    @GetMapping("/delemendian")
    public AjaxResult delemendian(@RequestHeader String token, @RequestParam String id) {
        Long userId = AuthContext.requireUserId();
        merchantStoreAccessService.requireOwner(userId);
        merchantStoreAccessService.requireStoreAccess(userId, Long.valueOf(id));
        QueryWrapper<PosFenlei> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("mendid", id);
        List<PosFenlei> list = posFenleiService.list(queryWrapper);
        if (list.size() > 0) {
            return error(MessageUtils.message("no.mendian.exist.classify.not.del"));
        } else {
            int rows = posStoreService.deletePosStoreById(Long.valueOf(id));
            if (rows > 0) {
                merchantSubaccountStoreService.deleteByStoreId(Long.valueOf(id));
            }
            return toAjax(rows);
        }
    }

    /**
     * H5端门店列表
     */
    @Anonymous
    @Auth(session = true)
    @GetMapping("/storelistlist")
    public AjaxResult storelistlist(@RequestHeader String token,
                                    @RequestParam Integer page,
                                    @RequestParam Integer size) {
        Long id = AuthContext.requireUserId();
        IPage<PosStore> stlist = new Page<>(page, size);
        QueryWrapper<PosStore> queryWrapper = new QueryWrapper<>();

        // 判断是否为摊位主(type=4)，摊位主通过 storeId 关联摊位
        InfoUser loginUser = infoUserService.selectInfoUserByUserId(Long.valueOf(id));
        if ("4".equals(loginUser.getUserType())) {
            if (loginUser.getStoreId() != null) {
                queryWrapper.eq("id", loginUser.getStoreId());
            } else {
                queryWrapper.eq("id", -1); // 无关联摊位，返回空列表
            }
        } else {
            Set<Long> storeIds = merchantStoreAccessService.getAccessibleStoreIds(id);
            if (storeIds.isEmpty()) {
                queryWrapper.eq("id", -1);
            } else {
                queryWrapper.in("id", storeIds);
            }
        }

        IPage<PosStore> list = posStoreService.page(stlist, queryWrapper);
        if (!list.getRecords().isEmpty()) {
            QueryWrapper<OperatingHours> wrapper = new QueryWrapper<>();
            wrapper.in("md_id", list.getRecords().stream().map(PosStore::getId).collect(Collectors.toList()));
            List<OperatingHours> hourslist = operatingHoursService.list(wrapper);
            list.getRecords().forEach(posStore -> {
                posStore.setBusinessHours(getStoreOperatOutput(hourslist, Long.valueOf(posStore.getId())));
                // 回显统一编号(统编)，供商家端编辑门店时显示
                posStore.setUbn(posStoreEzpayService.getUbn(Long.valueOf(posStore.getId())));
            });
        }

        return success(list);
    }

    //查询我的门店列表
    @Anonymous
    @Auth(session = true)
    @GetMapping("/getmystorelist")
    public AjaxResult getmystorelist(@RequestHeader String token) {
        Long id = AuthContext.requireUserId();
        QueryWrapper<PosStore> queryWrapper = new QueryWrapper<>();
        InfoUser loginUser = infoUserService.selectInfoUserByUserId(id);
        if (loginUser != null && "4".equals(loginUser.getUserType())) {
            queryWrapper.eq("id", loginUser.getStoreId() == null ? -1 : loginUser.getStoreId());
        } else {
            Set<Long> storeIds = merchantStoreAccessService.getAccessibleStoreIds(id);
            if (storeIds.isEmpty()) {
                queryWrapper.eq("id", -1);
            } else {
                queryWrapper.in("id", storeIds);
            }
        }
        List<PosStore> list = posStoreService.list(queryWrapper);
        return success(list);
    }

    //查询门店列表
    @Anonymous
    @GetMapping("/getstore")
    public AjaxResult getstore(@RequestHeader(defaultValue = "") String token, @RequestParam Integer id) {
        List<PosCollect> list = new ArrayList<>();
        if (!"".equals(token)) {
            JwtUtil jwtUtil = new JwtUtil();
            String usid = jwtUtil.getusid(token);
            QueryWrapper<PosCollect> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("user_id", usid);
            queryWrapper.eq("md_id", id);
            list = posCollectService.list(queryWrapper);
        }
        PosStore posStore = posStoreService.getById(id);
        // 回显统一编号(统编)，实存于 pos_store_ezpay.ubn
        posStore.setUbn(posStoreEzpayService.getUbn(id.longValue()));
        List<PosStore> stores=new ArrayList<>();
        stores.add(posStore);
        posStoreEnrichService.enrichStoreList(stores);
        StoreOutput storeOutput = new StoreOutput();
        BeanUtils.copyProperties(stores.getFirst(), storeOutput);
        storeOutput.setCollect(!list.isEmpty() ? 1 : 0);
        return success(storeOutput);

    }

    /**
     * 商家收款账户（線下轉賬收银台展示用）：门店 到 所属商家主账号 到 审核资料银行三字段
     * 商家级数据，连锁门店共享同一收款账户；任一字段为空返回 data=null，客户端据此隐藏線下支付选项
     */
    @Anonymous
    @GetMapping("/bankInfo")
    public AjaxResult bankInfo(@RequestParam Integer id) {
        PosStore store = posStoreService.getById(id);
        if (store == null || store.getUserId() == null) {
            return success(null);
        }
        InfoUser merchant = infoUserService.selectInfoUserByUserId(store.getUserId());
        if (merchant == null || StringUtils.isBlank(merchant.getBankAccountName())
                || StringUtils.isBlank(merchant.getBankName()) || StringUtils.isBlank(merchant.getBankAccountNo())) {
            return success(null);
        }
        JSONObject data = new JSONObject();
        data.put("accountName", merchant.getBankAccountName().trim());
        data.put("bankName", merchant.getBankName().trim());
        data.put("accountNo", merchant.getBankAccountNo().trim());
        return success(data);
    }

    //根据行业分类查询门店列表
    @Anonymous
    @GetMapping("/getstorelist")
    public AjaxResult getstorelist(@RequestParam BigDecimal longitude,
                                   @RequestParam BigDecimal latitude,
                                   @RequestParam Integer page,
                                   @RequestParam String area,
                                   @RequestParam Integer juli,
                                   @RequestParam(defaultValue = "") Integer sort,
                                   @RequestParam(defaultValue = "zh-TW", required = false) String language) {
        List<PosStore> list;
        if (sort == null) {
            list = posStoreMapper.getmdlist(longitude, latitude, (page - 1) * 20, "%" + area + "%", juli);
        } else {
            list = posStoreMapper.getdaidiq(longitude, latitude, (page - 1) * 20, "%" + area + "%", juli, sort);
        }

        posStoreEnrichService.enrichStoreList(list);

        // total 必须是符合条件总数，不能用当前页行数充当，否则客户端按 total 判断会误判"已加载完"导致翻页失效
        long total = sort == null
                ? posStoreMapper.getmdlistCount("%" + area + "%")
                : posStoreMapper.getdaidiqCount("%" + area + "%", sort);
        Page<StoreOutput> result = posStoreEnrichService.buildStoreOutputPage(list, language, page, total);
        return success(result);

    }

    //根据服务分类查询门店列表
    @Anonymous
    @GetMapping("/getserverlist")
    public AjaxResult getserverlist(@RequestParam BigDecimal longitude,
                                    @RequestParam BigDecimal latitude,
                                    @RequestParam Integer page,
                                    @RequestParam String area,
                                    @RequestParam Integer juli,
                                    @RequestParam(defaultValue = "") String serverType) {
        if (!"".equals(serverType)) {
            List<PosStore> list = posStoreMapper.getserverlist(longitude, latitude, (page - 1) * 20, "%" + area + "%", juli, "%" + serverType + "%");
            return success(list);
        } else {
            List<PosStore> list = posStoreMapper.getmdlist(longitude, latitude, (page - 1) * 20, "%" + area + "%", juli);
            return success(list);
        }

    }

    //添加门店
    @Anonymous
    @Auth(session = true)
    @PostMapping("/addmendian")
    @Transactional
    public AjaxResult addmendian(@RequestHeader String token, @RequestBody PosStore posStore) {
        Long loginUserId = AuthContext.requireUserId();
        InfoUser loginUser = infoUserService.selectInfoUserByUserId(loginUserId);
        if (posStore.getId() == null) {
            merchantStoreAccessService.requireOwner(loginUserId);
            userService.checkUserStatus(loginUserId);
            posStore.setUserId(loginUserId);
        } else {
            requireStoreAccess(loginUserId, loginUser, posStore.getId().longValue());
            PosStore existing = posStoreService.getById(posStore.getId());
            if (existing == null) {
                throw new ServiceException(MessageUtils.message("merchant.store.access.denied"));
            }
            posStore.setUserId(existing.getUserId());
        }
        try {
            // 1. 先保存门店信息
            Boolean org = posStoreService.saveOrUpdate(posStore);
            if (!org) {
                return error();
            }
            // 2. 查询保存后的门店信息（使用ID查询，避免锁等待）
            PosStore store;
            if (posStore.getId() != null) {
                store = posStoreService.getById(posStore.getId());
            } else {
                // 如果是新增，通过名称和用户ID查询
                QueryWrapper<PosStore> wrapper = new QueryWrapper<>();
                wrapper.eq("pos_name", posStore.getPosName());
                wrapper.eq("user_id", posStore.getUserId());
                store = posStoreService.getOne(wrapper);
            }

            if (store == null) {
                return error("门店信息保存失败");
            }

            // 3. 处理营业时间信息
            handlerBusinessHours(posStore, store);
            // 4. 统一保存统一编号(统编)到 pos_store_ezpay（不再走独立 saveUbn 接口）
            if (posStore.getUbn() != null) {
                posStoreEzpayService.uploadUbn(store.getId().longValue(), posStore.getUbn());
            }
            return success(MessageUtils.message("no.success"), store);
        } catch (ServiceException exception) {
            throw exception;
        } catch (Exception exception) {
            logger.error("保存商家门店失败,userId:{},storeId:{}", loginUserId, posStore.getId(), exception);
            return error(MessageUtils.message("no.system.error"));
        }
    }

    // 统一编号(统编)已并入 addmendian 保存、storelistlist 回显（存于 pos_store_ezpay），不再有独立 saveUbn/getUbn 接口

    /**
     * 更新门店信息处理营业时间
     * @param input
     * @param store
     */
    private void handlerBusinessHours(PosStore input, PosStore store) {
        if (input.getBusinessHours() != null && !input.getBusinessHours().isEmpty()) {
            // 先删除旧的营业时间记录
            LambdaQueryWrapper<OperatingHours> query = new LambdaQueryWrapper<>();
            query.eq(OperatingHours::getMdId, store.getId());
            operatingHoursService.remove(query);

            // 批量插入新的营业时间记录
            List<OperatingHours> operatingHours = new ArrayList<>();
            input.getBusinessHours().forEach(o -> {
                o.getTimeSlots().forEach(time -> {
                    OperatingHours op = new OperatingHours();
                    op.setStartTime(time.getStartTime());
                    op.setEndTime(time.getEndTime());
                    op.setDayOfWeek(time.getDayOfWeek());
                    op.setIsOpen(o.getIsOpen());
                    op.setMdId(Long.valueOf(store.getId()));
                    operatingHours.add(op);
                });
            });
            if (!operatingHours.isEmpty()) {
                operatingHoursService.saveBatch(operatingHours);
            }
        }
    }

    /**
     * （商家端app使用）获取门店营业时间
     * @param mdId 门店id
     * @return
     */
    @Anonymous
    @Auth(session = true)
    @GetMapping("/getMdBusinessHours")
    public AjaxResult getMdBusinessHours(@RequestHeader String token, @RequestParam Long mdId){
        Long userId = AuthContext.requireUserId();
        requireStoreAccess(userId, infoUserService.selectInfoUserByUserId(userId), mdId);
        LambdaQueryWrapper<OperatingHours> query=new LambdaQueryWrapper<>();
        query.eq(OperatingHours::getMdId,mdId);
        List<OperatingHours> list = operatingHoursService.list(query);
        List<StoreOperatOutput> data = new ArrayList<>();
        if(!list.isEmpty()){
            data = getStoreOperatOutput(list,mdId);
        }
        return success(data);
    }

    /**
     * 商家端app更新门店营业时间
     * @param businessHours
     * @return
     */
    @Anonymous
    @Auth(session = true)
    @PostMapping("/saveMdBusinessHours")
    public AjaxResult saveMdBusinessHours(@RequestHeader String token,
                                          @RequestBody List<StoreOperatOutput> businessHours) {
        if(businessHours == null || businessHours.isEmpty()) {
            throw new ServiceException(MessageUtils.message("no.mendian.not.set.business.hours"));
        }
        Long mdId = businessHours.get(0).getMdId();
        Long userId = AuthContext.requireUserId();
        requireStoreAccess(userId, infoUserService.selectInfoUserByUserId(userId), mdId);
        if (businessHours.stream().anyMatch(item -> !Objects.equals(mdId, item.getMdId()))) {
            throw new ServiceException(MessageUtils.message("merchant.store.access.denied"));
        }
        PosStore store = posStoreService.getById(businessHours.get(0).getMdId());
        // 先删除旧的营业时间记录
        LambdaQueryWrapper<OperatingHours> query = new LambdaQueryWrapper<>();
        query.eq(OperatingHours::getMdId, store.getId());
        operatingHoursService.remove(query);

        // 批量插入新的营业时间记录
        List<OperatingHours> operatingHours = new ArrayList<>();
        businessHours.forEach(o -> {
            o.getTimeSlots().forEach(time -> {
                OperatingHours op = new OperatingHours();
                op.setStartTime(time.getStartTime());
                op.setEndTime(time.getEndTime());
                op.setDayOfWeek(time.getDayOfWeek());
                op.setIsOpen(o.getIsOpen());
                op.setMdId(Long.valueOf(store.getId()));
                operatingHours.add(op);
            });
        });
        if(!operatingHours.isEmpty()) {
            operatingHoursService.saveBatch(operatingHours);
        }

        return success();
    }

    private void requireStoreAccess(Long loginUserId, InfoUser loginUser, Long storeId) {
        if (loginUser != null && "4".equals(loginUser.getUserType())) {
            if (!Objects.equals(loginUser.getStoreId(), storeId)) {
                throw new ServiceException(MessageUtils.message("merchant.store.access.denied"));
            }
            return;
        }
        merchantStoreAccessService.requireStoreAccess(loginUserId, storeId);
    }

    //返回营业时间（按星期分组）
    private List<StoreOperatOutput> getStoreOperatOutput(List<OperatingHours> list, Long mdId){
        List<StoreOperatOutput> data= new ArrayList<>();
        list=list.stream().filter(x-> x.getMdId().equals(mdId)).collect(Collectors.toList());
        if(!list.isEmpty()){
            Map<Integer,List<OperatingHours>> map = list.stream().collect(Collectors.groupingBy(OperatingHours::getDayOfWeek));
            map.forEach((k,v)->{
                data.add(new StoreOperatOutput(){
                    {
                        setMdId(mdId);
                        setDayOfWeek(k);
                        setIsOpen(v.get(0).getIsOpen());
                        setTimeSlots(v);
                    }
                });
            });
        }
        return data;
    }

    /**
     * 查询posstore列表
     */
    @PreAuthorize("@ss.hasPermi('chanting:store:list')")
//    @Anonymous
    @GetMapping("/list")
    public TableDataInfo list(PosStore posStore) {
        startPage();
        List<PosStore> list = posStoreService.selectPosStoreList(posStore);
        for (PosStore store : list) {
            InfoUser user = infoUserService.getById(store.getUserId());
            store.setUserName(user.getUserName());
        }
        return getDataTable(list);
    }

    /**
     * 导出posstore列表
     */
    @PreAuthorize("@ss.hasPermi('chanting:store:export')")
    @Log(title = "posstore", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, PosStore posStore) {
        List<PosStore> list = posStoreService.selectPosStoreList(posStore);
        ExcelUtil<PosStore> util = new ExcelUtil<PosStore>(PosStore.class);
        util.exportExcel(response, list, MessageUtils.message("no.export.excel.posstore"));
    }

    /**
     * 获取posstore详细信息
     */
    @PreAuthorize("@ss.hasPermi('chanting:store:query')")
    @GetMapping(value = "/{id:\\d+}")
    public AjaxResult getInfo(@PathVariable("id") Long id) {
        PosStore posStore = posStoreService.selectPosStoreById(id);
        // 回显营业时间（按周几分组的 timeSlots）与统一编号(统编)，供门店审核页显示
        if (posStore != null) {
            LambdaQueryWrapper<OperatingHours> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(OperatingHours::getMdId, id);
            posStore.setBusinessHours(getStoreOperatOutput(operatingHoursService.list(wrapper), id));
            // 统编实存于 pos_store_ezpay.ubn
            posStore.setUbn(posStoreEzpayService.getUbn(id));
        }
        return success(posStore);
    }

    /**
     * 新增posstore
     */
    @PreAuthorize("@ss.hasPermi('chanting:store:add')")
    @Log(title = "posstore", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@RequestBody PosStore posStore) {
        return toAjax(posStoreService.insertPosStore(posStore));
    }

    /**
     * 修改posstore
     */
    @PreAuthorize("@ss.hasPermi('chanting:store:edit')")
    @Log(title = "posstore", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@RequestBody PosStore posStore) {
        return toAjax(posStoreService.updatePosStore(posStore));
    }

    /**
     * 修改posstore下架状态
     */
    @Anonymous
    @PutMapping("/changeOffShelf")
    public AjaxResult changeOffShelf(@RequestBody PosStore posStore) {
        Boolean res = posStoreService.saveOrUpdate(posStore);
        if (res) {
            return success();
        } else {
            return error();
        }

    }

    /**
     * 删除posstore
     */
    @PreAuthorize("@ss.hasPermi('chanting:store:remove')")
    @Log(title = "posstore", businessType = BusinessType.DELETE)
    @DeleteMapping("/{ids}")
    public AjaxResult remove(@PathVariable Long[] ids) {
        return toAjax(posStoreService.deletePosStoreByIds(ids));
    }

    /**
     * 压缩图片店铺的商品图片
     */
    @Anonymous
    @GetMapping("/compressStoreImage")
    public AjaxResult compressStoreImage(@RequestParam String idsStr) {
        LambdaQueryWrapper<PosStore> queryWrapper = new LambdaQueryWrapper<>();

        List<Integer> ids = new ArrayList<>();
        if (!StringUtils.isEmpty(idsStr)) {
            ids = Arrays.stream(idsStr.split(","))
                    .map(Integer::valueOf)
                    .collect(Collectors.toList());
        }
        queryWrapper.in(!ids.isEmpty(), PosStore::getId, ids);
        List<PosStore> list = posStoreService.list(queryWrapper);
        AtomicInteger count = new AtomicInteger();
        list.forEach(food -> {
            String compressImage = ImageCompressUtils.compressImageByWebPath(food.getImage());
            if (!compressImage.equals(food.getImage())) {
                food.setImage(compressImage);
                PosStore posStore = new PosStore();
                posStore.setId(food.getId());
                posStore.setImage(compressImage);
                posStoreService.saveOrUpdate(posStore);
                count.getAndIncrement();
                System.out.println("store成功压缩的图片数量:" + count.get());
                logger.info("store成功压缩的图片数量:" + count.get());
            }
        });
        return success("成功压缩的图片数量:" + count.get());
    }

}
