package su.xserver.iikocon.service;

import io.vertx.core.Future;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.sqlclient.Pool;
import io.vertx.sqlclient.templates.SqlTemplate;

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

public class SettingsService {
  private final Pool pool;

  public SettingsService(Pool pool) { this.pool = pool; }

  public Future<JsonArray> getMetadata() {
    JsonArray meta = new JsonArray();
    meta.add(new JsonObject()
      .put("key", "site_name")
      .put("label", "Site Name")
      .put("description", "The name of the application shown in the header and title")
      .put("type", "text")
      .put("required", true)
    );
    meta.add(new JsonObject()
      .put("key", "site_description")
      .put("label", "Site Description")
      .put("description", "Brief description for SEO and meta tags")
      .put("type", "textarea")
      .put("rows", 2)
    );
    meta.add(new JsonObject()
      .put("key", "enable_registration")
      .put("label", "Allow Public Registration")
      .put("description", "If disabled, only admin can create users")
      .put("type", "boolean")
    );
    meta.add(new JsonObject()
      .put("key", "maintenance_mode")
      .put("label", "Maintenance Mode")
      .put("description", "When enabled, only admins can access the site")
      .put("type", "boolean")
    );
    meta.add(new JsonObject()
      .put("key", "session_timeout_minutes")
      .put("label", "Session Timeout (minutes)")
      .put("description", "How long until inactive users are logged out")
      .put("type", "number")
      .put("required", true)
    );

    // Безопасность и прокси
    meta.add(new JsonObject()
      .put("key", "use_proxy_headers")
      .put("label", "Use Proxy Headers")
      .put("description", "Respect X-Forwarded-* headers from trusted proxies")
      .put("type", "boolean")
    );
    meta.add(new JsonObject()
      .put("key", "trusted_proxies")
      .put("label", "Trusted Proxies")
      .put("description", "Comma-separated IP addresses of trusted proxies (e.g., 127.0.0.1,10.0.0.0/8)")
      .put("type", "text")
    );
    meta.add(new JsonObject()
      .put("key", "enable_csp")
      .put("label", "Enable CSP")
      .put("description", "Add Content-Security-Policy header")
      .put("type", "boolean")
    );
    meta.add(new JsonObject()
      .put("key", "allowed_hosts")
      .put("label", "Allowed Hosts")
      .put("description", "Comma-separated list of allowed Host headers (empty = allow all)")
      .put("type", "text")
    );

    return Future.succeededFuture(meta);
  }

  public Future<JsonObject> getAllWithDefaults() {
    return getAll().compose(values -> {
      JsonObject result = new JsonObject();
      return getMetadata().map(meta -> {
        for (Object item : meta) {
          JsonObject m = (JsonObject) item;
          String key = m.getString("key");
          String defaultValue = getDefaultValueByKey(key);
          String current = values.getString(key);
          result.put(key, current != null ? current : defaultValue);
        }
        return result;
      });
    });
  }

  private String getDefaultValueByKey(String key) {
    return switch (key) {
      case "site_name" -> "Admin Panel";
      case "site_description" -> "";
      case "enable_registration" -> "true";
      case "maintenance_mode" -> "false";
      case "session_timeout_minutes" -> "120";
      case "use_proxy_headers" -> "false";
      case "trusted_proxies" -> "127.0.0.1";
      case "enable_csp" -> "true";
      case "allowed_hosts" -> "";
      default -> "";
    };
  }

  public Future<Void> initDatabase() {
    String createTable = """
        CREATE TABLE IF NOT EXISTS app_settings (
          setting_key VARCHAR(255) PRIMARY KEY,
          setting_value TEXT
        )
        """;
    return pool.query(createTable).execute()
      .compose(v -> setIfAbsent("site_name", "Admin Panel"))
      .compose(v -> setIfAbsent("site_description", "Powerful administration dashboard"))
      .compose(v -> setIfAbsent("enable_registration", "true"))
      .compose(v -> setIfAbsent("maintenance_mode", "false"))
      .compose(v -> setIfAbsent("session_timeout_minutes", "120"))
      .mapEmpty();
  }

  private Future<Void> setIfAbsent(String key, String defaultValue) {
    return get(key).compose(existing -> {
      if (existing == null) {
        return set(key, defaultValue);
      }
      return Future.succeededFuture();
    });
  }

  public Future<String> get(String key) {
    return SqlTemplate.forQuery(pool, "SELECT setting_value FROM app_settings WHERE setting_key = #{key}")
      .execute(Map.of("key", key))
      .map(rows -> rows.iterator().hasNext() ? rows.iterator().next().getString("setting_value") : null);
  }

  public Future<Void> set(String key, String value) {
    return SqlTemplate.forUpdate(pool,
        "INSERT INTO app_settings (setting_key, setting_value) VALUES (#{key}, #{value}) " +
          "ON DUPLICATE KEY UPDATE setting_value = #{value}")
      .execute(Map.of("key", key, "value", value))
      .mapEmpty();
  }

  public Future<JsonObject> getAll() {
    return pool.query("SELECT setting_key, setting_value FROM app_settings")
      .execute()
      .map(rows -> {
        JsonObject json = new JsonObject();
        rows.forEach(row -> json.put(row.getString("setting_key"), row.getString("setting_value")));
        return json;
      });
  }

  // Публичные настройки (для фронтенда)
  public Future<JsonObject> getPublicSettings() {
    return getAll().map(all -> {
      JsonObject publicOnly = new JsonObject();
      // Только безопасные для отображения ключи
      List<String> publicKeys = List.of(
        "site_name", "site_description", "enable_registration"
      );
      for (String key : publicKeys) {
        String val = all.getString(key);
        if (val != null) publicOnly.put(key, val);
      }
      return publicOnly;
    });
  }

}
