package com.ruoyi.app.flashdelivery.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.ruoyi.app.flashdelivery.dto.InfoAddressRequest;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.system.domain.InfoAddress;
import com.ruoyi.system.service.IInfoAddressService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * 用户共享地址簿服务。
 * 每个读取和写入条件都绑定 token 对应的 userId，避免通过地址 ID 越权访问他人资料。
 */
@Service
public class InfoAddressBookService {
    private final IInfoAddressService addressService;

    public InfoAddressBookService(IInfoAddressService addressService) { this.addressService = addressService; }

    public List<InfoAddress> list(Long userId, String keyword) {
        QueryWrapper<InfoAddress> query = new QueryWrapper<InfoAddress>().eq("user_id", userId);
        if (keyword != null && !keyword.trim().isEmpty()) {
            String value = keyword.trim();
            query.and(item -> item.like("name", value).or().like("phone", value)
                    .or().like("address", value).or().like("address_detail", value));
        }
        query.orderByDesc("is_top").orderByDesc("top_time").orderByDesc("id");
        return addressService.list(query);
    }

    public InfoAddress detail(Long userId, Long id) {
        // 先查实体再核对所有权；对不存在和越权统一返回无访问权限，避免枚举地址 ID。
        InfoAddress address = id == null ? null : addressService.getById(id);
        if (address == null || !Objects.equals(userId, address.getUserId())) throw fail("address.access.denied");
        return address;
    }

    @Transactional
    public InfoAddress save(Long userId, InfoAddressRequest request) {
        validate(request);
        InfoAddress address;
        if (request.getId() == null) {
            address = new InfoAddress();
            address.setUserId(userId);
            copy(request, address);
            address.setIsTop(false);
            addressService.save(address);
        } else {
            address = detail(userId, request.getId());
            copy(request, address);
            // 使用显式 set 更新，使 null 能真正清空门牌、区域等可选字段。
            UpdateWrapper<InfoAddress> update = new UpdateWrapper<InfoAddress>()
                    .eq("id", request.getId()).eq("user_id", userId)
                    .set("name", address.getName()).set("phone", address.getPhone())
                    .set("address", address.getAddress()).set("address_detail", address.getAddressDetail())
                    .set("longitude", address.getLongitude()).set("latitude", address.getLatitude())
                    .set("country", address.getCountry()).set("province", address.getProvince())
                    .set("city", address.getCity()).set("area", address.getArea())
                    .set("annexes", address.getAnnexes());
            if (!addressService.update(update)) throw fail("address.access.denied");
        }
        return address;
    }

    public void delete(Long userId, Long id) {
        if (!addressService.remove(new QueryWrapper<InfoAddress>().eq("id", id).eq("user_id", userId))) {
            throw fail("address.access.denied");
        }
    }

    public void top(Long userId, Long id) {
        detail(userId, id);
        if (!addressService.update(new UpdateWrapper<InfoAddress>().eq("id", id).eq("user_id", userId)
                .set("is_top", true).set("top_time", new Date()))) throw fail("address.access.denied");
    }

    private void validate(InfoAddressRequest request) {
        if (request == null || blank(request.getName()) || blank(request.getPhone()) || blank(request.getAddress())
                || tooLong(request.getName(), 64) || tooLong(request.getPhone(), 32)
                || tooLong(request.getAddress(), 255) || tooLong(request.getAddressDetail(), 255)
                || tooLong(request.getCountry(), 64) || tooLong(request.getProvince(), 64)
                || tooLong(request.getCity(), 64) || tooLong(request.getArea(), 64)
                || tooLong(request.getAnnexes(), 1000)
                || invalid(request.getLatitude(), -90, 90) || invalid(request.getLongitude(), -180, 180)) {
            throw fail("address.data.invalid");
        }
    }

    private boolean invalid(BigDecimal value, int min, int max) {
        return value == null || value.compareTo(BigDecimal.valueOf(min)) < 0
                || value.compareTo(BigDecimal.valueOf(max)) > 0;
    }

    private boolean blank(String value) { return value == null || value.trim().isEmpty(); }
    private boolean tooLong(String value, int maximum) { return value != null && value.trim().length() > maximum; }
    private String trim(String value) { return blank(value) ? null : value.trim(); }
    private void copy(InfoAddressRequest from, InfoAddress to) {
        to.setName(from.getName().trim()); to.setPhone(from.getPhone().trim());
        to.setAddress(from.getAddress().trim()); to.setAddressDetail(trim(from.getAddressDetail()));
        to.setLongitude(from.getLongitude()); to.setLatitude(from.getLatitude());
        to.setCountry(trim(from.getCountry())); to.setProvince(trim(from.getProvince()));
        to.setCity(trim(from.getCity())); to.setArea(trim(from.getArea())); to.setAnnexes(trim(from.getAnnexes()));
    }
    private ServiceException fail(String key) { return new ServiceException(MessageUtils.message(key)); }
}
