package com.gxwebsoft.glt.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.gxwebsoft.common.core.annotation.OperationLog;
import com.gxwebsoft.common.core.exception.BusinessException;
import com.gxwebsoft.common.core.web.ApiResult;
import com.gxwebsoft.common.core.web.BaseController;
import com.gxwebsoft.common.core.web.BatchParam;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.common.system.entity.User;
import com.gxwebsoft.common.system.mapper.UserMapper;
import com.gxwebsoft.glt.entity.GltTicketOrder;
import com.gxwebsoft.glt.param.GltTicketOrderDeliveredParam;
import com.gxwebsoft.glt.param.GltTicketOrderParam;
import com.gxwebsoft.glt.service.GltSubscribeMessageService;
import com.gxwebsoft.glt.service.GltTicketOrderService;
import com.gxwebsoft.shop.entity.ShopStoreRider;
import com.gxwebsoft.shop.entity.ShopUserAddress;
import com.gxwebsoft.shop.service.ShopStoreFenceService;
import com.gxwebsoft.shop.service.ShopStoreRiderService;
import com.gxwebsoft.shop.service.ShopUserAddressService;
import cn.hutool.core.util.StrUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 送水订单控制器
 *
 * @author 科技小王子
 * @since 2026-02-05 18:50:21
 */
@Slf4j
@Tag(name = "送水订单管理")
@RestController
@RequestMapping("/api/glt/glt-ticket-order")
public class GltTicketOrderController extends BaseController {
    @Resource
    private GltTicketOrderService gltTicketOrderService;
    @Resource
    private ShopUserAddressService shopUserAddressService;
    @Resource
    private ShopStoreFenceService shopStoreFenceService;
    @Resource
    private ShopStoreRiderService shopStoreRiderService;
    @Resource
    private GltSubscribeMessageService gltSubscribeMessageService;
    @Resource
    private UserMapper userMapper;

    @Operation(summary = "分页查询送水订单")
    @GetMapping("/page")
    public ApiResult<PageResult<GltTicketOrder>> page(GltTicketOrderParam param) {
        // 使用关联查询
        return success(gltTicketOrderService.pageRel(param));
    }

    @PreAuthorize("isAuthenticated()")
    @Operation(summary = "配送员端：分页查询可接单的送水订单")
    @GetMapping("/rider/available")
    public ApiResult<PageResult<GltTicketOrder>> riderAvailablePage(GltTicketOrderParam param) {
        User loginUser = getLoginUser();
        if (loginUser == null) {
            return fail("请先登录", null);
        }
        Integer tenantId = getTenantId();
        param.setTenantId(tenantId);
        // 仅允许配送员访问
        requireActiveRider(loginUser.getUserId(), tenantId);

        // 查询未分配的待配送订单（riderId 为空或0）
        // 设置为0表示查询未分配的订单，XML中会处理为 IS NULL OR = 0
        param.setRiderId(0);
        if (param.getDeliveryStatus() == null) {
            param.setDeliveryStatus(GltTicketOrderService.DELIVERY_STATUS_WAITING);
        }
        // 配送员端默认按期望配送时间优先
        if (StrUtil.isBlank(param.getSort())) {
            param.setSort("sendTime asc, createTime desc");
        }
        
        // 使用现有的关联查询方法，通过参数控制
        return success(gltTicketOrderService.pageRel(param));
    }

    @PreAuthorize("isAuthenticated()")
    @Operation(summary = "配送员端：分页查询我的送水订单")
    @GetMapping("/rider/page")
    public ApiResult<PageResult<GltTicketOrder>> riderPage(GltTicketOrderParam param) {
        User loginUser = getLoginUser();
        if (loginUser == null) {
            return fail("请先登录", null);
        }
        Integer tenantId = getTenantId();
        param.setTenantId(tenantId);
        // 仅允许配送员访问
        requireActiveRider(loginUser.getUserId(), tenantId);

        // 关键修复：配送员只能看到分配给自己的订单
        param.setRiderId(loginUser.getUserId());
        
        // 默认查询待配送和配送中的订单
        if (param.getDeliveryStatus() == null) {
            // 可以通过参数传递多个状态，这里简化为只查待配送
            param.setDeliveryStatus(GltTicketOrderService.DELIVERY_STATUS_WAITING);
        }
        // 配送员端默认按期望配送时间优先
        if (StrUtil.isBlank(param.getSort())) {
            param.setSort("sendTime asc, createTime desc");
        }
        return success(gltTicketOrderService.pageRel(param));
    }

