package com.magistr.app.controller;

import com.magistr.app.config.auth.RequireRoles;
import com.magistr.app.config.tenant.ConfigMapUpdater;
import com.magistr.app.config.tenant.TenantConfig;
import com.magistr.app.config.tenant.TenantConfigWatcher;
import com.magistr.app.config.tenant.TenantContext;
import com.magistr.app.config.tenant.TenantRoutingDataSource;
import com.magistr.app.model.Role;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * API управления подключениями к базам данных (тенантами).
 * Доступно только для ADMIN.
 *
 * При добавлении/удалении тенанта:
 * 1. Обновляется in-memory DataSource (мгновенно на этом поде)
 * 2. Обновляется K8s ConfigMap (через ConfigMapUpdater)
 * 3. Другие поды подхватят изменения через TenantConfigWatcher (~30 сек)
 */
@RestController
@RequestMapping("/api/database")
@RequireRoles({Role.ADMIN})
public class DatabaseController {

    private final TenantRoutingDataSource routingDataSource;
    private final ConfigMapUpdater configMapUpdater;
    private final TenantConfigWatcher configWatcher;

    public DatabaseController(TenantRoutingDataSource routingDataSource,
                              ConfigMapUpdater configMapUpdater,
                              TenantConfigWatcher configWatcher) {
        this.routingDataSource = routingDataSource;
        this.configMapUpdater = configMapUpdater;
        this.configWatcher = configWatcher;
    }

    /**
     * Статус текущего подключения (по домену запроса).
     */
    @GetMapping("/status")
    public ResponseEntity<Map<String, Object>> getStatus() {
        String currentTenant = TenantContext.getCurrentTenant();
        boolean connected = routingDataSource.testConnection(currentTenant);

        TenantConfig config = routingDataSource.getTenantConfigs().get(currentTenant);

        Map<String, Object> result = new HashMap<>();
        result.put("tenant", currentTenant);
        result.put("connected", connected);
        result.put("configured", config != null);
        if (config != null) {
            result.put("name", config.getName());
            result.put("url", config.getUrl());
        }
        return ResponseEntity.ok(result);
    }

    /**
     * Список всех тенантов.
     */
    @GetMapping("/tenants")
    public ResponseEntity<List<Map<String, Object>>> getTenants() {
        List<Map<String, Object>> result = new ArrayList<>();

        for (TenantConfig config : routingDataSource.getTenantConfigs().values()) {
            Map<String, Object> tenant = new HashMap<>();
            tenant.put("name", config.getName());
            tenant.put("domain", config.getDomain());
            tenant.put("url", config.getUrl());
            tenant.put("username", config.getUsername());
            tenant.put("connected", routingDataSource.testConnection(config.getDomain()));
            result.add(tenant);
        }

        return ResponseEntity.ok(result);
    }

    /**
     * Добавить новый тенант.
     */
    @PostMapping("/tenants")
    public ResponseEntity<Map<String, Object>> addTenant(@RequestBody TenantConfig config) {
        Map<String, Object> result = new HashMap<>();

        if (config.getDomain() == null || config.getDomain().isBlank()) {
            result.put("success", false);
            result.put("message", "Домен не может быть пустым");
            return ResponseEntity.badRequest().body(result);
        }

        if (config.getUrl() == null || config.getUrl().isBlank()) {
            result.put("success", false);
            result.put("message", "URL базы данных не может быть пустым");
            return ResponseEntity.badRequest().body(result);
        }

        if (routingDataSource.hasTenant(config.getDomain())) {
            routingDataSource.removeTenant(config.getDomain());
        }

        try {
            // 1. Добавить в in-memory (мгновенно на этом поде)
            routingDataSource.addTenant(config);

            // 2. Инициализировать БД (init.sql) если нужно
            configWatcher.initDatabaseForTenant(config);

            // 3. Обновить K8s ConfigMap (другие поды подхватят через ~30 сек)
            persistToConfigMap();

            result.put("success", true);
            result.put("message", "Тенант '" + config.getDomain() + "' добавлен");
            return ResponseEntity.ok(result);
        } catch (Exception e) {
            result.put("success", false);
            result.put("message", "Ошибка: " + e.getMessage());
            return ResponseEntity.internalServerError().body(result);
        }
    }

    /**
     * Удалить тенант.
     */
    @DeleteMapping("/tenants/{domain}")
    public ResponseEntity<Map<String, Object>> removeTenant(@PathVariable String domain) {
        Map<String, Object> result = new HashMap<>();

        if (!routingDataSource.hasTenant(domain)) {
            result.put("success", false);
            result.put("message", "Тенант '" + domain + "' не найден");
            return ResponseEntity.status(404).body(result);
        }

        routingDataSource.removeTenant(domain);
        persistToConfigMap();

        result.put("success", true);
        result.put("message", "Тенант '" + domain + "' удалён");
        return ResponseEntity.ok(result);
    }

    /**
     * Тест подключения к произвольной БД.
     */
    @PostMapping("/test")
    public ResponseEntity<Map<String, Object>> testConnection(@RequestBody Map<String, String> params) {
        String url = params.get("url");
        String username = params.get("username");
        String password = params.get("password");

        Map<String, Object> result = new HashMap<>();

        if (url == null || url.isBlank()) {
            result.put("success", false);
            result.put("message", "URL не указан");
            return ResponseEntity.badRequest().body(result);
        }

        String testResult = routingDataSource.testExternalConnection(url, username, password);
        boolean success = "OK".equals(testResult);

        result.put("success", success);
        result.put("message", success ? "Подключение успешно!" : testResult);
        return ResponseEntity.ok(result);
    }

    /**
     * Сохраняет текущий список тенантов в K8s ConfigMap.
     */
    private void persistToConfigMap() {
        List<TenantConfig> tenants = new ArrayList<>(routingDataSource.getTenantConfigs().values());
        boolean ok = configMapUpdater.updateTenantsConfig(tenants);
        if (ok) {
            configWatcher.refreshHash(); // Чтобы watcher не перезагрузил те же данные
        }
    }
}
