package com.gzzm.lobster.llm;

import com.gzzm.lobster.common.ModelServiceTier;
import com.gzzm.platform.commons.crud.BaseNormalCrud;
import com.gzzm.platform.commons.crud.Buttons;
import com.gzzm.platform.commons.crud.PageTableView;
import net.cyan.arachne.annotation.Forward;
import net.cyan.arachne.annotation.NotSerialized;
import net.cyan.arachne.annotation.Select;
import net.cyan.arachne.annotation.Service;
import net.cyan.commons.util.KeyValue;
import net.cyan.commons.util.StringUtils;
import net.cyan.crud.OrderType;
import net.cyan.crud.annotation.Like;
import net.cyan.crud.view.components.CButton;
import net.cyan.nest.annotation.Inject;

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

/**
 * ModelProfileCrud —— 模型配置后台 CRUD / ModelProfile admin CRUD (zmeg_new framework).
 *
 * <p>实体：{@link ModelProfile}（表 {@code AI_MODEL_PROFILE}，主键 {@code modelId}）。
 * <p>挂载地址 {@code /ai/admin/model}，框架自动生成 list / add / update / delete 动作。
 * <p>新建 / 详情页走 {@code /ai/admin/model.ptl}（见 {@code web/ai/admin/model.ptl}）；
 * 列表页仍由 {@link #createListView()} 程序化构造。
 * <p>REST 风格同域 API 见 {@code AdminModelApi}（{@code /ai/api/admin/models/*}），二者互不冲突。
 *
 * <p>注意 apiKey 编辑策略：<br>
 *  - 详情页表单默认空，用户不填即视为"保留原值"；<br>
 *  - 保存时若字段为 null / 空串 / 含 {@code *} 则不写入，保留原值；<br>
 *  - 只有用户主动输入新值才会真的覆盖 apiKey。
 */
@Service(url = "/ai/admin/modelCrud")
public class ModelProfileCrud extends BaseNormalCrud<ModelProfile, String> {

    @Inject
    private ModelProfileDao modelDao;

    @Like
    private String modelId;

    public ModelProfileCrud() {
        setLog(true);
        addOrderBy("updateTime", OrderType.desc);
    }

    public String getModelId() { return modelId; }
    public void setModelId(String modelId) { this.modelId = modelId; }

    // ===== 新建 / 详情 forward 到 ptl =====

    @Override
    @Forward(page = "/ai/admin/model.ptl")
    public String add(String forward) throws Exception {
        return super.add(forward);
    }

    @Override
    @Forward(page = "/ai/admin/model.ptl")
    public String show(String key, String forward) throws Exception {
        return super.show(key, forward);
    }

    // ===== 下拉选项（@Select + getter）供 ptl 里 <select name=".." bind=""> 自动填充 =====

    @NotSerialized
    @Select(field = "entity.provider")
    public List<KeyValue<String>> getProviderOptions() {
        return enumOptions(ModelProvider.values());
    }

    @NotSerialized
    @Select(field = "entity.protocol")
    public List<KeyValue<String>> getProtocolOptions() {
        return enumOptions(ModelProtocol.values());
    }

    @NotSerialized
    @Select(field = "entity.serviceTier")
    public List<KeyValue<String>> getServiceTierOptions() {
        return enumOptions(ModelServiceTier.values());
    }

    private static <E extends Enum<E>> List<KeyValue<String>> enumOptions(E[] values) {
        List<KeyValue<String>> list = new ArrayList<>(values.length);
        for (E e : values) list.add(new KeyValue<>(e.name(), e.name()));
        return list;
    }

    // ===== 生命周期钩子 =====

    @Override
    public void initEntity(ModelProfile entity) throws Exception {
        super.initEntity(entity);
        entity.setEnabled(Boolean.TRUE);
        entity.setNativeToolCalling(Boolean.TRUE);
        entity.setStreaming(Boolean.TRUE);
        entity.setReasoning(Boolean.FALSE);
        entity.setMultimodal(Boolean.FALSE);
    }

    @Override
    public boolean beforeInsert() throws Exception {
        super.beforeInsert();
        Date now = new Date();
        ModelProfile p = getEntity();
        if (p.getCreateTime() == null) p.setCreateTime(now);
        p.setUpdateTime(now);
        return true;
    }

    @Override
    public boolean beforeUpdate() throws Exception {
        super.beforeUpdate();
        ModelProfile p = getEntity();
        // apiKey：空串 / 含 * 的占位串一律视为"未修改"，不写回
        String k = p.getApiKey();
        if (k == null || k.isEmpty() || k.contains("*")) {
            p.setApiKey(null);
        }
        p.setUpdateTime(new Date());
        return true;
    }

    // ===== 列表页 =====

    /** 双击 / 点击「修改」统一走此 JS 弹模态窗，URL 带 query 参数 modelId。 */
    private static final String OPEN_MODAL_JS =
            "System.showModal('/ai/admin/model?modelId=${modelId}', null, {width: 800, height: 600});";

    /** 新建模态窗：URL 不带 modelId，showModel 方法据此判断为"新建"流程。 */
    private static final String OPEN_MODAL_NEW_JS =
            "System.showModal('/ai/admin/model', null, {width: 800, height: 600});";


    @Service(url = "/ai/admin/model")
    public String showModel(String modelId) throws Exception {
        if(StringUtils.isNotEmpty(modelId)) {
            this.modelId = modelId;
            setEntity(getEntity(modelId));
        }
        return "/ai/admin/model.ptl";
    }


    @Override
    protected Object createListView() throws Exception {
        PageTableView view = new PageTableView();

        view.addComponent("Model ID", "modelId");

        view.addColumn("Model ID", "modelId").setWidth("200");
        view.addColumn("显示名", "displayName").setWidth("200");
        view.addColumn("Provider", "provider").setWidth("120");
        view.addColumn("Protocol", "protocol").setWidth("120");
        view.addColumn("服务层级", "serviceTier").setWidth("100");
        view.addColumn("上下文", "contextWindow").setWidth("80");
        view.addColumn("流式", "(streaming==null||streaming)?'是':'否'").setWidth("60");
        view.addColumn("工具调用", "(nativeToolCalling==null||nativeToolCalling)?'是':'否'").setWidth("80");
        view.addColumn("启用", "(enabled==null||enabled)?'是':'否'").setWidth("60");
        view.addColumn("更新时间", "updateTime").setWidth("140");

        // 自定义的"修改"列：直接走 System.showModal 弹模态窗
        view.addColumn("修改", new CButton("修改", OPEN_MODAL_JS)).setWidth("70");

        // 顶部按钮自己组：查询 / 新建（我们的 modal 版） / 删除。
        // 不再调 addDefaultButtons()——默认的"新建"按钮走的是 in-place 对话框，
        // 和"修改"/双击的 System.showModal 风格不统一。
        view.addButton(Buttons.query());
        view.addButton(new CButton("新建", OPEN_MODAL_NEW_JS));
        view.addButton(Buttons.delete());

        // 双击行同样走自定义的 showModal
        view.setOnDblClick(OPEN_MODAL_JS);

        return view;
    }
}
