package com.izouma.nineth.repo;

import com.izouma.nineth.domain.Asset;
import com.izouma.nineth.enums.AssetStatus;
import com.izouma.nineth.enums.CollectionType;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;

import javax.transaction.Transactional;
import java.time.LocalDateTime;
import java.util.*;

public interface AssetRepo extends JpaRepository<Asset, Long>, JpaSpecificationExecutor<Asset> {
    @Query("update Asset t set t.del = true where t.id = ?1")
    @Modifying
    @Transactional
    void softDelete(Long id);

    long countByIpfsUrlAndStatusNot(String ipfsUrl, AssetStatus status);

    List<Asset> findByCollectionId(Long collectionId);

    List<Asset> findByCollectionIdInAndStatus(Iterable<Long> collectionId, AssetStatus status);

    List<Asset> findAllByCollectionIdInAndStatusIn(List<Long> collectionId, Iterable<AssetStatus> statuses);

    List<Asset> findByCreatedAtBefore(LocalDateTime localDateTime);

    List<Asset> findByConsignmentTrue();

    List<Asset> findByTokenIdIn(Iterable<String> tokenId);

    List<Asset> findByTokenIdOrderByCreatedAt(String tokenId);

    List<Asset> findByOrderId(Long orderId);

    @Query("select a from Asset a join Order o on o.assetId = a.id join Asset aa on aa.orderId = o.id where a.id = ?1")
    Optional<Asset> findChild(Long id);

    @Query("select a from Asset a join User u on a.userId = u.id where a.consignment = true and u.settleAccountId is null")
    List<Asset> findNoAccount();

    Set<Asset> findAllByUserIdInAndCollectionId(List<Long> ids, Long collectionId);

    List<Asset> findByTxHash(String hash);

    List<Asset> findByIdIn(Iterable<Long> ids);

    @Query("select a from Asset a left join TokenHistory t on a.tokenId = t.tokenId where t.id is null")
    List<Asset> findByNoHistory();


    List<Asset> findByTokenIdAndCreatedAtBetween(String tokenId, LocalDateTime start, LocalDateTime end);

    Asset findFirstByTokenId(String tokenId);

    Asset findFirstByTxHashIsNullAndTokenIdNotNullAndStatusOrderByCreatedAt(AssetStatus status);

    @Query("select a from Asset a where a.txHash is null and a.tokenId is not null " +
            "and a.status = com.izouma.nineth.enums.AssetStatus.NORMAL and a.createdAt < ?1 " +
            "order by a.createdAt desc")
    List<Asset> toMint(LocalDateTime time);

    List<Asset> findAllByIdInAndUserId(Collection<Long> id, Long userId);

    @Query(value = "select c.id, c.pic, c.model3d, c.minter_avatar, c.owner_avatar, c.detail from asset c", nativeQuery = true)
    List<List<String>> selectResource();

    List<Asset> findAllByOwnerIdAndStatusAndOasisIdNotNull(Long userId, AssetStatus status);

    @Modifying
    @Transactional
    @Query(value = "update asset c set c.pic = ?2, c.model3d = ?3, c.minter_avatar = ?4, " +
            "c.owner_avatar = ?5, c.detail = ?6 where c.id = ?1", nativeQuery = true)
    int updateCDN(Long id, String pic, String model3d, String minterAvatar,
                  String ownerAvatar, String detail);

    Page<Asset> findByUserIdAndStatusAndNameLike(Long userId, AssetStatus status, String name, Pageable pageable);

    List<Asset> findAllByOasisIdInAndStatusIn(List<Long> oasisIds, List<AssetStatus> assetStatuses);

    List<Asset> findAllByUserIdAndCollectionIdAndStatus(Long userId, Long collectionId, AssetStatus status);

    @Modifying
    @Transactional
    @Query(value = "update Asset a set a.holdDays = ?2 where a.id = ?1")
    void updateHoldDays(Long id, Integer holdDays);

    @Query("select a from Asset a " +
            "  join a.tags t on t.id = ?2 " +
            "where a.userId = ?1 " +
            "  and a.status = com.izouma.nineth.enums.AssetStatus.NORMAL")
    Page<Asset> byTag(Long userId, Long tagId, Pageable pageable);

    @Query(nativeQuery = true, value = "select id from asset where user_id = ?1 and collection_id in ?2 " +
            "and status = 'NORMAL' limit 1")
    Long findDiscount(Long userId, Collection<Long> ids);

    List<Asset> findByStatus(AssetStatus status);

    List<Asset> findAllByUserIdAndTypeAndOpened(Long userId, CollectionType type, Boolean opened);

    @Query(nativeQuery = true, value = "SELECT asset.user_id userId,user.nickname nickname,user.username username,user.avatar avatar,asset.name,asset.prefix_name prefixName,count(*) num FROM asset left join user on asset.user_id = user.id where asset.user_id not in (1435297,4273750, 56302) and asset.status in ('NORMAL','TRADING','GIFTING','MINTING','AUCTIONING') GROUP BY asset.user_id ORDER BY count(*) DESC limit ?1,?2")
    List<Map<String, String>> findByPage(int start, int end);

    @Query(nativeQuery = true, value = "SELECT count(distinct user_id) FROM asset where status in ('NORMAL','TRADING','GIFTING','MINTING','AUCTIONING') ")
    int totalElements();

    List<Asset> findAllByUserIdAndStatusIn(Long userId, List<AssetStatus> status);

    @Query("select a from Asset a where a.status in (com.izouma.nineth.enums.AssetStatus.NORMAL,com.izouma.nineth.enums.AssetStatus.TRADING,com.izouma.nineth.enums.AssetStatus.GIFTING,com.izouma.nineth.enums.AssetStatus.MINTING,com.izouma.nineth.enums.AssetStatus.AUCTIONING) and a.userId = ?1 and a.name like ?2")
    List<Asset> findAllByUserIdAndNameLike(Long userId, String name);
}