package com.gzzm.lobster.plan;

import com.gzzm.lobster.common.IdGenerator;
import com.gzzm.lobster.common.LobsterException;
import com.gzzm.lobster.common.PlanItemStatus;
import com.gzzm.lobster.common.PlanStatus;
import com.gzzm.lobster.identity.UserContext;
import com.gzzm.lobster.thread.ThreadRoom;
import com.gzzm.platform.commons.Tools;
import net.cyan.arachne.annotation.Service;
import net.cyan.nest.annotation.Inject;

import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * PlanService —— 计划与步骤服务 / Plan + PlanItem service.
 *
 * <p>负责 {@code update_plan} 工具的后端逻辑。runtime 不编排执行顺序；
 * 计划只是 LLM 自主使用的状态表达，平台只做持久化 + 流式推送。
 */
@Service
public class PlanService {

    @Inject
    private PlanDao planDao;

    @Inject
    private PlanItemDao itemDao;

    /** thunwind DAO 跨线程保护 —— 详见 feedback_thunwind_dao_thread_binding */
    private PlanDao planDao() {
        try {
            PlanDao d = Tools.getBean(PlanDao.class);
            if (d != null) return d;
        } catch (Throwable ignore) { /* fallback */ }
        return planDao;
    }
    private PlanItemDao itemDao() {
        try {
            PlanItemDao d = Tools.getBean(PlanItemDao.class);
            if (d != null) return d;
        } catch (Throwable ignore) { /* fallback */ }
        return itemDao;
    }

    /**
     * 更新或创建计划，返回最新 items 列表。
     * Upsert a plan and return the authoritative items list.
     */
    public PlanSnapshot upsert(ThreadRoom thread, UserContext user, String planId, String title,
                               List<Map<String, Object>> itemSpecs, String skillId) throws Exception {
        Plan plan = planId == null ? null : planDao().getPlan(planId);
        if (plan == null) {
            plan = planDao().getActivePlan(thread.getThreadId(), PlanStatus.ABANDONED);
        }
        if (plan == null) {
            plan = new Plan();
            plan.setPlanId(IdGenerator.planId());
            plan.setThreadId(thread.getThreadId());
            plan.setUserId(user.getUserId());
            plan.setTitle(title == null ? "任务计划" : title);
            plan.setSkillId(skillId);
            plan.setStatus(PlanStatus.ACTIVE);
            plan.setCreateTime(new Date());
            plan.setUpdateTime(new Date());
            planDao().save(plan);
        } else {
            if (title != null) plan.setTitle(title);
            if (skillId != null) plan.setSkillId(skillId);
            plan.setStatus(PlanStatus.ACTIVE);
            plan.setUpdateTime(new Date());
            planDao().save(plan);
        }
        // 替换 items（简单策略：全量覆盖）/ Simple strategy: replace all items.
        itemDao().deleteByPlan(plan.getPlanId());
        List<PlanItem> items = new ArrayList<>();
        if (itemSpecs != null) {
            int seq = 1;
            for (Map<String, Object> spec : itemSpecs) {
                PlanItem it = new PlanItem();
                it.setItemId(IdGenerator.planItemId());
                it.setPlanId(plan.getPlanId());
                it.setSeq(asInt(spec.get("seq"), seq++));
                it.setTitle(asStr(spec.get("title")));
                it.setDescription(asStr(spec.get("description")));
                it.setStatus(parseStatus(asStr(spec.get("status"))));
                it.setResultSummary(asStr(spec.get("resultSummary")));
                it.setArtifactId(asStr(spec.get("artifactId")));
                it.setCreateTime(new Date());
                it.setUpdateTime(new Date());
                itemDao().save(it);
                items.add(it);
            }
        }
        // 判断是否全部完成 / detect full completion
        boolean allCompleted = !items.isEmpty();
        int completed = 0;
        for (PlanItem it : items) {
            if (it.getStatus() == PlanItemStatus.COMPLETED) completed++;
            else allCompleted = false;
        }
        if (allCompleted) {
            planDao().updateStatus(PlanStatus.COMPLETED, new Date(), plan.getPlanId());
            plan.setStatus(PlanStatus.COMPLETED);
        }
        return new PlanSnapshot(plan, items, completed);
    }

    public PlanSnapshot loadActive(String threadId) throws Exception {
        Plan p = planDao().getActivePlan(threadId, PlanStatus.ABANDONED);
        if (p == null) return null;
        List<PlanItem> items = itemDao().listByPlan(p.getPlanId());
        int completed = 0;
        for (PlanItem it : items) if (it.getStatus() == PlanItemStatus.COMPLETED) completed++;
        return new PlanSnapshot(p, items, completed);
    }

    private int asInt(Object o, int def) {
        if (o == null) return def;
        if (o instanceof Number) return ((Number) o).intValue();
        try { return Integer.parseInt(String.valueOf(o)); } catch (Exception e) { return def; }
    }

    private String asStr(Object o) { return o == null ? null : String.valueOf(o); }

    private PlanItemStatus parseStatus(String s) {
        if (s == null) return PlanItemStatus.PENDING;
        try { return PlanItemStatus.valueOf(s.trim()); }
        catch (Exception e) {
            String u = s.toUpperCase();
            switch (u) {
                case "DONE": case "OK": return PlanItemStatus.COMPLETED;
                case "INPROGRESS": case "DOING": return PlanItemStatus.IN_PROGRESS;
                default: return PlanItemStatus.PENDING;
            }
        }
    }

    /** 用于流式推送的快照 / Snapshot used by streaming emitters. */
    public static final class PlanSnapshot {
        private final Plan plan;
        private final List<PlanItem> items;
        private final int completedCount;

        public PlanSnapshot(Plan plan, List<PlanItem> items, int completedCount) {
            this.plan = plan;
            this.items = items;
            this.completedCount = completedCount;
        }

        public Plan getPlan() { return plan; }
        public List<PlanItem> getItems() { return items; }
        public int getCompletedCount() { return completedCount; }
        public int getTotalCount() { return items == null ? 0 : items.size(); }

        public Map<String, Object> toMap() {
            Map<String, Object> map = new LinkedHashMap<>();
            if (plan != null) {
                map.put("planId", plan.getPlanId());
                map.put("title", plan.getTitle());
                map.put("status", plan.getStatus().name());
            }
            List<Map<String, Object>> itemList = new ArrayList<>();
            if (items != null) {
                for (PlanItem it : items) {
                    Map<String, Object> m = new LinkedHashMap<>();
                    m.put("itemId", it.getItemId());
                    m.put("seq", it.getSeq());
                    m.put("title", it.getTitle());
                    m.put("status", it.getStatus().name());
                    if (it.getResultSummary() != null) m.put("resultSummary", it.getResultSummary());
                    if (it.getArtifactId() != null) m.put("artifactId", it.getArtifactId());
                    itemList.add(m);
                }
            }
            map.put("items", itemList);
            map.put("completedCount", completedCount);
            map.put("totalCount", getTotalCount());
            return map;
        }
    }
}
