package com.buukle.agent.instance.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.buukle.agent.common.event.SessionCreatedEvent;
import com.buukle.agent.common.exception.BizException;
import com.buukle.agent.instance.domain.AgentInstance;
import com.buukle.agent.instance.domain.AgentSession;
import com.buukle.agent.instance.dtvo.dto.CreateSessionDTO;
import com.buukle.agent.instance.dtvo.enums.SessionEnum;
import com.buukle.agent.instance.dtvo.vo.SessionVO;
import com.buukle.agent.instance.exception.InstanceErrorCode;
import com.buukle.agent.instance.repository.InstanceMapper;
import com.buukle.agent.instance.repository.SessionMapper;
import com.buukle.agent.instance.service.SessionService;
import com.buukle.agent.instance.service.converter.SessionConverter;
import lombok.RequiredArgsConstructor;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
@RequiredArgsConstructor
public class SessionServiceImpl extends ServiceImpl<SessionMapper, AgentSession> implements SessionService {
    private final SessionConverter sessionConverter;
    private final ApplicationEventPublisher eventPublisher;
    private final InstanceMapper instanceMapper;

    @Override
    public SessionVO createSession(CreateSessionDTO dto) {
        AgentInstance instance = instanceMapper.selectById(dto.getAgentInstanceId());
        if (instance == null) {
            throw new BizException(InstanceErrorCode.INSTANCE_NOT_FOUND);
        }
        if (instance.getModelRouteId() == null && dto.getOverrideModelRouteId() == null) {
            throw new BizException(InstanceErrorCode.INSTANCE_NO_MODEL_ROUTE);
        }
        AgentSession session = sessionConverter.toDO(dto);
        session.setTitleAutoGenerated(true);
        save(session);
        SessionVO vo = sessionConverter.toVO(session);
        SessionCreatedEvent event = new SessionCreatedEvent();
        event.setSessionId(vo.getId());
        event.setAgentInstanceId(dto.getAgentInstanceId());
        eventPublisher.publishEvent(event);
        return vo;
    }

    @Override
    public SessionVO getSession(Long id) {
        AgentSession session = getById(id);
        if (session == null) throw new BizException(InstanceErrorCode.SESSION_NOT_FOUND);
        if (SessionEnum.STATUS_CLOSED.equals(session.getStatus()))
            throw new BizException(InstanceErrorCode.SESSION_CLOSED);
        return sessionConverter.toVO(session);
    }

    @Override
    public SessionVO updateSession(Long id, String title) {
        AgentSession session = getById(id);
        if (session == null) throw new BizException(InstanceErrorCode.SESSION_NOT_FOUND);
        session.setTitle(title);
        session.setTitleAutoGenerated(false);
        updateById(session);
        return sessionConverter.toVO(session);
    }

    @Override
    public List<SessionVO> listSessions(int offset, int limit, String keyword) {
        List<AgentSession> sessions = lambdaQuery()
                .eq(AgentSession::getStatus, SessionEnum.STATUS_ACTIVE)
                .like(keyword != null && !keyword.isBlank(), AgentSession::getTitle, keyword)
                .orderByDesc(AgentSession::getUpdatedAt)
                .last("OFFSET " + offset + " LIMIT " + limit)
                .list();
        return sessions.stream().map(sessionConverter::toVO).toList();
    }

    @Override
    public void closeSession(Long id) {
        AgentSession session = getById(id);
        if (session == null) throw new BizException(InstanceErrorCode.SESSION_NOT_FOUND);
        session.setStatus(SessionEnum.STATUS_CLOSED);
        updateById(session);
    }

    @Override
    public void batchCloseSessions(List<Long> ids) {
        if (ids == null || ids.isEmpty()) return;
        lambdaUpdate()
                .in(AgentSession::getId, ids)
                .set(AgentSession::getStatus, SessionEnum.STATUS_CLOSED)
                .update();
    }

    @Override
    public void updateSummaryManually(Long sessionId, String summary) {
        AgentSession session = getById(sessionId);
        if (session == null) return;
        session.setSummary(summary);
        session.setSummaryUpdatedAt(java.time.LocalDateTime.now());
        updateById(session);
    }

    @Override
    public void touchSession(Long sessionId) {
        AgentSession session = getById(sessionId);
        if (session == null) return;
        // updateById triggers AuditMetaObjectHandler to set updatedAt = now
        session.setTitle(session.getTitle());
        updateById(session);
    }

    @Override
    public void updateSummary(Long sessionId, String summary, String summaryUpdatedAt, Long modelRouteId) {
        AgentSession session = getById(sessionId);
        if (session == null) return;
        session.setSummary(summary);
        try {
            session.setSummaryUpdatedAt(java.time.LocalDateTime.parse(summaryUpdatedAt));
        } catch (Exception e) {
            session.setSummaryUpdatedAt(java.time.LocalDateTime.now());
        }
        session.setSummaryModelRouteId(modelRouteId);
        updateById(session);
    }
}
