package com.yaoai.ai.providers.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.yaoai.common.exception.BizException;
import com.yaoai.common.exception.ErrorCode;
import com.yaoai.domain.entity.SystemSetting;
import com.yaoai.domain.mapper.SystemSettingMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;

@Slf4j
@Service
public class PlatformModelConfigService {

    public static final String SETTING_KEY = "ai.model.config";
    public static final String MASKED_API_KEY = "******";

    private final SystemSettingMapper systemSettingMapper;
    private final ArkProperties arkProperties;
    private final ObjectMapper objectMapper;

    @Autowired
    public PlatformModelConfigService(SystemSettingMapper systemSettingMapper, ArkProperties arkProperties) {
        this(systemSettingMapper, arkProperties, new ObjectMapper());
    }

    PlatformModelConfigService(SystemSettingMapper systemSettingMapper,
                               ArkProperties arkProperties,
                               ObjectMapper objectMapper) {
        this.systemSettingMapper = systemSettingMapper;
        this.arkProperties = arkProperties;
        this.objectMapper = objectMapper;
    }

    public ResolvedModelConfig resolve(ModelCapability capability) {
        PlatformModelItem item = loadStoredSettings().get(capability);
        if (isUsable(item)) {
            return toResolved(item, fallback(capability));
        }
        return fallback(capability);
    }

    public PlatformModelSettings getAdminSettings() {
        PlatformModelSettings settings = withFallbacks(loadStoredSettings());
        maskApiKey(settings.getText());
        maskApiKey(settings.getImage());
        maskApiKey(settings.getVideo());
        return settings;
    }

    public PlatformModelSettings saveAdminSettings(PlatformModelSettings input, Long adminId) {
        PlatformModelSettings current = loadStoredSettings();
        PlatformModelSettings next = withFallbacks(input == null ? new PlatformModelSettings() : input);
        preserveMaskedApiKey(next.getText(), current.getText());
        preserveMaskedApiKey(next.getImage(), current.getImage());
        preserveMaskedApiKey(next.getVideo(), current.getVideo());

        try {
            String json = objectMapper.writeValueAsString(next);
            SystemSetting setting = systemSettingMapper.findByKey(SETTING_KEY).orElseGet(SystemSetting::new);
            setting.setSettingKey(SETTING_KEY);
            setting.setSettingValue(json);
            setting.setUpdatedAt(LocalDateTime.now());
            setting.setUpdatedBy(adminId);
            if (setting.getId() == null) {
                systemSettingMapper.insert(setting);
            } else {
                systemSettingMapper.updateById(setting);
            }
            return getAdminSettings();
        } catch (Exception e) {
            log.error("save platform model config failed", e);
            throw new BizException(ErrorCode.INTERNAL_ERROR, "保存模型配置失败: " + e.getMessage());
        }
    }

    private PlatformModelSettings loadStoredSettings() {
        return systemSettingMapper.findByKey(SETTING_KEY)
                .map(SystemSetting::getSettingValue)
                .filter(StringUtils::hasText)
                .map(this::parseSettings)
                .orElseGet(PlatformModelSettings::new);
    }

    private PlatformModelSettings parseSettings(String json) {
        try {
            PlatformModelSettings settings = objectMapper.readValue(json, PlatformModelSettings.class);
            return settings == null ? new PlatformModelSettings() : settings;
        } catch (Exception e) {
            log.warn("ignore invalid platform model config json", e);
            return new PlatformModelSettings();
        }
    }

    private PlatformModelSettings withFallbacks(PlatformModelSettings settings) {
        PlatformModelSettings next = new PlatformModelSettings();
        next.setText(merge(settings.getText(), fallback(ModelCapability.TEXT)));
        next.setImage(merge(settings.getImage(), fallback(ModelCapability.IMAGE)));
        next.setVideo(merge(settings.getVideo(), fallback(ModelCapability.VIDEO)));
        return next;
    }

