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.BaseEmployee;
import com.ruoyi.web.base.domain.BaseMaterial;
import com.ruoyi.web.base.service.IBaseEmployeeService;
import com.ruoyi.web.base.service.IBaseMaterialService;
import com.ruoyi.web.sales.domain.*;
import com.ruoyi.web.sales.service.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

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

@RestController
@Api(tags = "销售折让单")
@RequestMapping("/sales-allowance")
public class SalesAllowanceController {

    @Autowired
    private ISalesAllowanceService salesAllowanceService;
    @Autowired
    private ISalesAllowanceItemService salesAllowanceItemService;
    @Autowired
    private ISalesDeliveryService salesDeliveryService;
    @Autowired
    private ISalesDeliveryGoodsService salesDeliveryGoodsService;
    @Autowired
    private IBaseCustomerService customerService;
    @Autowired
    private IBaseEmployeeService baseEmployeeService;
    @Autowired
    private IBaseMaterialService baseMaterialService;
    @Autowired
    private TokenService tokenService;

    @ApiOperation("销售折让单新增")
    @PostMapping("/add")
    @Transactional
    public AjaxResult add(@RequestBody SalesAllowance allowance, HttpServletRequest request) throws Exception {
        String orgId = tokenService.getLoginOrgId(request);
        validateBeforeSave(allowance, orgId, true);
        fillCustomerInfo(allowance, orgId);
        recalcItemAmountAndTotal(allowance);
        allowance.setOrgId(orgId);
        allowance.setDelFlag("0");
        allowance.setAuditStatus(1);
        if (allowance.getOffsetStatus() == null) {
            allowance.setOffsetStatus(0);
        }
        String username = getUsername();
        allowance.setId(null);
        allowance.setCreateBy(username);
        allowance.setCreateTime(new Date());
        allowance.setUpdateBy(null);
        allowance.setUpdateTime(null);
        salesAllowanceService.save(allowance);
        saveItems(allowance, orgId, username);
        return success();
    }

    @ApiOperation("销售折让单修改")
    @PostMapping("/edit")
    @Transactional
    public AjaxResult edit(@RequestBody SalesAllowance allowance, HttpServletRequest request) throws Exception {
        if (allowance.getId() == null) {
            throw new Exception("id不能为空");
        }
        SalesAllowance old = salesAllowanceService.getById(allowance.getId());
        if (old == null || !"0".equals(old.getDelFlag())) {
            throw new Exception("销售折让单不存在");
        }
        if (old.getAuditStatus() != null && old.getAuditStatus() == 1) {
            throw new Exception("已审核的销售折让单不能修改，请先反审核");
        }
        if (old.getOffsetStatus() != null && old.getOffsetStatus() == 1) {
            throw new Exception("已冲销的销售折让单不能修改");
        }
        String orgId = tokenService.getLoginOrgId(request);
        validateBeforeSave(allowance, orgId, false);
        fillCustomerInfo(allowance, orgId);
        recalcItemAmountAndTotal(allowance);
        allowance.setOrgId(orgId);
        allowance.setAuditStatus(1);
        allowance.setOffsetStatus(old.getOffsetStatus());
        String username = getUsername();
        allowance.setCreateBy(old.getCreateBy());
        allowance.setCreateTime(old.getCreateTime());
        allowance.setUpdateBy(username);
        allowance.setUpdateTime(new Date());
        salesAllowanceService.updateById(allowance);
        String oldNum = StringUtils.isNotBlank(old.getAllowanceNum()) ? old.getAllowanceNum().trim() : null;
        deleteItemsByAllowanceNum(orgId, oldNum);
        saveItems(allowance, orgId, username);
        return success();
    }

