package com.ruoyi.web.sales.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.web.base.domain.BaseMaterial;
import com.ruoyi.web.base.domain.BasePriceType;
import com.ruoyi.web.base.service.IBaseMaterialService;
import com.ruoyi.web.base.service.IBasePriceTypeService;
import com.ruoyi.web.sales.domain.SalesPrice;
import com.ruoyi.web.sales.domain.SalesPriceItem;
import com.ruoyi.web.sales.mapper.SalesPriceItemMapper;
import com.ruoyi.web.sales.service.ISalesPriceItemService;
import com.ruoyi.web.sales.service.ISalesPriceService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
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 javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static com.ruoyi.common.core.domain.AjaxResult.success;
import static com.ruoyi.common.utils.SecurityUtils.getUsername;

@RestController
@Api(tags = "价格管理")
@RequestMapping("/price")
public class SalesPriceController {

    @Autowired
    private ISalesPriceService salesPriceService;
    @Autowired
    private ISalesPriceItemService salesPriceItemService;
    @Autowired
    private SalesPriceItemMapper salesPriceItemMapper;
    @Autowired
    private IBaseMaterialService baseMaterialService;
    @Autowired
    private IBasePriceTypeService basePriceTypeService;
    @Autowired
    private TokenService tokenService;

    @ApiOperation("价格管理新增")
    @PreAuthorize("@ss.hasPermi('base:price:add')")
    @PostMapping("/add")
    @Transactional
    public AjaxResult add(@RequestBody SalesPrice price, HttpServletRequest request) throws Exception {
        String orgId = tokenService.getLoginOrgId(request);
        // 新增时后台统一生成价格单编号：确保组织内唯一
        price.setPriceNum(nextAvailablePriceNum(orgId));
        validateBeforeSave(price, orgId, true);
        price.setOrgId(orgId);
        price.setDelFlag("0");
        String username = getUsername();
        price.setCreateBy(username);
        price.setCreateTime(new Date());
        price.setUpdateBy(null);
        price.setUpdateTime(null);
        salesPriceService.save(price);
        saveItems(price, orgId, username);
        return success();
    }

    @ApiOperation("价格管理批量新增")
    @PreAuthorize("@ss.hasPermi('base:price:add')")
    @PostMapping("/batchAdd")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult batchAdd(@RequestBody List<SalesPrice> prices, HttpServletRequest request) throws Exception {
        if (prices == null || prices.isEmpty()) {
            throw new Exception("数据不能为空");
        }
        String orgId = tokenService.getLoginOrgId(request);
        String username = getUsername();
        Date now = new Date();
        for (SalesPrice price : prices) {
            if (price == null) {
                throw new Exception("存在空对象");
            }
            price.setId(null);
            price.setPriceNum(nextAvailablePriceNum(orgId));
            validateBeforeSave(price, orgId, true);
            price.setOrgId(orgId);
            price.setDelFlag("0");
            price.setCreateBy(username);
            price.setCreateTime(now);
            price.setUpdateBy(null);
            price.setUpdateTime(null);
            salesPriceService.save(price);
            saveItems(price, orgId, username);
        }
        return success();
    }

    @ApiOperation("价格管理修改")
    @PreAuthorize("@ss.hasPermi('base:price:edit')")
    @PostMapping("/edit")
    @Transactional
    public AjaxResult edit(@RequestBody SalesPrice price, HttpServletRequest request) throws Exception {
        if (price.getId() == null) {
            throw new Exception("id不能为空");
        }
        SalesPrice old = salesPriceService.getById(price.getId());
        if (old == null || !"0".equals(old.getDelFlag())) {
            throw new Exception("价格单不存在");
        }
        String orgId = tokenService.getLoginOrgId(request);
        validateBeforeSave(price, orgId, false);
        price.setOrgId(orgId);
        String username = getUsername();
        price.setCreateBy(old.getCreateBy());
        price.setCreateTime(old.getCreateTime());
        price.setUpdateBy(username);
        price.setUpdateTime(new Date());
        salesPriceService.updateById(price);
        salesPriceItemService.remove(new QueryWrapper<SalesPriceItem>()
                .eq("org_id", orgId)
                .eq("price_num", old.getPriceNum()));
        saveItems(price, orgId, username);
        return success();
    }