    private PlatformModelItem merge(PlatformModelItem item, ResolvedModelConfig fallback) {
        PlatformModelItem next = item == null ? new PlatformModelItem() : item;
        if (!StringUtils.hasText(next.getProvider())) next.setProvider(fallback.provider());
        if (!StringUtils.hasText(next.getProviderName())) next.setProviderName(fallback.providerName());
        if (!StringUtils.hasText(next.getProtocol())) next.setProtocol(fallback.protocol());
        if (!StringUtils.hasText(next.getBaseUrl())) next.setBaseUrl(fallback.baseUrl());
        if (!StringUtils.hasText(next.getApiKey())) next.setApiKey(fallback.apiKey());
        if (!StringUtils.hasText(next.getModelId())) next.setModelId(fallback.modelId());
        if (!StringUtils.hasText(next.getModelName())) next.setModelName(fallback.modelName());
        if (!StringUtils.hasText(next.getEndpoint())) next.setEndpoint(fallback.endpoint());
        if (!StringUtils.hasText(next.getStatusEndpoint())) next.setStatusEndpoint(fallback.statusEndpoint());
        if (next.getEnabled() == null) next.setEnabled(false);
        return next;
    }

    private ResolvedModelConfig toResolved(PlatformModelItem item, ResolvedModelConfig fallback) {
        return new ResolvedModelConfig(
                valueOr(item.getProvider(), fallback.provider()),
                valueOr(item.getProviderName(), fallback.providerName()),
                valueOr(item.getProtocol(), fallback.protocol()),
                normalizeBaseUrl(valueOr(item.getBaseUrl(), fallback.baseUrl())),
                valueOr(item.getApiKey(), fallback.apiKey()),
                valueOr(item.getModelId(), fallback.modelId()),
                valueOr(item.getModelName(), fallback.modelName()),
                normalizeEndpoint(valueOr(item.getEndpoint(), fallback.endpoint())),
                normalizeEndpoint(valueOr(item.getStatusEndpoint(), fallback.statusEndpoint())),
                valueOr(item.getResolveIp(), fallback.resolveIp())
        );
    }

    private ResolvedModelConfig fallback(ModelCapability capability) {
        return switch (capability) {
            case TEXT -> new ResolvedModelConfig(
                    "volcengine",
                    "Volcengine ARK",
                    "openai",
                    normalizeBaseUrl(arkProperties.getBaseUrl()),
                    arkProperties.getApiKey(),
                    arkProperties.getTextModel(),
                    "Doubao Text",
                    "/chat/completions",
                    null,
                    null
            );
            case IMAGE -> new ResolvedModelConfig(
                    "volcengine",
                    "Volcengine ARK",
                    "seedream",
                    normalizeBaseUrl(arkProperties.getBaseUrl()),
                    arkProperties.getApiKey(),
                    arkProperties.getImageModel(),
                    "Seedream Image",
                    "/images/generations",
                    null,
                    null
            );
            case VIDEO -> new ResolvedModelConfig(
                    "volcengine",
                    "Volcengine ARK",
                    "seedance",
                    normalizeBaseUrl(arkProperties.getBaseUrl()),
                    arkProperties.getApiKey(),
                    arkProperties.getVideoModel(),
                    "Seedance Image-to-Video",
                    "/contents/generations/tasks",
                    "/contents/generations/tasks/{id}",
                    null
            );
        };
    }

    private boolean isUsable(PlatformModelItem item) {
        return item != null
                && Boolean.TRUE.equals(item.getEnabled())
                && StringUtils.hasText(item.getBaseUrl())
                && StringUtils.hasText(item.getApiKey())
                && StringUtils.hasText(item.getModelId())
                && !MASKED_API_KEY.equals(item.getApiKey());
    }

    private void preserveMaskedApiKey(PlatformModelItem next, PlatformModelItem current) {
        if (next == null) return;
        String apiKey = next.getApiKey();
        if (!StringUtils.hasText(apiKey) || MASKED_API_KEY.equals(apiKey)) {
            next.setApiKey(current == null ? "" : current.getApiKey());
        }
    }

    private void maskApiKey(PlatformModelItem item) {
        if (item != null && StringUtils.hasText(item.getApiKey())) {
            item.setApiKey(MASKED_API_KEY);
        }
    }

    private String valueOr(String value, String fallback) {
        return StringUtils.hasText(value) ? value.trim() : fallback;
    }

    private String normalizeBaseUrl(String value) {
        if (!StringUtils.hasText(value)) return value;
        return value.trim().replaceAll("/+$", "");
    }

    private String normalizeEndpoint(String value) {
        if (!StringUtils.hasText(value)) return value;
        String trimmed = value.trim();
        return trimmed.startsWith("/") ? trimmed : "/" + trimmed;
    }
}