    @Operation(summary = "查询全部送水订单")
    @GetMapping()
    public ApiResult<List<GltTicketOrder>> list(GltTicketOrderParam param) {
        // 使用关联查询
        return success(gltTicketOrderService.listRel(param));
    }

    @Operation(summary = "根据id查询送水订单")
    @GetMapping("/{id}")
    public ApiResult<GltTicketOrder> get(@PathVariable("id") Integer id) {
        // 使用关联查询
        return success(gltTicketOrderService.getByIdRel(id));
    }

    @Operation(summary = "添加送水订单")
    @PostMapping()
    public ApiResult<?> save(@RequestBody GltTicketOrder gltTicketOrder) {
        // 下单：后端原子完成（扣水票 + 写核销记录 + 生成订单）
        User loginUser = getLoginUser();
        if (loginUser == null) {
            return fail("请先登录");
        }
        if (gltTicketOrder == null) {
            return fail("订单参数不能为空");
        }

        // 地址快照：把用户关联的“详细地址”落到 glt_ticket_order.address，避免用户后续修改地址导致历史订单丢失
        ShopUserAddress userAddress = null;
        if (gltTicketOrder.getAddressId() != null) {
            userAddress = shopUserAddressService.getByIdRel(gltTicketOrder.getAddressId());
        } else {
            userAddress = shopUserAddressService.getDefaultAddress(loginUser.getUserId());
        }
        if (userAddress == null) {
            return fail("请先添加收货地址");
        }
        if (!loginUser.getUserId().equals(userAddress.getUserId())) {
            return fail("收货地址不存在或无权限");
        }
        if (loginUser.getTenantId() != null && userAddress.getTenantId() != null
                && !loginUser.getTenantId().equals(userAddress.getTenantId())) {
            return fail("收货地址不存在或无权限");
        }
        gltTicketOrder.setAddressId(userAddress.getId());
        gltTicketOrder.setAddress(buildAddressSnapshot(userAddress));

        // 下单时校验配送范围（电子围栏）：不信任前端传经纬度，使用地址表坐标校验
        if (StrUtil.isBlank(userAddress.getLat()) || StrUtil.isBlank(userAddress.getLng())) {
            return fail("收货地址坐标缺失，请重新选择收货地址");
        }
        try {
            double lat = Double.parseDouble(userAddress.getLat().trim());
            double lng = Double.parseDouble(userAddress.getLng().trim());
            shopStoreFenceService.validatePointInEnabledFences(loginUser.getTenantId(), lng, lat);
        } catch (Exception e) {
            return fail(e.getMessage() == null ? "收货地址不在配送范围内" : e.getMessage());
        }

        gltTicketOrderService.createWithWriteOff(gltTicketOrder, loginUser.getUserId(), loginUser.getTenantId());

        // 订单创建成功后，异步通知所有在线配送员有新订单
        try {
            notifyRidersOfNewOrder(gltTicketOrder, loginUser.getTenantId());
        } catch (Exception e) {
            log.warn("通知配送员失败（不影响下单）: {}", e.getMessage());
        }

        return success("下单成功");
    }

    /**
     * 通知所有在线配送员有新订单
     */
    private void notifyRidersOfNewOrder(GltTicketOrder order, Integer tenantId) {
        if (order == null || tenantId == null) {
            return;
        }

        // 查询所有启用且在线的配送员
        List<ShopStoreRider> onlineRiders = shopStoreRiderService.list(
                new LambdaQueryWrapper<ShopStoreRider>()
                        .eq(ShopStoreRider::getTenantId, tenantId)
                        .eq(ShopStoreRider::getIsDelete, 0)
                        .eq(ShopStoreRider::getStatus, 1)
                        .eq(ShopStoreRider::getWorkStatus, 1) // 在线状态
                        .or()
                        .eq(ShopStoreRider::getTenantId, tenantId)
                        .eq(ShopStoreRider::getIsDelete, 0)
                        .eq(ShopStoreRider::getStatus, 1)
                        .isNull(ShopStoreRider::getWorkStatus) // 兼容未设置状态的配送员
        );

        if (onlineRiders == null || onlineRiders.isEmpty()) {
            log.info("当前无在线配送员，无需发送订阅消息");
            return;
        }

        // 获取配送员的 userId 列表
        List<Integer> riderUserIds = onlineRiders.stream()
                .map(ShopStoreRider::getUserId)
                .filter(id -> id != null && id > 0)
                .collect(Collectors.toList());

        if (riderUserIds.isEmpty()) {
            return;
        }

        // 批量查询配送员的 openId
        List<User> riders = userMapper.selectList(
                new LambdaQueryWrapper<User>()
                        .select(User::getUserId, User::getOpenid)
                        .in(User::getUserId, riderUserIds)
                        .isNotNull(User::getOpenid)
        );

        // 发送订阅消息
        for (User rider : riders) {
            if (StrUtil.isNotBlank(rider.getOpenid())) {
                try {
                    gltSubscribeMessageService.sendNewOrderNotice(order, rider.getOpenid(), tenantId);
                } catch (Exception e) {
                    log.warn("发送订阅消息给配送员失败 - userId={}, error={}", rider.getUserId(), e.getMessage());
                }
            }
        }

        log.info("已向 {} 位配送员发送新订单通知", riders.size());
    }

