package com.example.demo.customer.service;

import com.example.demo.customer.dto.CustomerDtos;
import com.example.demo.customer.entity.Customer;
import com.example.demo.customer.repo.CustomerRepository;
import org.springframework.data.domain.PageRequest;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
public class CustomerService {

    private final CustomerRepository customerRepository;
    private final JdbcTemplate jdbcTemplate;

    public CustomerService(CustomerRepository customerRepository, JdbcTemplate jdbcTemplate) {
        this.customerRepository = customerRepository;
        this.jdbcTemplate = jdbcTemplate;
    }

    public java.util.Map<String, Object> search(Long shopId, String kw, boolean debtOnly, int page, int size) {
        List<Customer> list = customerRepository.search(shopId, kw, PageRequest.of(page, size));
        List<CustomerDtos.CustomerListItem> items = list.stream().map(c -> new CustomerDtos.CustomerListItem(
                c.getId(), c.getName(), c.getContactName(), c.getMobile(), c.getPhone(), c.getLevel(), c.getPriceLevel(), c.getRemark(), calcReceivable(shopId, c.getId(), c.getArOpening())
        )).collect(Collectors.toList());
        if (debtOnly) {
            items = items.stream().filter(it -> it.receivable != null && it.receivable.compareTo(BigDecimal.ZERO) > 0).collect(Collectors.toList());
        }
        java.util.Map<String, Object> resp = new java.util.HashMap<>();
        resp.put("list", items);
        return resp;
    }

    public Optional<Customer> findById(Long id) {
        return customerRepository.findById(id);
    }

    @Transactional
    public Long create(Long shopId, Long userId, CustomerDtos.CreateOrUpdateCustomerRequest req) {
        Customer c = new Customer();
        c.setShopId(shopId); c.setUserId(userId);
        c.setName(req.name); c.setLevel(req.level); c.setPriceLevel(cnPriceLevelOrDefault(req.priceLevel));
        c.setContactName(req.contactName); c.setMobile(req.mobile); c.setPhone(req.phone); c.setAddress(req.address);
        c.setStatus(1);
        c.setArOpening(req.arOpening == null ? BigDecimal.ZERO : req.arOpening);
        c.setRemark(req.remark);
        java.time.LocalDateTime now = java.time.LocalDateTime.now();
        c.setCreatedAt(now);
        c.setUpdatedAt(now);
        return customerRepository.save(c).getId();
    }

    @Transactional
    public void update(Long id, Long shopId, Long userId, CustomerDtos.CreateOrUpdateCustomerRequest req) {
        Customer c = customerRepository.findById(id).orElseThrow();
        if (!c.getShopId().equals(shopId)) throw new IllegalArgumentException("跨店铺修改");
        c.setName(req.name); c.setLevel(req.level); c.setPriceLevel(cnPriceLevelOrDefault(req.priceLevel));
        c.setContactName(req.contactName); c.setMobile(req.mobile); c.setPhone(req.phone); c.setAddress(req.address);
        if (req.arOpening != null) c.setArOpening(req.arOpening);
        c.setRemark(req.remark);
        c.setUpdatedAt(java.time.LocalDateTime.now());
        customerRepository.save(c);
    }

    private String cnPriceLevelOrDefault(String v) {
        if (v == null || v.isBlank()) return "零售价";
        // 兼容历史英文值
        if ("retail".equalsIgnoreCase(v)) return "零售价";
        if ("wholesale".equalsIgnoreCase(v) || "distribution".equalsIgnoreCase(v)) return "批发价";
        if ("big_client".equalsIgnoreCase(v)) return "大单报价";
        return v; // 已是中文
    }

    public BigDecimal computeReceivable(Long shopId, Long customerId) {
        Optional<Customer> oc = customerRepository.findById(customerId);
        BigDecimal opening = oc.map(Customer::getArOpening).orElse(BigDecimal.ZERO);
        return calcReceivable(shopId, customerId, opening);
    }

    private BigDecimal calcReceivable(Long shopId, Long customerId, BigDecimal opening) {
        BigDecimal open = opening == null ? BigDecimal.ZERO : opening;
        BigDecimal sale = n(jdbcTemplate.queryForObject("SELECT COALESCE(SUM(amount - paid_amount),0) FROM sales_orders WHERE shop_id=? AND customer_id=? AND status='approved'", BigDecimal.class, shopId, customerId));
        BigDecimal saleRet = n(jdbcTemplate.queryForObject("SELECT COALESCE(SUM(amount - paid_amount),0) FROM sales_return_orders WHERE shop_id=? AND customer_id=? AND status='approved'", BigDecimal.class, shopId, customerId));
        BigDecimal otherIn = n(jdbcTemplate.queryForObject("SELECT COALESCE(SUM(amount),0) FROM other_transactions WHERE shop_id=? AND counterparty_type='customer' AND counterparty_id=? AND `type`='income'", BigDecimal.class, shopId, customerId));
        BigDecimal otherOut = n(jdbcTemplate.queryForObject("SELECT COALESCE(SUM(amount),0) FROM other_transactions WHERE shop_id=? AND counterparty_type='customer' AND counterparty_id=? AND `type`='expense'", BigDecimal.class, shopId, customerId));
        return open.add(sale).subtract(saleRet).add(otherIn).subtract(otherOut).setScale(2, java.math.RoundingMode.HALF_UP);
    }

    private static BigDecimal n(BigDecimal v) { return v == null ? BigDecimal.ZERO : v; }
}


