package com.gzzm.lobster.run;

import com.gzzm.lobster.common.RunExitReason;
import com.gzzm.lobster.common.RunStatus;
import net.cyan.thunwind.annotation.OQL;
import net.cyan.thunwind.annotation.OQLUpdate;
import net.cyan.thunwind.dao.GeneralDao;

import java.util.Date;
import java.util.List;

/**
 * RunDao —— Run 持久化 / Run persistence (internal observation).
 *
 * <p>status 枚举 thunwind 默认存 smallint ordinal，OQL 里用参数绑定，不写字面量。
 */
public abstract class RunDao extends GeneralDao {

    @OQL("select r from Run r where r.runId=:1")
    public abstract Run getRun(String runId) throws Exception;

    @OQL("select r from Run r where r.threadId=:1 order by r.startedAt desc")
    public abstract List<Run> listByThread(String threadId) throws Exception;

    @OQL("select r from Run r where r.userId=:1 and r.threadId=:2 and r.clientRequestId=:3 order by r.startedAt desc")
    public abstract List<Run> listByClientRequestId(String userId, String threadId,
                                                    String clientRequestId) throws Exception;

    @OQL("select r from Run r where r.status=?1 and r.heartbeatAt<=?2 order by r.heartbeatAt asc limit :3,:4")
    public abstract List<Run> listStaleRunnable(RunStatus status, Date staleBefore, int offset, int limit) throws Exception;

    @OQL("select count(r.runId) from Run r where r.userId=:1 and r.status=?2")
    public abstract Long countActiveByUser(String userId, RunStatus status) throws Exception;

    @OQL("select count(r.runId) from Run r where r.threadId=:1 and r.status=?2")
    public abstract Long countActiveByThread(String threadId, RunStatus status) throws Exception;

    @OQLUpdate("update Run set status=?1, endedAt=?2, exitReason=?3 where runId=?4")
    public abstract int cancel(RunStatus status, Date endedAt, RunExitReason exitReason, String runId) throws Exception;

    @OQLUpdate("update Run set heartbeatAt=?1 where runId=?2 and status=?3")
    public abstract int heartbeat(Date heartbeatAt, String runId, RunStatus status) throws Exception;

    @OQLUpdate("update Run set heartbeatAt=?1 where runId=?2 and status=?3 and workerId=?4")
    public abstract int heartbeatOwned(Date heartbeatAt, String runId, RunStatus status,
                                       String workerId) throws Exception;

    @OQLUpdate("update Run set turns=?1, heartbeatAt=?2 where runId=?3 and status=?4 and workerId=?5")
    public abstract int progressOwned(Integer turns, Date heartbeatAt, String runId,
                                      RunStatus status, String workerId) throws Exception;

    @OQLUpdate("update Run set requestPayloadJson=?1 where runId=?2 and status=?3 and workerId=?4")
    public abstract int updateRequestPayloadOwned(String requestPayloadJson, String runId,
                                                  RunStatus status, String workerId) throws Exception;

    @OQLUpdate("update Run set modelId=?1 where runId=?2 and status=?3 and workerId=?4")
    public abstract int updateModelOwned(String modelId, String runId, RunStatus status,
                                         String workerId) throws Exception;

    @OQLUpdate("update Run set status=?1, endedAt=?2, exitReason=?3, turns=?4, errorCode=?5, errorMessage=?6, heartbeatAt=?2 where runId=?7 and status=?8 and workerId=?9")
    public abstract int finishOwned(RunStatus toStatus, Date endedAt, RunExitReason exitReason,
                                    Integer turns, String errorCode, String errorMessage,
                                    String runId, RunStatus fromStatus, String workerId) throws Exception;

    @OQLUpdate("update Run set status=?1, exitReason=?2, turns=?3, heartbeatAt=?4 where runId=?5 and status=?6 and workerId=?7")
    public abstract int suspendOwned(RunStatus toStatus, RunExitReason exitReason, Integer turns,
                                     Date heartbeatAt, String runId, RunStatus fromStatus,
                                     String workerId) throws Exception;

    @OQLUpdate("update Run set workerId=?1, claimedAt=?2, heartbeatAt=?2 where runId=?3 and status=?4 and heartbeatAt<=?5")
    public abstract int claimStaleRunnable(String workerId, Date now, String runId, RunStatus status, Date staleBefore) throws Exception;

    @OQLUpdate("update Run set status=?1, endedAt=?2, exitReason=?3 where runId=?4 and status=?5")
    public abstract int finishIfStatus(RunStatus toStatus, Date endedAt, RunExitReason exitReason,
                                       String runId, RunStatus fromStatus) throws Exception;
}
