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

import java.util.List;
import java.util.Optional;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import com.ecep.contract.IEntityService;
import com.ecep.contract.ds.other.repository.EmployeeRepository;
import com.ecep.contract.model.Employee;
import com.ecep.contract.model.EmployeeRole;

import jakarta.transaction.Transactional;

/**
 * 员工服务类
 */
@Lazy
@Service
@CacheConfig(cacheNames = "employee")
public class EmployeeService implements IEntityService<Employee> {
    private static final Logger logger = LoggerFactory.getLogger(EmployeeService.class);
    public static final int DEFAULT_SYSTEM_EMPLOYEE_ID = 26;
    @Lazy
    @Autowired
    private EmployeeRepository employeeRepository;

    /**
     * 根据员工ID查找员工信息，并使用缓存机制提高查询效率。
     * <p>
     * 该方法首先会检查缓存中是否存在对应的员工信息，如果存在则直接返回缓存中的数据，
     * 如果不存在则从数据库中查询，并将查询结果存入缓存中，以便下次查询时可以直接从缓存中获取。
     *
     * @param id 员工的唯一标识符，类型为Integer。
     * @return 返回与指定ID对应的Employee对象。如果数据库中不存在该ID对应的员工信息，则返回null。
     */
    @Cacheable(key = "#p0")
    public Employee findById(Integer id) {
        // 从员工仓库中根据ID查找员工信息，如果不存在则返回null
        return employeeRepository.findById(id).orElse(null);
    }

    @Cacheable(key = "'ac-'+#p0")
    public Employee findByAccount(String username) {
        return employeeRepository.findByAccount(username).orElse(null);
    }

    /**
     * @param name
     * @return
     */
    @Cacheable(key = "'name-'+#p0")
    public Employee findByName(String name) {
        return employeeRepository.findByName(name).orElseGet(() -> {
            return employeeRepository.findByAlias(name).orElse(null);
        });
    }

    @Cacheable(key = "'code-'+#p0")
    public Employee findByCode(String personCode) {
        return employeeRepository.findByCode(personCode).orElse(null);
    }

    /**
     * 保存员工信息，并在保存成功后根据指定的缓存键清除相关缓存。
     * <p>
     * 该函数使用了Spring的缓存注解 `@Caching`，结合 `@CacheEvict` 注解，在保存员工信息后，
     * 清除与该员工相关的缓存。具体清除的缓存键包括：
     * - 以员工ID为键的缓存
     * - 以员工姓名为键的缓存（键格式为 "name-员工姓名"）
     * - 以员工代码为键的缓存（键格式为 "code-员工代码"）
     *
     * @param employee 要保存的员工对象，包含员工的ID、姓名、代码等信息。
     * @return 返回保存后的员工对象，通常与传入的对象相同，但可能包含数据库生成的新ID或其他更新后的字段。
     */
    @Caching(evict = {
            @CacheEvict(key = "#p0.id"),
            @CacheEvict(key = "'ac-'+#p0.account"),
            @CacheEvict(key = "'name-'+#p0.name"),
            @CacheEvict(key = "'code-'+#p0.code")
    })
    public Employee save(Employee employee) {
        // 调用员工仓库的保存方法，将员工信息持久化到数据库
        return employeeRepository.save(employee);
    }

    @Caching(evict = {
            @CacheEvict(key = "#p0.id"), @CacheEvict(key = "'ac-'+#p0.account"),
            @CacheEvict(key = "'name-'+#p0.name"),
            @CacheEvict(key = "'code-'+#p0.code")
    })
    public void delete(Employee employee) {
        employeeRepository.delete(employee);
    }

    public Page<Employee> findAll(Specification<Employee> spec, Pageable pageable) {
        return employeeRepository.findAll(spec, pageable);
    }

    @Override
    public Specification<Employee> getSpecification(String searchText) {
        if (!StringUtils.hasText(searchText)) {
            return null;
        }
        return (root, query, builder) -> {
            // 使用或条件组合查询，以实现对员工代码或名称的模糊搜索
            return builder.or(
                    builder.like(root.get("account"), "%" + searchText + "%"),
                    builder.like(root.get("name"), "%" + searchText + "%"),
                    builder.like(root.get("alias"), "%" + searchText + "%"),
                    builder.like(root.get("code"), "%" + searchText + "%"),
                    builder.like(root.get("email"), "%" + searchText + "%"),
                    builder.like(root.get("phone"), "%" + searchText + "%"));
        };
    }

    /**
     * 根据搜索文本查询员工列表
     * 此方法构建了一个特定的规格化查询，以实现对员工代码或名称的模糊搜索
     * 它通过将搜索文本与员工代码和名称进行模糊匹配来筛选结果
     * 此外，它只返回搜索结果的前10条记录
     *
     * @param searchText 要搜索的文本，用于在员工代码和名称中进行模糊匹配
     * @return 包含搜索结果的员工列表，最多10条记录
     */
    public List<Employee> search(String searchText) {
        // 创建一个Specification对象，用于定义复杂的查询条件
        Specification<Employee> spec = getSpecification(searchText);
        return employeeRepository.findAll(spec, Pageable.ofSize(10)).getContent();
    }

    @Transactional
    public List<EmployeeRole> getRolesByEmployeeId(int employeeId) {
        Optional<Employee> optional = employeeRepository.findById(employeeId);
        if (optional.isPresent()) {
            Employee employee = optional.get();
            return employee.getRoles().stream().toList();
        }
        return null;
    }



}
