package com.yaoai.api.controller;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yaoai.api.dto.settings.ModelProviderDTO;
import com.yaoai.common.exception.BizException;
import com.yaoai.common.exception.ErrorCode;
import com.yaoai.common.response.ApiResponse;
import com.yaoai.domain.entity.TenantModelDefault;
import com.yaoai.domain.entity.TenantModelProvider;
import com.yaoai.domain.entity.TenantSetting;
import com.yaoai.domain.mapper.TenantModelDefaultMapper;
import com.yaoai.domain.mapper.TenantModelProviderMapper;
import com.yaoai.domain.mapper.TenantSettingMapper;
import com.yaoai.security.context.TenantContext;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Map;

@Tag(name = "租户设置")
@RestController
@RequiredArgsConstructor
public class TenantSettingsController {

    private final TenantSettingMapper settingMapper;
    private final TenantModelProviderMapper providerMapper;
    private final TenantModelDefaultMapper defaultMapper;
    private final ObjectMapper objectMapper;

    // ---- Generic Settings ----

    @Operation(summary = "获取设置项")
    @GetMapping("/settings/{key}")
    public ApiResponse<Map<String, Object>> getSetting(@PathVariable String key) {
        Long tenantId = TenantContext.get();
        String value = settingMapper.findByKey(tenantId, key)
                .map(TenantSetting::getSettingValue)
                .orElse(null);
        return ApiResponse.success(Map.of("key", key, "value", value != null ? value : ""));
    }

    @Operation(summary = "保存设置项")
    @PutMapping("/settings/{key}")
    public ApiResponse<Void> saveSetting(@PathVariable String key,
                                          @RequestBody Map<String, Object> body) {
        Long tenantId = TenantContext.get();
        String value = body.getOrDefault("value", "").toString();
        TenantSetting existing = settingMapper.findByKey(tenantId, key).orElse(null);
        if (existing == null) {
            TenantSetting s = new TenantSetting();
            s.setTenantId(tenantId);
            s.setSettingKey(key);
            s.setSettingValue(value);
            settingMapper.insert(s);
        } else {
            existing.setSettingValue(value);
            settingMapper.updateById(existing);
        }
        return ApiResponse.success(null);
    }

    // ---- Model Providers ----

    @Operation(summary = "模型供应商列表")
    @GetMapping("/models/providers")
    public ApiResponse<List<ModelProviderDTO>> listProviders(
            @RequestParam(required = false) String capability) {
        Long tenantId = TenantContext.get();
        List<TenantModelProvider> providers = capability != null
                ? providerMapper.findByTenantAndCapability(tenantId, capability)
                : providerMapper.findByTenant(tenantId);
        List<ModelProviderDTO> dtos = providers.stream().map(p -> {
            ModelProviderDTO dto = ModelProviderDTO.from(p);
            dto.setModels(parseModels(p.getModelsJson()));
            return dto;
        }).toList();
        return ApiResponse.success(dtos);
    }

    @Operation(summary = "新增模型供应商")
    @PostMapping("/models/providers")
    public ApiResponse<ModelProviderDTO> createProvider(@RequestBody Map<String, Object> body) {
        Long tenantId = TenantContext.get();
        TenantModelProvider p = buildProvider(tenantId, body, null);
        providerMapper.insert(p);
        ModelProviderDTO dto = ModelProviderDTO.from(p);
        dto.setModels(parseModels(p.getModelsJson()));
        return ApiResponse.success(dto);
    }

    @Operation(summary = "更新模型供应商")
    @PutMapping("/models/providers/{id}")
    public ApiResponse<ModelProviderDTO> updateProvider(@PathVariable Long id,
                                                         @RequestBody Map<String, Object> body) {
        Long tenantId = TenantContext.get();
        TenantModelProvider existing = providerMapper.selectById(id);
        if (existing == null || !existing.getTenantId().equals(tenantId)) {
            throw new BizException(ErrorCode.NOT_FOUND, "供应商不存在");
        }
        TenantModelProvider p = buildProvider(tenantId, body, existing);
        p.setId(id);
        providerMapper.updateById(p);
        ModelProviderDTO dto = ModelProviderDTO.from(p);
        dto.setModels(parseModels(p.getModelsJson()));
        return ApiResponse.success(dto);
    }