    @PreAuthorize("isAuthenticated()")
    @Operation(summary = "配送员接单")
    @PostMapping("/{id}/accept")
    public ApiResult<?> accept(@PathVariable("id") Integer id) {
        User loginUser = getLoginUser();
        if (loginUser == null) {
            return fail("请先登录");
        }
        Integer tenantId = getTenantId();
        requireActiveRider(loginUser.getUserId(), tenantId);
        gltTicketOrderService.accept(id, loginUser.getUserId(), tenantId);
        return success("接单成功");
    }

    @PreAuthorize("isAuthenticated()")
    @Operation(summary = "配送员开始配送")
    @PostMapping("/{id}/start")
    public ApiResult<?> start(@PathVariable("id") Integer id) {
        User loginUser = getLoginUser();
        if (loginUser == null) {
            return fail("请先登录");
        }
        Integer tenantId = getTenantId();
        requireActiveRider(loginUser.getUserId(), tenantId);
        gltTicketOrderService.start(id, loginUser.getUserId(), tenantId);
        return success("开始配送");
    }

    @PreAuthorize("isAuthenticated()")
    @Operation(summary = "配送员确认送达")
    @PostMapping("/{id}/delivered")
    public ApiResult<?> delivered(@PathVariable("id") Integer id,
                                  @RequestBody(required = false) GltTicketOrderDeliveredParam body) {
        User loginUser = getLoginUser();
        if (loginUser == null) {
            return fail("请先登录");
        }
        Integer tenantId = getTenantId();
        requireActiveRider(loginUser.getUserId(), tenantId);
        String sendEndImg = body == null ? null : body.getSendEndImg();
        // 配送员提成结算：在 service 内部按“拍照上传/用户确认收货”规则幂等处理。
        gltTicketOrderService.delivered(id, loginUser.getUserId(), tenantId, sendEndImg);
        return success("确认送达");
    }

    @PreAuthorize("isAuthenticated()")
    @Operation(summary = "用户确认收货")
    @PostMapping("/{id}/confirm-receive")
    public ApiResult<?> confirmReceive(@PathVariable("id") Integer id) {
        User loginUser = getLoginUser();
        if (loginUser == null) {
            return fail("请先登录");
        }
        // 配送员提成结算：在 service 内部按规则幂等处理。
        gltTicketOrderService.confirmReceive(id, loginUser.getUserId(), getTenantId());
        return success("确认收货成功");
    }

    private ShopStoreRider requireActiveRider(Integer userId, Integer tenantId) {
        if (userId == null) {
            throw new BusinessException("请先登录");
        }
        if (tenantId == null) {
            throw new BusinessException("租户信息缺失");
        }
        ShopStoreRider rider = shopStoreRiderService.getOne(new LambdaQueryWrapper<ShopStoreRider>()
                .eq(ShopStoreRider::getUserId, userId)
                .eq(ShopStoreRider::getTenantId, tenantId)
                .eq(ShopStoreRider::getIsDelete, 0)
                .last("limit 1"));
        if (rider == null) {
            throw new BusinessException("非配送员，无权限操作");
        }
        if (rider.getStatus() == null || rider.getStatus() != 1) {
            throw new BusinessException("配送员已禁用");
        }
        return rider;
    }

    private String buildAddressSnapshot(ShopUserAddress addr) {
        if (addr == null) {
            return null;
        }
        // 兼容旧数据：fullAddress 为空时，拼接省市区 + 详细地址
        return StrUtil.blankToDefault(
                StrUtil.join("",
                        StrUtil.nullToEmpty(addr.getProvince()),
                        StrUtil.nullToEmpty(addr.getCity()),
                        StrUtil.nullToEmpty(addr.getRegion()),
                        StrUtil.nullToEmpty(addr.getAddress()),
                        StrUtil.nullToEmpty(addr.getFullAddress())
                ),
                addr.getAddress()
        );
    }