    @ApiOperation("价格管理删除")
    @PreAuthorize("@ss.hasPermi('base:price:remove')")
    @PostMapping("/delete")
    public AjaxResult delete(@RequestBody Map<String, String> params) throws Exception {
        String ids = params.get("ids");
        for (String id : ids.split(",")) {
            SalesPrice price = salesPriceService.getById(id);
            if (price == null || !"0".equals(price.getDelFlag())) {
                continue;
            }
            SalesPrice up = new SalesPrice();
            up.setId(Integer.valueOf(id));
            up.setDelFlag("2");
            up.setUpdateBy(getUsername());
            up.setUpdateTime(new Date());
            salesPriceService.updateById(up);

            // 主表删除时，同步将子表明细逻辑删除
            SalesPriceItem itemUp = new SalesPriceItem();
            itemUp.setDelFlag("2");
            itemUp.setUpdateBy(getUsername());
            itemUp.setUpdateTime(new Date());
            salesPriceItemService.update(itemUp, new QueryWrapper<SalesPriceItem>()
                    .eq("org_id", price.getOrgId())
                    .eq("price_num", price.getPriceNum())
                    .eq("del_flag", "0"));
        }
        return success();
    }

    @ApiOperation("价格管理详情")
    @PreAuthorize("@ss.hasPermi('base:price:query')")
    @PostMapping("/listById")
    public AjaxResult listById(@RequestBody Map<String, String> params, HttpServletRequest request) {
        String id = params.get("id");
        SalesPrice price = salesPriceService.getById(id);
        if (price == null) {
            return success(null);
        }
        String orgId = tokenService.getLoginOrgId(request);
        List<SalesPriceItem> items = salesPriceItemService.list(new QueryWrapper<SalesPriceItem>()
                .eq("org_id", orgId)
                .eq("price_num", price.getPriceNum())
                .eq("del_flag", "0")
                .orderByAsc("id"));
        enrichItemsFromMaterial(items, orgId);
        price.setItems(items);
        enrichSalesPriceTypeNames(Collections.singletonList(price), orgId);
        return success(price);
    }

    @ApiOperation("价格管理分页")
    @PreAuthorize("@ss.hasPermi('base:price:list')")
    @GetMapping("/page")
    public AjaxResult page(@RequestParam("pageNum") Integer pageNum,
                           @RequestParam("pageSize") Integer pageSize,
                           SalesPrice query,
                           HttpServletRequest request) {
        String orgId = tokenService.getLoginOrgId(request);
        QueryWrapper<SalesPrice> wrapper = buildWrapper(query, orgId);
        Page<SalesPrice> page = salesPriceService.page(new Page<SalesPrice>(pageNum, pageSize), wrapper);
        enrichSalesPriceTypeNames(page.getRecords(), orgId);
        return success(page);
    }

    @ApiOperation("物料价格明细列表：按价格类型编码、主表执行日期区间筛 sales_price，返回符合条件的 sales_price_item（含单价、自提价及主表类型/日期）")
    @PreAuthorize("@ss.hasPermi('base:price:list')")
    @GetMapping("/list")
    public AjaxResult list(SalesPrice query, HttpServletRequest request) {
        String orgId = tokenService.getLoginOrgId(request);
        String priceType = query == null || StringUtils.isBlank(query.getPriceType()) ? null : query.getPriceType().trim();
        List<SalesPriceItem> items = salesPriceItemMapper.listByJoin(
                orgId,
                priceType,
                query == null ? null : query.getEffectiveDateStart(),
                query == null ? null : query.getEffectiveDateEnd()
        );
        enrichItemsFromMaterial(items, orgId);
        return success(items);
    }

    @ApiOperation("获取新增价格页面数据")
    @PreAuthorize("@ss.hasPermi('base:price:add')")
    @PostMapping("/getAddPageData")
    public AjaxResult getAddPageData(HttpServletRequest request) {
        // 执行日期/失效日期均默认取“当前日期后一天”
        String tomorrow = LocalDate.now().plusDays(1).format(DateTimeFormatter.ISO_LOCAL_DATE);
        Map<String, Object> data = new HashMap<String, Object>();
        data.put("effectiveDate", tomorrow);
        data.put("expireDate", tomorrow);
        return success(data);
    }

    @ApiOperation("价格管理导出")
    @PreAuthorize("@ss.hasPermi('base:price:export')")
    @PostMapping("/export")
    public void export(HttpServletResponse response, SalesPrice query, HttpServletRequest request) {
        String orgId = tokenService.getLoginOrgId(request);
        List<SalesPrice> list = salesPriceService.list(buildWrapper(query, orgId));
        enrichSalesPriceTypeNames(list, orgId);
        ExcelUtil<SalesPrice> util = new ExcelUtil<SalesPrice>(SalesPrice.class);
        util.exportExcel(response, list, "价格管理");
    }

