package com.qqchen.deploy.backend.framework.repository;

import com.google.common.collect.Lists;
import com.qqchen.deploy.backend.framework.domain.Entity;
import jakarta.persistence.LockModeType;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.repository.query.Param;
import org.springframework.data.jpa.repository.Lock;

import java.io.Serializable;
import java.util.List;
import java.util.Optional;
import java.util.Collection;
import java.time.LocalDateTime;

@NoRepositoryBean
public interface IBaseRepository<T extends Entity<ID>, ID extends Serializable> extends JpaRepository<T, ID>, QuerydslPredicateExecutor<T> {

    // 基础查询方法
    @Override
    @Query("select e from #{#entityName} e where e.deleted = false")
    List<T> findAll();

    @Override
    @Query("select e from #{#entityName} e where e.id = ?1 and e.deleted = false")
    Optional<T> findById(ID id);

    // 逻辑删除
    default void logicDelete(T entity) {
        entity.setDeleted(true);
        save(entity);
    }

    default void logicDeleteById(ID id) {
        findById(id).ifPresent(this::logicDelete);
    }

    // 批量操作
    @Modifying
    @Query("update #{#entityName} e set e.deleted = true where e.id in :ids")
    void batchDelete(@Param("ids") Collection<ID> ids);

    @Modifying
    @Query("UPDATE #{#entityName} e SET e.updateTime = :updateTime, " +
        "e.updateBy = :updateBy, e.version = e.version + 1 " +
        "WHERE e.id IN :ids")
    void batchUpdate(
        @Param("ids") Collection<ID> ids,
        @Param("updateTime") LocalDateTime updateTime,
        @Param("updateBy") String updateBy
    );

    // 快速查询方法
    Optional<T> findByIdAndDeletedFalse(ID id);

    List<T> findByIdInAndDeletedFalse(Collection<ID> ids);

    boolean existsByIdAndDeletedFalse(ID id);

    // 条件查询
    @Query("select e from #{#entityName} e where e.deleted = false and " +
        "(:start is null or e.createTime >= :start) and " +
        "(:end is null or e.createTime <= :end)")
    List<T> findByCreateTimeBetween(
        @Param("start") LocalDateTime start,
        @Param("end") LocalDateTime end
    );

    @Query("select e from #{#entityName} e where e.deleted = false and " +
        "(:creator is null or e.createBy = :creator)")
    List<T> findByCreateBy(@Param("creator") String creator);

    @Query("select e from #{#entityName} e where e.deleted = false " +
        "order by e.createTime desc")
    List<T> findLatest(Pageable pageable);

    // 统计方法
    @Query("select count(e) from #{#entityName} e where e.deleted = false")
    long countNonDeleted();

    // QueryDSL支持
    default List<T> findAllByCondition(com.querydsl.core.types.Predicate predicate, Sort sort) {
        return Lists.newArrayList(findAll(predicate, sort));
    }

    // 乐观锁支持
    @Lock(LockModeType.PESSIMISTIC_WRITE)
    @Query("SELECT e FROM #{#entityName} e WHERE e.id = :id AND e.deleted = false")
    Optional<T> findByIdWithLock(@Param("id") ID id);

    @Modifying
    @Query("UPDATE #{#entityName} e SET e.updateTime = :updateTime, " +
        "e.updateBy = :updateBy, e.version = e.version + 1 " +
        "WHERE e.id IN :ids AND e.version = :version")
    int batchUpdateWithVersion(
        @Param("ids") Collection<ID> ids,
        @Param("updateTime") LocalDateTime updateTime,
        @Param("updateBy") String updateBy,
        @Param("version") Integer version
    );
}