package su.xserver.iikocon;

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.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", "theme")
      .put("label", "Theme")
      .put("description", "Default color scheme")
      .put("type", "select")
      .put("options", new JsonArray()
        .add(new JsonObject().put("value", "light").put("label", "Light"))
        .add(new JsonObject().put("value", "dark").put("label", "Dark"))
        .add(new JsonObject().put("value", "auto").put("label", "Auto (system preference)"))
      )
    );
    meta.add(new JsonObject()
      .put("key", "items_per_page")
      .put("label", "Items Per Page")
      .put("description", "Number of items shown in tables")
      .put("type", "number")
      .put("required", true)
    );
    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", "default_language")
      .put("label", "Default Language")
      .put("description", "Interface language")
      .put("type", "select")
      .put("options", new JsonArray()
        .add(new JsonObject().put("value", "en").put("label", "English"))
        .add(new JsonObject().put("value", "ru").put("label", "Русский"))
        .add(new JsonObject().put("value", "es").put("label", "Español"))
      )
    );
    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", "logo_url")
      .put("label", "Logo URL")
      .put("description", "Path or URL to custom logo image")
      .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 "theme" -> "light";
      case "items_per_page" -> "20";
      case "enable_registration" -> "true";
      case "maintenance_mode" -> "false";
      case "default_language" -> "en";
      case "session_timeout_minutes" -> "60";
      case "logo_url" -> "";
      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("theme", "light"))
      .compose(v -> setIfAbsent("items_per_page", "20"))
      .compose(v -> setIfAbsent("enable_registration", "true"))
      .compose(v -> setIfAbsent("maintenance_mode", "false"))
      .compose(v -> setIfAbsent("default_language", "en"))
      .compose(v -> setIfAbsent("session_timeout_minutes", "60"))
      .compose(v -> setIfAbsent("logo_url", "/assets/logo.png"))
      .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;
      });
  }
}