    @PreAuthorize("hasAuthority('glt:gltTicketOrder:update')")
    @OperationLog
    @Operation(summary = "修改送水订单")
    @PutMapping()
    public ApiResult<?> update(@RequestBody GltTicketOrder gltTicketOrder) {
        if (gltTicketOrder == null || gltTicketOrder.getId() == null) {
            return fail("订单ID不能为空");
        }
        Integer tenantId = getTenantId();

        // 根据 addressId 同步更新订单地址快照
        if (gltTicketOrder.getAddressId() != null) {
            ShopUserAddress userAddress = shopUserAddressService.getByIdRel(gltTicketOrder.getAddressId());
            if (userAddress == null) {
                return fail("收货地址不存在");
            }
            if (tenantId != null && userAddress.getTenantId() != null && !tenantId.equals(userAddress.getTenantId())) {
                return fail("收货地址不存在或无权限");
            }
            GltTicketOrder oldOrder = gltTicketOrderService.getById(gltTicketOrder.getId());
            if (oldOrder == null) {
                return fail("订单不存在");
            }
            Integer targetUserId = gltTicketOrder.getUserId() != null ? gltTicketOrder.getUserId() : oldOrder.getUserId();
            if (targetUserId != null && userAddress.getUserId() != null && !targetUserId.equals(userAddress.getUserId())) {
                return fail("收货地址不存在或无权限");
            }
            gltTicketOrder.setAddressId(userAddress.getId());
            gltTicketOrder.setAddress(buildAddressSnapshot(userAddress));
        }

        if (gltTicketOrderService.updateById(gltTicketOrder)) {
            // 后台指派配送员（直接改 riderId）时，同步商城订单为“已发货”(deliveryStatus=20)
            if (gltTicketOrder != null
                    && gltTicketOrder.getId() != null
                    && gltTicketOrder.getRiderId() != null
                    && gltTicketOrder.getRiderId() > 0) {
                gltTicketOrderService.markShopOrderShippedAfterRiderAssigned(
                        gltTicketOrder.getId(),
                        tenantId,
                        gltTicketOrder.getRiderId()
                );
            }
            // 后台直接改“已完成”(deliveryStatus=40)时，同步商城订单为“已完成”(orderStatus=1)
            if (gltTicketOrder != null
                    && gltTicketOrder.getId() != null
                    && gltTicketOrder.getDeliveryStatus() != null
                    && gltTicketOrder.getDeliveryStatus() == GltTicketOrderService.DELIVERY_STATUS_FINISHED) {
                gltTicketOrderService.markShopOrderCompletedAfterTicketFinished(gltTicketOrder.getId(), tenantId);
            }
            return success("修改成功");
        }
        return fail("修改失败");
    }

    @PreAuthorize("hasAuthority('glt:gltTicketOrder:remove')")
    @OperationLog
    @Operation(summary = "删除送水订单")
    @DeleteMapping("/{id}")
    public ApiResult<?> remove(@PathVariable("id") Integer id) {
        if (gltTicketOrderService.removeById(id)) {
            return success("删除成功");
        }
        return fail("删除失败");
    }

    @PreAuthorize("hasAuthority('glt:gltTicketOrder:save')")
    @OperationLog
    @Operation(summary = "批量添加送水订单")
    @PostMapping("/batch")
    public ApiResult<?> saveBatch(@RequestBody List<GltTicketOrder> list) {
        if (gltTicketOrderService.saveBatch(list)) {
            return success("添加成功");
        }
        return fail("添加失败");
    }

    @PreAuthorize("hasAuthority('glt:gltTicketOrder:update')")
    @OperationLog
    @Operation(summary = "批量修改送水订单")
    @PutMapping("/batch")
    public ApiResult<?> removeBatch(@RequestBody BatchParam<GltTicketOrder> batchParam) {
        if (batchParam.update(gltTicketOrderService, "id")) {
            return success("修改成功");
        }
        return fail("修改失败");
    }

    @PreAuthorize("hasAuthority('glt:gltTicketOrder:remove')")
    @OperationLog
    @Operation(summary = "批量删除送水订单")
    @DeleteMapping("/batch")
    public ApiResult<?> removeBatch(@RequestBody List<Integer> ids) {
        if (gltTicketOrderService.removeByIds(ids)) {
            return success("删除成功");
        }
        return fail("删除失败");
    }

}
