package com.example.demo.product.service;

import com.example.demo.product.dto.ProductDtos;
import com.example.demo.product.entity.Inventory;
import com.example.demo.product.entity.Product;
import com.example.demo.product.entity.ProductImage;
import com.example.demo.product.entity.ProductPrice;
import com.example.demo.product.repo.InventoryRepository;
import com.example.demo.product.repo.ProductImageRepository;
import com.example.demo.product.repo.ProductPriceRepository;
import com.example.demo.product.repo.ProductRepository;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
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.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

@Service
public class ProductService {

    private final ProductRepository productRepository;
    private final ProductPriceRepository priceRepository;
    private final InventoryRepository inventoryRepository;
    private final ProductImageRepository imageRepository;
    private final JdbcTemplate jdbcTemplate;

    public ProductService(ProductRepository productRepository,
                          ProductPriceRepository priceRepository,
                          InventoryRepository inventoryRepository,
                          ProductImageRepository imageRepository,
                          JdbcTemplate jdbcTemplate) {
        this.productRepository = productRepository;
        this.priceRepository = priceRepository;
        this.inventoryRepository = inventoryRepository;
        this.imageRepository = imageRepository;
        this.jdbcTemplate = jdbcTemplate;
    }

    public Page<ProductDtos.ProductListItem> search(Long shopId, String kw, Long categoryId, int page, int size) {
        try {
            Page<Product> p = productRepository.search(shopId, kw, categoryId, PageRequest.of(page, size));
            return p.map(prod -> {
                ProductDtos.ProductListItem it = new ProductDtos.ProductListItem();
                it.id = prod.getId();
                it.name = prod.getName();
                it.brand = prod.getBrand();
                it.model = prod.getModel();
                it.spec = prod.getSpec();
                inventoryRepository.findById(prod.getId()).ifPresent(inv -> it.stock = inv.getQuantity());
                priceRepository.findById(prod.getId()).ifPresent(pr -> it.retailPrice = pr.getRetailPrice());
                List<ProductImage> imgs = imageRepository.findByProductIdOrderBySortOrderAscIdAsc(prod.getId());
                it.cover = imgs.isEmpty() ? null : imgs.get(0).getUrl();
                return it;
            });
        } catch (Exception e) {
            // 安全回退为 JDBC 查询，保障功能可用
            StringBuilder sql = new StringBuilder("SELECT p.id,p.name,p.brand,p.model,p.spec,\n" +
                    "(SELECT i.quantity FROM inventories i WHERE i.product_id=p.id) AS stock,\n" +
                    "(SELECT pr.retail_price FROM product_prices pr WHERE pr.product_id=p.id) AS retail_price,\n" +
                    "(SELECT img.url FROM product_images img WHERE img.product_id=p.id ORDER BY img.sort_order, img.id LIMIT 1) AS cover\n" +
                    "FROM products p WHERE p.shop_id=? AND p.deleted_at IS NULL");
            List<Object> ps = new ArrayList<>();
            ps.add(shopId);
            if (kw != null && !kw.isBlank()) { sql.append(" AND (p.name LIKE ? OR p.brand LIKE ? OR p.model LIKE ? OR p.spec LIKE ? OR p.barcode LIKE ?)");
                String like = "%" + kw + "%"; ps.add(like); ps.add(like); ps.add(like); ps.add(like); ps.add(like); }
            if (categoryId != null) { sql.append(" AND p.category_id=?"); ps.add(categoryId); }
            sql.append(" ORDER BY p.id DESC LIMIT ? OFFSET ?");
            ps.add(size); ps.add(page * size);
            List<ProductDtos.ProductListItem> list = jdbcTemplate.query(sql.toString(), (rs,rn) -> {
                ProductDtos.ProductListItem it = new ProductDtos.ProductListItem();
                it.id = rs.getLong("id");
                it.name = rs.getString("name");
                it.brand = rs.getString("brand");
                it.model = rs.getString("model");
                it.spec = rs.getString("spec");
                java.math.BigDecimal st = (java.math.BigDecimal) rs.getObject("stock");
                it.stock = st;
                java.math.BigDecimal rp = (java.math.BigDecimal) rs.getObject("retail_price");
                it.retailPrice = rp;
                it.cover = rs.getString("cover");
                return it;
            }, ps.toArray());
            return new PageImpl<>(list, PageRequest.of(page, size), list.size());
        }
    }

    public Optional<ProductDtos.ProductDetail> findDetail(Long id) {
        Optional<Product> op = productRepository.findById(id);
        if (op.isEmpty()) return Optional.empty();
        Product p = op.get();
        ProductDtos.ProductDetail d = new ProductDtos.ProductDetail();
        d.id = p.getId();
        d.name = p.getName();
        d.barcode = p.getBarcode();
        d.brand = p.getBrand();
        d.model = p.getModel();
        d.spec = p.getSpec();
        d.origin = p.getOrigin();
        d.categoryId = p.getCategoryId();
        d.unitId = p.getUnitId();
        d.safeMin = p.getSafeMin();
        d.safeMax = p.getSafeMax();
        inventoryRepository.findById(p.getId()).ifPresent(inv -> d.stock = inv.getQuantity());
        priceRepository.findById(p.getId()).ifPresent(pr -> {
            d.purchasePrice = pr.getPurchasePrice();
            d.retailPrice = pr.getRetailPrice();
            d.wholesalePrice = pr.getWholesalePrice();
            d.bigClientPrice = pr.getBigClientPrice();
        });
        List<ProductImage> imgs = imageRepository.findByProductIdOrderBySortOrderAscIdAsc(p.getId());
        List<ProductDtos.Image> list = new ArrayList<>();
        for (ProductImage img : imgs) {
            ProductDtos.Image i = new ProductDtos.Image();
            i.url = img.getUrl();
            list.add(i);
        }
        d.images = list;
        return Optional.of(d);
    }