    @ApiOperation("销售折让单删除")
    @PostMapping("/delete")
    public AjaxResult delete(@RequestBody Map<String, String> params) throws Exception {
        String ids = params.get("ids");
        for (String id : ids.split(",")) {
            SalesAllowance allowance = salesAllowanceService.getById(id);
            if (allowance == null || !"0".equals(allowance.getDelFlag())) {
                continue;
            }
            if (allowance.getAuditStatus() != null && allowance.getAuditStatus() == 1) {
                throw new Exception("已审核的销售折让单不能删除，请先反审核");
            }
            if (allowance.getOffsetStatus() != null && allowance.getOffsetStatus() == 1) {
                throw new Exception("已冲销的销售折让单不能删除");
            }
            deleteItemsByAllowanceNum(allowance.getOrgId(), allowance.getAllowanceNum());
            SalesAllowance up = new SalesAllowance();
            up.setId(Integer.valueOf(id));
            up.setDelFlag("2");
            up.setUpdateBy(getUsername());
            up.setUpdateTime(new Date());
            salesAllowanceService.updateById(up);
        }
        return success();
    }

    @ApiOperation("销售折让单详情")
    @PostMapping("/listById")
    public AjaxResult listById(@ApiParam("详情参数: id") @RequestBody Map<String, String> params, HttpServletRequest request) {
        SalesAllowance allowance = salesAllowanceService.getById(params.get("id"));
        if (allowance == null) {
            return success(null);
        }
        String orgId = tokenService.getLoginOrgId(request);
        List<SalesAllowanceItem> items = salesAllowanceItemService.list(new QueryWrapper<SalesAllowanceItem>()
                .eq("org_id", orgId)
                .eq("allowance_num", allowance.getAllowanceNum())
                .eq("del_flag", "0"));
        allowance.setItems(items);
        enrichAllowanceDisplay(allowance, orgId);
        return success(allowance);
    }

    @ApiOperation("销售折让单分页")
    @GetMapping("/page")
    public AjaxResult page(@RequestParam("pageNum") Integer pageNum,
                           @RequestParam("pageSize") Integer pageSize,
                           SalesAllowance query,
                           HttpServletRequest request) {
        String orgId = tokenService.getLoginOrgId(request);
        QueryWrapper<SalesAllowance> wrapper = buildWrapper(query, orgId);
        Page<SalesAllowance> page = salesAllowanceService.page(new Page<SalesAllowance>(pageNum, pageSize), wrapper);
        for (SalesAllowance row : page.getRecords()) {
            enrichAllowanceDisplay(row, orgId);
        }
        return success(page);
    }

    @ApiOperation("销售折让单列表")
    @PostMapping("/list")
    public AjaxResult list(@RequestBody SalesAllowance query, HttpServletRequest request) {
        String orgId = tokenService.getLoginOrgId(request);
        List<SalesAllowance> list = salesAllowanceService.list(buildWrapper(query, orgId));
        for (SalesAllowance row : list) {
            enrichAllowanceDisplay(row, orgId);
        }
        attachItemsForListRows(list, orgId);
        return success(list);
    }

    @ApiOperation("销售折让单导出")
    @PostMapping("/export")
    public void export(HttpServletResponse response, SalesAllowance query, HttpServletRequest request) {
        String orgId = tokenService.getLoginOrgId(request);
        List<SalesAllowance> list = salesAllowanceService.list(buildWrapper(query, orgId));
        for (SalesAllowance row : list) {
            enrichAllowanceDisplay(row, orgId);
        }
        ExcelUtil<SalesAllowance> util = new ExcelUtil<SalesAllowance>(SalesAllowance.class);
        util.exportExcel(response, list, "销售折让单");
    }

    @ApiOperation("销售折让单审核")
    @PostMapping("/audit")
    public AjaxResult audit(@RequestBody Map<String, String> params) throws Exception {
        SalesAllowance allowance = getActiveById(params.get("id"));
        allowance.setAuditStatus(1);
        allowance.setUpdateBy(getUsername());
        allowance.setUpdateTime(new Date());
        return success(salesAllowanceService.updateById(allowance));
    }

    @ApiOperation("销售折让单反审核")
    @PostMapping("/unaudit")
    public AjaxResult unaudit(@RequestBody Map<String, String> params) throws Exception {
        SalesAllowance allowance = getActiveById(params.get("id"));
        if (allowance.getOffsetStatus() != null && allowance.getOffsetStatus() == 1) {
            throw new Exception("已做冲销的销售折让单不可反审核");
        }
        allowance.setAuditStatus(0);
        allowance.setUpdateBy(getUsername());
        allowance.setUpdateTime(new Date());
        return success(salesAllowanceService.updateById(allowance));
    }

