package com.ecep.contract.ds.other.service;

import java.time.LocalDate;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import com.ecep.contract.IEntityService;
import com.ecep.contract.QueryService;
import com.ecep.contract.SpringApp;
import com.ecep.contract.ds.other.repository.InventoryRepository;
import com.ecep.contract.model.Employee;
import com.ecep.contract.model.Inventory;
import com.ecep.contract.model.InventoryCatalog;
import com.ecep.contract.service.VoableService;
import com.ecep.contract.util.SpecificationUtils;
import com.ecep.contract.vo.InventoryVo;
import com.fasterxml.jackson.databind.JsonNode;

import jakarta.persistence.criteria.Join;
import jakarta.persistence.criteria.JoinType;
import lombok.Getter;
import lombok.Setter;

@Lazy
@Service
@CacheConfig(cacheNames = "inventory")
public class InventoryService
        implements IEntityService<Inventory>, QueryService<InventoryVo>, VoableService<Inventory, InventoryVo> {
    @Lazy
    @Autowired
    private InventoryRepository inventoryRepository;
    @Getter
    @Setter
    private int searchPageSize = 10;

    @Cacheable(key = "#p0")
    public InventoryVo findById(Integer id) {
        return inventoryRepository.findById(id).map(Inventory::toVo).orElse(null);
    }

    public Inventory getById(Integer id) {
        return inventoryRepository.findById(id).orElse(null);
    }

    @Override
    public Page<Inventory> findAll(Specification<Inventory> spec, Pageable pageable) {
        return inventoryRepository.findAll(spec, pageable);
    }

    @Override
    public Page<InventoryVo> findAll(JsonNode paramsNode, Pageable pageable) {
        Specification<Inventory> spec = null;
        if (paramsNode.has("searchText")) {
            spec = getSpecification(paramsNode.get("searchText").asText());
        }
        // 可以根据需要添加更多参数处理
        return findAll(spec, pageable).map(Inventory::toVo);
    }

    @Override
    public Specification<Inventory> getSpecification(String searchText) {
        if (!StringUtils.hasText(searchText)) {
            return null;
        }
        return SpecificationUtils.andWith(searchText, this::buildSearchSpecification);
    }

    protected Specification<Inventory> buildSearchSpecification(String searchText) {
        return (root, query, builder) -> {
            Join<Object, Object> catalog = root.join("catalog", JoinType.LEFT);
            query.orderBy(
                    builder.asc(builder.length(root.get("name"))),
                    builder.asc(builder.length(root.get("specification"))));
            return builder.or(
                    builder.and(
                            builder.isNotNull(catalog),
                            builder.equal(catalog.get("name"), searchText)),
                    builder.like(root.get("code"), "%" + searchText + "%"),
                    builder.like(root.get("specification"), "%" + searchText + "%"),
                    builder.like(root.get("name"), "%" + searchText + "%"));
        };
    }

    public List<Inventory> search(String searchText) {
        Pageable pageable = Pageable.ofSize(getSearchPageSize());
        pageable.getSort().and(Sort.by(Sort.Direction.DESC, "id"));
        Specification<Inventory> specification = getSpecification(searchText);
        return inventoryRepository.findAll(specification, pageable).getContent();
    }

    @Cacheable(key = "'code-'+#p0")
    public InventoryVo findByCode(String code) {
        return inventoryRepository.findByCode(code).map(Inventory::toVo).orElse(null);
    }

    @Caching(evict = {
            @CacheEvict(key = "#p0.id"),
            @CacheEvict(key = "'code-'+#p0.code"),
    })
    public Inventory save(Inventory entity) {
        return inventoryRepository.save(entity);
    }

    @Caching(evict = {
            @CacheEvict(key = "#p0.id"),
            @CacheEvict(key = "'code-'+#p0.code"),
    })
    public void delete(Inventory entity) {
        inventoryRepository.delete(entity);
    }

    public long count(Specification<Inventory> spec) {
        return inventoryRepository.count(spec);
    }

    public Inventory createNewInstance() {
        Inventory inventory = new Inventory();

        inventory.setNameLock(false);
        inventory.setSpecificationLock(false);
        inventory.getSalePrice().setTaxRate(13);
        inventory.getPurchasePrice().setTaxRate(13);
        inventory.setWeightUnit("kg");
        inventory.setVolumeUnit("m³");
        inventory.setSizeUnit("mm");

        inventory.setCreateTime(LocalDate.now());
        return inventory;
    }

    @Override
    public void updateByVo(Inventory entity, InventoryVo vo) {
        if (entity == null || vo == null) {
            return;
        }

        // 映射基本属性
        if (vo.getCatalogId() != null) {
            if (entity.getCatalog() == null || !entity.getCatalog().getId().equals(vo.getCatalogId())) {
                InventoryCatalog catalog = SpringApp.getBean(InventoryCatalogService.class).getById(vo.getCatalogId());
                entity.setCatalog(catalog);
            }
        } else {
            entity.setCatalog(null);
        }

        entity.setCode(vo.getCode());

        entity.setSpecification(vo.getSpecification());
        entity.setSpecificationLock(vo.isSpecificationLock());

        entity.setName(vo.getName());
        entity.setNameLock(vo.isNameLock());

        entity.setUnit(vo.getUnit());
        entity.setDescription(vo.getDescription());

        // 映射重量相关属性
        if (vo.getWeight() != null) {
            entity.setWeight(vo.getWeight());
        }
        if (vo.getPackagedWeight() != null) {
            entity.setPackagedWeight(vo.getPackagedWeight());
        }
        entity.setWeightUnit(vo.getWeightUnit());
        entity.setVolumeUnit(vo.getVolumeUnit());
        entity.setSizeUnit(vo.getSizeUnit());

        // 映射价格相关属性
        if (vo.getPurchasePrice() != null) {
            entity.getPurchasePrice().setTaxRate(vo.getPurchasePrice().getTaxRate());
            entity.getPurchasePrice().setPreTaxPrice(vo.getPurchasePrice().getPreTaxPrice());
            entity.getPurchasePrice().setPostTaxPrice(vo.getPurchasePrice().getPostTaxPrice());
        }
        if (vo.getSalePrice() != null) {
            entity.getSalePrice().setTaxRate(vo.getSalePrice().getTaxRate());
            entity.getSalePrice().setPreTaxPrice(vo.getSalePrice().getPreTaxPrice());
            entity.getSalePrice().setPostTaxPrice(vo.getSalePrice().getPostTaxPrice());
        }

        // 映射体积尺寸相关属性
        if (vo.getVolumeSize() != null) {
            entity.getVolumeSize().setVolume(vo.getVolumeSize().getVolume());
            entity.getVolumeSize().setLength(vo.getVolumeSize().getLength());
            entity.getVolumeSize().setWidth(vo.getVolumeSize().getWidth());
            entity.getVolumeSize().setHeight(vo.getVolumeSize().getHeight());
        }
        if (vo.getPackagedVolumeSize() != null) {
            entity.getPackagedVolumeSize().setVolume(vo.getPackagedVolumeSize().getVolume());
            entity.getPackagedVolumeSize().setLength(vo.getPackagedVolumeSize().getLength());
            entity.getPackagedVolumeSize().setWidth(vo.getPackagedVolumeSize().getWidth());
            entity.getPackagedVolumeSize().setHeight(vo.getPackagedVolumeSize().getHeight());
        }

        EmployeeService employeeService = SpringApp.getBean(EmployeeService.class);
        entity.setCreateTime(vo.getCreateTime());
        if (vo.getCreatorId() == null) {
            entity.setCreator(null);
        } else {
            if (entity.getCreator() == null || !entity.getCreator().getId().equals(vo.getCreatorId())) {
                Employee creator = employeeService.getById(vo.getCreatorId());
                entity.setCreator(creator);
            }
        }
        entity.setUpdateDate(vo.getUpdateDate());
        if (vo.getUpdaterId() == null) {
            entity.setUpdater(null);
        } else {
            if (entity.getUpdater() == null || !entity.getUpdater().getId().equals(vo.getUpdaterId())) {
                Employee updater = employeeService.getById(vo.getUpdaterId());
                entity.setUpdater(updater);
            }
        }

        // 忽略active属性，因为实体中没有这个属性
    }
}