    @Operation(summary = "删除模型供应商")
    @DeleteMapping("/models/providers/{id}")
    public ApiResponse<Void> deleteProvider(@PathVariable Long id) {
        Long tenantId = TenantContext.get();
        TenantModelProvider existing = providerMapper.selectById(id);
        if (existing == null || !existing.getTenantId().equals(tenantId)) {
            throw new BizException(ErrorCode.NOT_FOUND, "供应商不存在");
        }
        providerMapper.deleteById(id);
        return ApiResponse.success(null);
    }

    // ---- Model Defaults ----

    @Operation(summary = "获取默认模型配置")
    @GetMapping("/models/defaults")
    public ApiResponse<Map<String, Object>> getDefaults() {
        Long tenantId = TenantContext.get();
        List<TenantModelDefault> defaults = defaultMapper.findByTenant(tenantId);
        Map<String, Object> result = new java.util.HashMap<>();
        for (TenantModelDefault d : defaults) {
            result.put(d.getCapability(), Map.of(
                    "providerId", d.getProviderId(),
                    "modelId", d.getModelId()
            ));
        }
        return ApiResponse.success(result);
    }

    @Operation(summary = "保存默认模型配置")
    @PutMapping("/models/defaults")
    public ApiResponse<Void> saveDefaults(@RequestBody Map<String, Object> body) {
        Long tenantId = TenantContext.get();
        for (String cap : List.of("text", "image", "video")) {
            if (!body.containsKey(cap)) continue;
            @SuppressWarnings("unchecked")
            Map<String, Object> val = (Map<String, Object>) body.get(cap);
            if (val == null) continue;
            Long providerId = Long.valueOf(val.get("providerId").toString());
            String modelId = val.get("modelId").toString();
            TenantModelDefault existing = defaultMapper.findByCapability(tenantId, cap).orElse(null);
            if (existing == null) {
                TenantModelDefault d = new TenantModelDefault();
                d.setTenantId(tenantId);
                d.setCapability(cap);
                d.setProviderId(providerId);
                d.setModelId(modelId);
                defaultMapper.insert(d);
            } else {
                existing.setProviderId(providerId);
                existing.setModelId(modelId);
                defaultMapper.updateById(existing);
            }
        }
        return ApiResponse.success(null);
    }

    // ---- Helpers ----

    private TenantModelProvider buildProvider(Long tenantId, Map<String, Object> body,
                                               TenantModelProvider existing) {
        TenantModelProvider p = new TenantModelProvider();
        p.setTenantId(tenantId);
        p.setName(body.getOrDefault("name", "").toString());
        p.setProtocol(body.getOrDefault("protocol", "openai").toString());
        p.setCapability(body.getOrDefault("capability", "text").toString());
        p.setBaseUrl(body.getOrDefault("baseUrl", "").toString());

        String apiKey = body.getOrDefault("apiKey", "").toString();
        if (apiKey.contains("••••") && existing != null) {
            p.setApiKey(existing.getApiKey());
        } else {
            p.setApiKey(apiKey);
        }

        String secretKey = body.getOrDefault("secretKey", "").toString();
        if (secretKey.contains("••••") && existing != null) {
            p.setSecretKey(existing.getSecretKey());
        } else {
            p.setSecretKey(secretKey);
        }

        Object models = body.get("models");
        if (models != null) {
            try {
                p.setModelsJson(objectMapper.writeValueAsString(models));
            } catch (Exception e) {
                p.setModelsJson("[]");
            }
        } else {
            p.setModelsJson(existing != null ? existing.getModelsJson() : "[]");
        }
        return p;
    }

    private List<ModelProviderDTO.ModelItem> parseModels(String json) {
        if (json == null || json.isBlank()) return List.of();
        try {
            return objectMapper.readValue(json,
                    new TypeReference<List<ModelProviderDTO.ModelItem>>() {});
        } catch (Exception e) {
            return List.of();
        }
    }
}