    @ApiOperation("销售折让单打印数据")
    @PostMapping("/print")
    public AjaxResult print(@RequestBody Map<String, String> params, HttpServletRequest request) throws Exception {
        SalesAllowance allowance = getActiveById(params.get("id"));
        String orgId = tokenService.getLoginOrgId(request);
        List<SalesAllowanceItem> items = salesAllowanceItemService.list(new QueryWrapper<SalesAllowanceItem>()
                .eq("org_id", orgId)
                .eq("allowance_num", allowance.getAllowanceNum())
                .eq("del_flag", "0"));
        allowance.setItems(items);
        enrichAllowanceDisplay(allowance, orgId);
        return success(allowance);
    }

    @ApiOperation("获取新增销售折让单页面数据")
    @PostMapping("/getAddPageData")
    public AjaxResult getAddPageData(HttpServletRequest request) throws Exception {
        String orgId = tokenService.getLoginOrgId(request);
        String tomorrow = LocalDate.now().plusDays(1).format(DateTimeFormatter.ISO_LOCAL_DATE);
        Map<String, Object> data = new HashMap<String, Object>();
        data.put("allowanceDate", tomorrow);
        data.put("allowanceNum", generateSalesAllowanceNum(orgId));
        return success(data);
    }

    @ApiOperation("按销售出库单生成折让清单行(追加用，优先传主键id以避免单号重复时误命中)")
    @PostMapping("/fillLinesByDelivery")
    public AjaxResult fillLinesByDelivery(@RequestBody Map<String, String> params, HttpServletRequest request) throws Exception {
        String orgId = tokenService.getLoginOrgId(request);
        SalesDelivery delivery = resolveDeliveryForFill(params, orgId);
        return success(buildAllowanceItemsFromDelivery(delivery, orgId));
    }

    @ApiOperation("按销售出库单编号生成折让清单行(追加用)")
    @PostMapping("/fillLinesByDeliveryNum")
    public AjaxResult fillLinesByDeliveryNum(@RequestBody Map<String, String> params, HttpServletRequest request) throws Exception {
        String orgId = tokenService.getLoginOrgId(request);
        SalesDelivery delivery = resolveDeliveryForFill(params, orgId);
        return success(buildAllowanceItemsFromDelivery(delivery, orgId));
    }

    private SalesDelivery resolveDeliveryForFill(Map<String, String> params, String orgId) throws Exception {
        String id = params.get("id");
        if (StringUtils.isNotBlank(id)) {
            SalesDelivery delivery = salesDeliveryService.getById(id.trim());
            if (delivery == null || !orgId.equals(delivery.getOrgId()) || !"0".equals(delivery.getDelFlag())) {
                throw new Exception("销售出库单不存在");
            }
            return delivery;
        }
        String deliveryNum = params.get("deliveryNum");
        if (StringUtils.isBlank(deliveryNum)) {
            throw new Exception("销售出库单主键id或编号不能为空");
        }
        SalesDelivery delivery = salesDeliveryService.getOne(new QueryWrapper<SalesDelivery>()
                .eq("org_id", orgId).eq("delivery_num", deliveryNum.trim()).eq("del_flag", "0").orderByDesc("id").last("limit 1"));
        if (delivery == null) {
            throw new Exception("销售出库单不存在");
        }
        return delivery;
    }