    @Transactional
    public Long create(Long shopId, Long userId, ProductDtos.CreateOrUpdateProductRequest req) {
        validate(shopId, req);
        LocalDateTime now = LocalDateTime.now();

        Product p = new Product();
        p.setShopId(shopId);
        p.setUserId(userId);
        p.setName(req.name);
        p.setBarcode(emptyToNull(req.barcode));
        p.setBrand(emptyToNull(req.brand));
        p.setModel(emptyToNull(req.model));
        p.setSpec(emptyToNull(req.spec));
        p.setOrigin(emptyToNull(req.origin));
        p.setCategoryId(req.categoryId);
        p.setUnitId(req.unitId);
        p.setSafeMin(req.safeMin);
        p.setSafeMax(req.safeMax);
        p.setDescription(emptyToNull(req.remark));
        p.setCreatedAt(now);
        p.setUpdatedAt(now);
        productRepository.save(p);

        upsertPrice(userId, now, p.getId(), shopId, req.prices);
        upsertInventory(userId, now, p.getId(), shopId, req.stock);
        syncImages(userId, p.getId(), shopId, req.images);

        return p.getId();
    }

    @Transactional
    public void update(Long id, Long shopId, Long userId, ProductDtos.CreateOrUpdateProductRequest req) {
        validate(shopId, req);
        Product p = productRepository.findById(id).orElseThrow();
        if (!p.getShopId().equals(shopId)) throw new IllegalArgumentException("跨店铺数据");
        p.setUserId(userId);
        p.setName(req.name);
        p.setBarcode(emptyToNull(req.barcode));
        p.setBrand(emptyToNull(req.brand));
        p.setModel(emptyToNull(req.model));
        p.setSpec(emptyToNull(req.spec));
        p.setOrigin(emptyToNull(req.origin));
        p.setCategoryId(req.categoryId);
        p.setUnitId(req.unitId);
        p.setSafeMin(req.safeMin);
        p.setSafeMax(req.safeMax);
        p.setDescription(emptyToNull(req.remark));
        p.setUpdatedAt(LocalDateTime.now());
        productRepository.save(p);

        LocalDateTime now = LocalDateTime.now();
        upsertPrice(userId, now, p.getId(), shopId, req.prices);
        upsertInventory(userId, now, p.getId(), shopId, req.stock);
        syncImages(userId, p.getId(), shopId, req.images);
    }

    private void validate(Long shopId, ProductDtos.CreateOrUpdateProductRequest req) {
        if (req.name == null || req.name.isBlank()) throw new IllegalArgumentException("name必填");
        if (req.unitId == null) throw new IllegalArgumentException("unitId必填");
        if (req.safeMin != null && req.safeMax != null) {
            if (req.safeMin.compareTo(req.safeMax) > 0) throw new IllegalArgumentException("安全库存区间不合法");
        }
        if (req.barcode != null && !req.barcode.isBlank()) {
            if (productRepository.existsByShopIdAndBarcode(shopId, req.barcode)) {
                // 更新时允许自己相同：由Controller层在调用前判定并跳过；简化此处逻辑
            }
        }
    }

    private void upsertPrice(Long userId, LocalDateTime now, Long productId, Long shopId, ProductDtos.Prices prices) {
        if (prices == null) prices = new ProductDtos.Prices();
        java.util.Optional<ProductPrice> existed = priceRepository.findById(productId);
        ProductPrice pr = existed.orElseGet(ProductPrice::new);
        pr.setProductId(productId);
        pr.setShopId(shopId);
        pr.setUserId(userId);
        pr.setPurchasePrice(nvl(prices.purchasePrice, BigDecimal.ZERO));
        pr.setRetailPrice(nvl(prices.retailPrice, BigDecimal.ZERO));
        pr.setWholesalePrice(nvl(prices.wholesalePrice, BigDecimal.ZERO));
        pr.setBigClientPrice(nvl(prices.bigClientPrice, BigDecimal.ZERO));
        pr.setUpdatedAt(now);
        priceRepository.save(pr);
    }

    private void upsertInventory(Long userId, LocalDateTime now, Long productId, Long shopId, BigDecimal stock) {
        Inventory inv = inventoryRepository.findById(productId).orElseGet(Inventory::new);
        inv.setProductId(productId);
        inv.setShopId(shopId);
        inv.setUserId(userId);
        inv.setQuantity(nvl(stock, BigDecimal.ZERO));
        inv.setUpdatedAt(now);
        inventoryRepository.save(inv);
    }

    private void syncImages(Long userId, Long productId, Long shopId, java.util.List<String> images) {
        imageRepository.deleteByProductId(productId);
        if (images == null) return;
        int idx = 0;
        for (String url : images) {
            if (url == null || url.isBlank()) continue;
            ProductImage img = new ProductImage();
            img.setShopId(shopId);
            img.setUserId(userId);
            img.setProductId(productId);
            img.setUrl(url);
            img.setSortOrder(idx++);
            imageRepository.save(img);
        }
    }

    private static <T> T nvl(T v, T def) { return v != null ? v : def; }
    private static String emptyToNull(String s) { return (s == null || s.isBlank()) ? null : s; }
}