    @ApiOperation("价格管理打印数据")
    @PreAuthorize("@ss.hasPermi('base:price:print')")
    @PostMapping("/print")
    public AjaxResult print(@RequestBody Map<String, String> params, HttpServletRequest request) throws Exception {
        SalesPrice price = getActiveById(params.get("id"));
        String orgId = tokenService.getLoginOrgId(request);
        List<SalesPriceItem> items = salesPriceItemService.list(new QueryWrapper<SalesPriceItem>()
                .eq("org_id", orgId)
                .eq("price_num", price.getPriceNum())
                .eq("del_flag", "0")
                .orderByAsc("id"));
        enrichItemsFromMaterial(items, orgId);
        price.setItems(items);
        enrichSalesPriceTypeNames(Collections.singletonList(price), orgId);
        return success(price);
    }

    /** sales_price.price_type 与 base_price_type.price_type_num 匹配，填充 priceTypeName */
    private void enrichSalesPriceTypeNames(List<SalesPrice> rows, String orgId) {
        if (rows == null || rows.isEmpty() || StringUtils.isBlank(orgId)) {
            return;
        }
        Set<String> nums = new LinkedHashSet<String>();
        for (SalesPrice p : rows) {
            if (StringUtils.isNotBlank(p.getPriceType())) {
                nums.add(p.getPriceType().trim());
            }
        }
        if (nums.isEmpty()) {
            return;
        }
        List<BasePriceType> types = basePriceTypeService.list(new QueryWrapper<BasePriceType>()
                .eq("org_id", orgId)
                .in("price_type_num", nums));
        Map<String, String> nameByNum = new HashMap<String, String>();
        for (BasePriceType t : types) {
            if (t.getPriceTypeNum() == null || StringUtils.isBlank(t.getPriceTypeName())) {
                continue;
            }
            String key = t.getPriceTypeNum().trim();
            if (!nameByNum.containsKey(key)) {
                nameByNum.put(key, t.getPriceTypeName().trim());
            }
        }
        for (SalesPrice p : rows) {
            if (StringUtils.isBlank(p.getPriceType())) {
                continue;
            }
            String nm = nameByNum.get(p.getPriceType().trim());
            if (StringUtils.isNotBlank(nm)) {
                p.setPriceTypeName(nm);
            }
        }
    }

    private QueryWrapper<SalesPrice> buildWrapper(SalesPrice query, String orgId) {
        QueryWrapper<SalesPrice> wrapper = new QueryWrapper<SalesPrice>()
                .eq("org_id", orgId)
                .eq("del_flag", "0");
        if (query == null) {
            return wrapper.orderByDesc("id");
        }
        if (StringUtils.isNotBlank(query.getPriceNum())) {
            wrapper.like("price_num", query.getPriceNum());
        }
        if (StringUtils.isNotBlank(query.getPriceType())) {
            wrapper.eq("price_type", query.getPriceType().trim());
        }
        if (query.getEffectiveDateStart() != null) {
            wrapper.ge("effective_date", query.getEffectiveDateStart());
        }
        if (query.getEffectiveDateEnd() != null) {
            wrapper.le("effective_date", query.getEffectiveDateEnd());
        }
        return wrapper.orderByDesc("id");
    }

    private void validateBeforeSave(SalesPrice price, String orgId, boolean isAdd) throws Exception {
        if (price == null) {
            throw new Exception("参数不能为空");
        }
        if (StringUtils.isBlank(price.getPriceType())) {
            throw new Exception("价格类型不能为空");
        }
        price.setPriceType(price.getPriceType().trim());
        if (!isAdd && StringUtils.isBlank(price.getPriceNum())) {
            throw new Exception("价格单编号不能为空");
        }
        if (price.getEffectiveDate() == null || price.getExpireDate() == null) {
            throw new Exception("执行日期和失效日期不能为空");
        }
        if (price.getExpireDate().before(price.getEffectiveDate())) {
            throw new Exception("失效日期不能早于执行日期");
        }

        // 同一价格类型 + 同一执行日期（未删除）仅允许一条主表记录
        // effective_date 为 date 类型，直接按日期精确匹配
        QueryWrapper<SalesPrice> effectiveWrapper = new QueryWrapper<SalesPrice>()
                .eq("org_id", orgId)
                .eq("del_flag", "0")
                .eq("price_type", price.getPriceType())
                .eq("effective_date", price.getEffectiveDate());
        if (!isAdd && price.getId() != null) {
            effectiveWrapper.ne("id", price.getId());
        }
        if (salesPriceService.count(effectiveWrapper) > 0) {
            throw new Exception("该价格类型在执行日期已存在价格单");
        }

        QueryWrapper<SalesPrice> numWrapper = new QueryWrapper<SalesPrice>()
                .eq("org_id", orgId)
                .eq("price_num", price.getPriceNum())
                .eq("price_type", price.getPriceType())
                .eq("del_flag", "0");
        if (!isAdd && price.getId() != null) {
            numWrapper.ne("id", price.getId());
        }
        if (salesPriceService.count(numWrapper) > 0) {
            throw new Exception("该价格单编号已存在");
        }
        if (price.getItems() == null || price.getItems().isEmpty()) {
            throw new Exception("价格明细不能为空");
        }
        for (SalesPriceItem item : price.getItems()) {
            if (StringUtils.isBlank(item.getMaterialNum())) {
                throw new Exception("明细物料编号不能为空");
            }
            if (item.getUnitPrice() == null) {
                throw new Exception("明细单价不能为空");
            }
        }
    }