    private List<SalesAllowanceItem> buildAllowanceItemsFromDelivery(SalesDelivery delivery, String orgId) {
        List<SalesDeliveryGoods> deliveryGoods = salesDeliveryGoodsService.list(new QueryWrapper<SalesDeliveryGoods>()
                .eq("org_id", orgId).eq("delivery_num", delivery.getDeliveryNum()).eq("del_flag", "0"));
        List<SalesAllowanceItem> items = new ArrayList<SalesAllowanceItem>();
        for (SalesDeliveryGoods g : deliveryGoods) {
            SalesAllowanceItem item = new SalesAllowanceItem();
            item.setDeliveryNum(delivery.getDeliveryNum());
            item.setSalesDate(delivery.getDocumentDate());
            item.setBatchNum(g.getBatchNum());
            BaseMaterial m = null;
            if (StringUtils.isNotBlank(g.getGoodsNum())) {
                m = baseMaterialService.getOne(new QueryWrapper<BaseMaterial>()
                        .eq("org_id", orgId).eq("goods_num", g.getGoodsNum()).eq("del_flag", "0").last("limit 1"));
            }
            item.setGoodsName(m != null ? m.getGoodsName() : null);
            item.setGoodsNum(g.getGoodsNum());
            item.setQuantity(g.getBaseNum());
            item.setUnit(g.getBaseUnit());
            item.setUnitPrice(g.getUnitPrice());
            BigDecimal p = parseMoney(item.getUnitPrice());
            BigDecimal q = parseMoney(item.getQuantity());
            item.setAmount((p != null && q != null) ? formatMoney(p.multiply(q)) : g.getAmount());
            item.setGoodsRemark(g.getGoodsRemark());
            items.add(item);
        }
        return items;
    }

    private QueryWrapper<SalesAllowance> buildWrapper(SalesAllowance query, String orgId) {
        QueryWrapper<SalesAllowance> wrapper = new QueryWrapper<SalesAllowance>()
                .eq("org_id", orgId).eq("del_flag", "0");
        if (query == null) {
            return wrapper.orderByDesc("id");
        }
        if (query.getAllowanceDateStart() != null) {
            wrapper.ge("allowance_date", query.getAllowanceDateStart());
        }
        if (query.getAllowanceDateEnd() != null) {
            wrapper.le("allowance_date", query.getAllowanceDateEnd());
        }
        if (StringUtils.isNotBlank(query.getAllowanceNum())) {
            wrapper.like("allowance_num", query.getAllowanceNum());
        }
        if (StringUtils.isNotBlank(query.getCustomerNum())) {
            wrapper.like("customer_num", query.getCustomerNum());
        }
        if (StringUtils.isNotBlank(query.getCustomerName())) {
            String safe = query.getCustomerName().trim().replace("'", "''");
            wrapper.inSql("customer_num", "SELECT customer_num FROM base_customer WHERE org_id='" + orgId + "' AND del_flag='0' AND customer_name LIKE '%" + safe + "%'");
        }
        if (StringUtils.isNotBlank(query.getEmployeeNum())) {
            wrapper.like("employee_num", query.getEmployeeNum());
        }
        if (StringUtils.isNotBlank(query.getDepartmentNum())) {
            wrapper.like("department_num", query.getDepartmentNum());
        }
        if (StringUtils.isNotBlank(query.getRemark())) {
            wrapper.like("remark", query.getRemark());
        }
        if (query.getAuditStatus() != null) {
            wrapper.eq("audit_status", query.getAuditStatus());
        }
        return wrapper.orderByDesc("id");
    }

    private void validateBeforeSave(SalesAllowance allowance, String orgId, boolean isAdd) throws Exception {
        if (allowance == null) {
            throw new Exception("参数不能为空");
        }
        if (StringUtils.isAnyBlank(allowance.getAllowanceNum(), allowance.getCustomerNum())) {
            throw new Exception("折让编号、客户编号不能为空");
        }
        QueryWrapper<SalesAllowance> numWrapper = new QueryWrapper<SalesAllowance>()
                .eq("org_id", orgId).eq("allowance_num", allowance.getAllowanceNum()).eq("del_flag", "0");
        if (!isAdd && allowance.getId() != null) {
            numWrapper.ne("id", allowance.getId());
        }
        if (salesAllowanceService.count(numWrapper) > 0) {
            throw new Exception("该折让编号已存在");
        }
        if (allowance.getItems() == null || allowance.getItems().isEmpty()) {
            throw new Exception("销售出库单清单不能为空");
        }
        if (StringUtils.isNotBlank(allowance.getEmployeeNum())) {
            BaseEmployee emp = baseEmployeeService.getOne(new QueryWrapper<BaseEmployee>()
                    .eq("org_id", orgId).eq("employee_num", allowance.getEmployeeNum().trim()).eq("del_flag", "0").last("limit 1"));
            if (emp == null) {
                throw new Exception("业务员编号不存在");
            }
        }
    }

