package com.lanyuanxiaoyao.service.ai.knowledge.service;

import club.kingon.sql.builder.SqlBuilder;
import club.kingon.sql.builder.entry.Alias;
import club.kingon.sql.builder.entry.Column;
import cn.hutool.core.util.IdUtil;
import com.lanyuanxiaoyao.service.ai.knowledge.entity.Group;
import com.lanyuanxiaoyao.service.common.Constants;
import io.qdrant.client.ConditionFactory;
import io.qdrant.client.QdrantClient;
import io.qdrant.client.grpc.Points;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import org.eclipse.collections.api.factory.Lists;
import org.eclipse.collections.api.list.ImmutableList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * @author lanyuanxiaoyao
 * @version 20250522
 */
@Service
public class GroupService {
  public static final String GROUP_TABLE_NAME = Constants.DATABASE_NAME + ".service_ai_group";
  private static final Logger logger = LoggerFactory.getLogger(GroupService.class);
  private static final RowMapper<Group> groupMapper = (rs, row) -> {
    Group vo = new Group();
    vo.setId(String.valueOf(rs.getLong(1)));
    vo.setName(rs.getString(2));
    vo.setStatus(rs.getString(3));
    vo.setCreatedTime(rs.getTimestamp(4).getTime());
    vo.setModifiedTime(rs.getTimestamp(5).getTime());
    return vo;
  };

  private final JdbcTemplate template;
  private final QdrantClient client;

  public GroupService(JdbcTemplate template, VectorStore vectorStore) {
    this.template = template;
    this.client = (QdrantClient) vectorStore.getNativeClient().orElseThrow();
  }

  public Group get(Long id) {
    return template.queryForObject(
        SqlBuilder.select("id", "name", "status", "created_time", "modified_time")
            .from(GROUP_TABLE_NAME)
            .whereEq("id", id)
            .orderByDesc("created_time")
            .build(),
        groupMapper
    );
  }

  @Transactional(rollbackFor = Exception.class)
  public Long add(Long knowledgeId, String name) {
    long id = IdUtil.getSnowflakeNextId();
    template.update(
        SqlBuilder.insertInto(GROUP_TABLE_NAME, "id", "knowledge_id", "name", "status")
            .values()
            .addValue("?", "?", "?", "?")
            .precompileSql(),
        id,
        knowledgeId,
        name,
        "RUNNING"
    );
    return id;
  }

  public ImmutableList<Group> list(Long knowledgeId) {
    return template.query(
            SqlBuilder.select("id", "name", "status", "created_time", "modified_time")
                .from(GROUP_TABLE_NAME)
                .whereEq("knowledge_id", knowledgeId)
                .orderByDesc("created_time")
                .build(),
            groupMapper
        )
        .stream()
        .collect(Collectors.toCollection(Lists.mutable::empty))
        .toImmutable();
  }

  @Transactional(rollbackFor = Exception.class)
  public void finish(Long groupId) {
    template.update(
        SqlBuilder.update(GROUP_TABLE_NAME)
            .set("status", "FINISHED")
            .whereEq("id", groupId)
            .build()
    );
  }

  @Transactional(rollbackFor = Exception.class)
  public void remove(Long groupId) throws ExecutionException, InterruptedException {
    Long vectorSourceId = template.queryForObject(
        SqlBuilder.select("k.vector_source_id")
            .from(Alias.of(GROUP_TABLE_NAME, "g"), Alias.of(KnowledgeService.KNOWLEDGE_TABLE_NAME, "k"))
            .whereEq("g.knowledge_id", Column.as("k.id"))
            .andEq("g.id", groupId)
            .precompileSql(),
        Long.class,
        groupId
    );
    logger.info("Delete {} {}", vectorSourceId, groupId);
    client.deleteAsync(
        String.valueOf(vectorSourceId),
        Points.Filter.newBuilder()
            .addMust(ConditionFactory.matchKeyword("vector_source_id", String.valueOf(vectorSourceId)))
            .addMust(ConditionFactory.matchKeyword("group_id", String.valueOf(groupId)))
            .build()
    ).get();
    template.update(
        SqlBuilder.delete(GROUP_TABLE_NAME)
            .whereEq("id", groupId)
            .build()
    );
  }

  @Transactional(rollbackFor = Exception.class)
  public void removeByKnowledgeId(Long knowledgeId) {
    template.update(
        SqlBuilder.delete(GROUP_TABLE_NAME)
            .whereEq("knowledge_id", "?")
            .precompileSql(),
        knowledgeId
    );
  }
}