    /**
     * 生成组织内未占用的价格单编号：
     * P + 次日yyyyMMdd + 5位递增序号（不足补0，从00001开始）
     */
    private String nextAvailablePriceNum(String orgId) throws Exception {
        String ymd = LocalDate.now().plusDays(1).format(DateTimeFormatter.BASIC_ISO_DATE);
        String prefix = "P" + ymd;

        // 先取已存在最大后缀，作为起始序号（避免每次都从 00001 开始扫描）
        SalesPrice last = salesPriceService.getOne(new QueryWrapper<SalesPrice>()
                .eq("org_id", orgId)
                .eq("del_flag", "0")
                .like("price_num", prefix)
                .orderByDesc("price_num")
                .last("limit 1"));

        int startSeq = 1;
        if (last != null && StringUtils.isNotBlank(last.getPriceNum())) {
            String pn = last.getPriceNum().trim();
            // pn 应为：PyyyyMMdd + 5位数字
            if (pn.startsWith(prefix) && pn.length() == prefix.length() + 5) {
                String suffix = pn.substring(prefix.length());
                try {
                    startSeq = Integer.parseInt(suffix) + 1;
                } catch (Exception ignored) {
                    startSeq = 1;
                }
            }
        }

        for (int seq = startSeq; seq <= 99999; seq++) {
            String candidate = prefix + String.format("%05d", seq);
            long occupied = salesPriceService.count(new QueryWrapper<SalesPrice>()
                    .eq("org_id", orgId)
                    .eq("price_num", candidate)
                    .eq("del_flag", "0"));
            if (occupied == 0) {
                return candidate;
            }
        }
        throw new Exception("无法生成唯一价格单编号");
    }

    private void saveItems(SalesPrice price, String orgId, String username) {
        List<SalesPriceItem> items = price.getItems();
        if (items == null) {
            items = Collections.emptyList();
        }
        Date now = new Date();
        for (SalesPriceItem item : items) {
            item.setId(null);
            item.setOrgId(orgId);
            item.setPriceNum(price.getPriceNum());
            item.setDelFlag("0");
            item.setCreateBy(username);
            item.setCreateTime(now);
            item.setUpdateBy(null);
            item.setUpdateTime(null);
            salesPriceItemService.save(item);
        }
    }

    private void enrichItemsFromMaterial(List<SalesPriceItem> items, String orgId) {
        if (items == null || items.isEmpty()) {
            return;
        }
        for (SalesPriceItem item : items) {
            if (StringUtils.isBlank(item.getMaterialNum())) {
                continue;
            }
            BaseMaterial material = baseMaterialService.getOne(new QueryWrapper<BaseMaterial>()
                    .eq("org_id", orgId)
                    .eq("goods_num", item.getMaterialNum())
                    .eq("del_flag", "0")
                    .last("limit 1"));
            if (material != null) {
                item.setMaterialName(material.getGoodsName());
                item.setMaterialSpec(material.getGoodsSpec());
                if (StringUtils.isBlank(item.getLevel())) {
                    item.setLevel(material.getGoodsLevel());
                }
                if (StringUtils.isBlank(item.getVariety())) {
                    String v = material.getVariety();
                    if (StringUtils.isBlank(v)) {
                        v = material.getVarietyName();
                    }
                    item.setVariety(v);
                }
                if (StringUtils.isBlank(item.getUnit())) {
                    item.setUnit(material.getUnit());
                }
            }
        }
    }

    private SalesPrice getActiveById(String id) throws Exception {
        SalesPrice price = salesPriceService.getById(id);
        if (price == null || !"0".equals(price.getDelFlag())) {
            throw new Exception("价格单不存在");
        }
        return price;
    }
}