    private void fillCustomerInfo(SalesAllowance allowance, String orgId) throws Exception {
        BaseCustomer customer = customerService.getOne(new QueryWrapper<BaseCustomer>()
                .eq("org_id", orgId).eq("customer_num", allowance.getCustomerNum()).eq("del_flag", "0").last("limit 1"));
        if (customer == null) {
            throw new Exception("客户编号不存在");
        }
    }

    private void recalcItemAmountAndTotal(SalesAllowance allowance) {
        List<SalesAllowanceItem> items = allowance.getItems();
        if (items == null || items.isEmpty()) {
            allowance.setTotalAmount(null);
            return;
        }
        BigDecimal sum = BigDecimal.ZERO;
        boolean any = false;
        for (SalesAllowanceItem it : items) {
            BigDecimal p = parseMoney(it.getUnitPrice());
            BigDecimal q = parseMoney(it.getQuantity());
            BigDecimal line = (p != null && q != null) ? p.multiply(q) : parseMoney(it.getAmount());
            if (line != null) {
                it.setAmount(formatMoney(line));
                sum = sum.add(line);
                any = true;
            } else {
                it.setAmount(null);
            }
        }
        allowance.setTotalAmount(any ? formatMoney(sum) : null);
    }

    private void saveItems(SalesAllowance allowance, String orgId, String username) {
        List<SalesAllowanceItem> items = allowance.getItems();
        if (items == null) {
            items = Collections.emptyList();
        }
        Date now = new Date();
        for (SalesAllowanceItem it : items) {
            it.setId(null);
            it.setOrgId(orgId);
            it.setAllowanceNum(allowance.getAllowanceNum());
            it.setDelFlag("0");
            it.setCreateBy(username);
            it.setCreateTime(now);
            it.setUpdateBy(null);
            it.setUpdateTime(null);
            salesAllowanceItemService.save(it);
        }
    }

    /**
     * 列表接口带出折让明细：按折让单号批量查子表，与 listById 一致。
     */
    private void attachItemsForListRows(List<SalesAllowance> list, String orgId) {
        if (list == null || list.isEmpty()) {
            return;
        }
        List<String> allowanceNums = list.stream()
                .filter(a -> a != null && StringUtils.isNotBlank(a.getAllowanceNum()))
                .map(a -> a.getAllowanceNum().trim())
                .distinct()
                .collect(Collectors.toList());
        if (allowanceNums.isEmpty()) {
            return;
        }
        List<SalesAllowanceItem> allItems = salesAllowanceItemService.list(new QueryWrapper<SalesAllowanceItem>()
                .eq("org_id", orgId)
                .in("allowance_num", allowanceNums)
                .eq("del_flag", "0")
                .orderByAsc("id"));
        Map<String, List<SalesAllowanceItem>> byAllowanceNum = new HashMap<String, List<SalesAllowanceItem>>();
        for (SalesAllowanceItem it : allItems) {
            if (it == null || StringUtils.isBlank(it.getAllowanceNum())) {
                continue;
            }
            String key = it.getAllowanceNum().trim();
            byAllowanceNum.computeIfAbsent(key, k -> new ArrayList<SalesAllowanceItem>()).add(it);
        }
        for (SalesAllowance row : list) {
            if (row == null || StringUtils.isBlank(row.getAllowanceNum())) {
                continue;
            }
            List<SalesAllowanceItem> items = byAllowanceNum.get(row.getAllowanceNum().trim());
            row.setItems(items != null ? new ArrayList<SalesAllowanceItem>(items) : new ArrayList<SalesAllowanceItem>());
        }
    }

    private void enrichAllowanceDisplay(SalesAllowance allowance, String orgId) {
        if (allowance == null) {
            return;
        }
        allowance.setCustomerName(null);
        allowance.setEmployeeName(null);
        allowance.setDepartmentName(null);
        if (StringUtils.isNotBlank(allowance.getCustomerNum())) {
            BaseCustomer c = customerService.getOne(new QueryWrapper<BaseCustomer>()
                    .eq("org_id", orgId).eq("customer_num", allowance.getCustomerNum().trim()).eq("del_flag", "0").last("limit 1"));
            if (c != null) {
                allowance.setCustomerName(c.getCustomerName());
            }
        }
        if (StringUtils.isNotBlank(allowance.getEmployeeNum())) {
            BaseEmployee e = baseEmployeeService.getOne(new QueryWrapper<BaseEmployee>()
                    .eq("org_id", orgId).eq("employee_num", allowance.getEmployeeNum().trim()).eq("del_flag", "0").last("limit 1"));
            if (e != null) {
                allowance.setEmployeeName(e.getEmployeeName());
                allowance.setDepartmentName(e.getDepartmentName());
            }
        }
    }

    /**
     * 单据编号规则：
     * XXZR + 当前日期后一天的yyyyMMdd + 3位递增序号（不足补零，从001开始）
     */
    private String generateSalesAllowanceNum(String orgId) throws Exception {
        if (StringUtils.isBlank(orgId)) {
            throw new Exception("orgId不能为空");
        }
        String tomorrowYmd = LocalDate.now().plusDays(1).format(DateTimeFormatter.BASIC_ISO_DATE);
        String base = "XXZR" + tomorrowYmd;

        SalesAllowance last = salesAllowanceService.getOne(new QueryWrapper<SalesAllowance>()
                .eq("org_id", orgId)
                .eq("del_flag", "0")
                .like("allowance_num", base)
                .orderByDesc("allowance_num")
                .last("limit 1"));

        int startSeq = 1;
        if (last != null && StringUtils.isNotBlank(last.getAllowanceNum()) && last.getAllowanceNum().length() >= 3) {
            String suffix = last.getAllowanceNum().substring(last.getAllowanceNum().length() - 3);
            try {
                startSeq = Integer.parseInt(suffix) + 1;
            } catch (Exception ignored) {
                startSeq = 1;
            }
        }

        for (int seq = startSeq; seq <= 999; seq++) {
            String candidate = base + String.format("%03d", seq);
            long occupied = salesAllowanceService.count(new QueryWrapper<SalesAllowance>()
                    .eq("org_id", orgId)
                    .eq("allowance_num", candidate)
                    .eq("del_flag", "0"));
            if (occupied == 0) {
                return candidate;
            }
        }
        throw new Exception("无法生成唯一销售折让单编号");
    }

    private void deleteItemsByAllowanceNum(String orgId, String allowanceNum) {
        if (StringUtils.isBlank(orgId) || StringUtils.isBlank(allowanceNum)) {
            return;
        }
        SalesAllowanceItem up = new SalesAllowanceItem();
        up.setDelFlag("2");
        up.setUpdateBy(getUsername());
        up.setUpdateTime(new Date());
        salesAllowanceItemService.update(up, new QueryWrapper<SalesAllowanceItem>()
                .eq("org_id", orgId)
                .eq("allowance_num", allowanceNum)
                .eq("del_flag", "0"));
    }

    private BigDecimal parseMoney(String s) {
        if (StringUtils.isBlank(s)) {
            return null;
        }
        try {
            return new BigDecimal(s.trim().replace(",", ""));
        } catch (Exception e) {
            return null;
        }
    }

    private String formatMoney(BigDecimal n) {
        if (n == null) {
            return null;
        }
        return n.stripTrailingZeros().toPlainString();
    }

    private SalesAllowance getActiveById(String id) throws Exception {
        SalesAllowance allowance = salesAllowanceService.getById(id);
        if (allowance == null || !"0".equals(allowance.getDelFlag())) {
            throw new Exception("销售折让单不存在");
        }
        return allowance;
    }
}
