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.Row;
import io.vertx.sqlclient.templates.SqlTemplate;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

public class RestaurantService {
  private final Pool pool;

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

  // Хеширование пароля SHA-1
  private String hashPassword(String password) {
    try {
      MessageDigest md = MessageDigest.getInstance("SHA-1");
      byte[] hash = md.digest(password.getBytes(StandardCharsets.UTF_8));
      StringBuilder hexString = new StringBuilder();
      for (byte b : hash) {
        String hex = Integer.toHexString(0xff & b);
        if (hex.length() == 1) hexString.append('0');
        hexString.append(hex);
      }
      return hexString.toString();
    } catch (NoSuchAlgorithmException e) {
      throw new RuntimeException("SHA-1 algorithm not found", e);
    }
  }

  public Future<Void> initDatabase() {
    String createTable = """
      CREATE TABLE IF NOT EXISTS restaurants (
        id INT AUTO_INCREMENT PRIMARY KEY,
        name VARCHAR(255) UNIQUE NOT NULL,
        login VARCHAR(255) UNIQUE NOT NULL,
        password VARCHAR(255) NOT NULL,
        host VARCHAR(255) NOT NULL,
        https BOOLEAN DEFAULT FALSE,
        created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
      )
      """;
    return pool.query(createTable).execute().mapEmpty();
  }

  public Future<Void> createRestaurant(String name, String login, String password, String host, boolean https) {
    String hashedPassword = hashPassword(password);
    Map<String, Object> params = Map.of(
      "name", name,
      "login", login,
      "password", hashedPassword,
      "host", host,
      "https", https
    );
    return SqlTemplate.forUpdate(pool,
        "INSERT INTO restaurants (name, login, password, host, https) VALUES (#{name}, #{login}, #{password}, #{host}, #{https})")
      .execute(params)
      .mapEmpty();
  }

  public Future<JsonArray> getAllRestaurants() {
    return pool.query("SELECT id, name, login, created, updated, https, host FROM restaurants ORDER BY id")
      .execute()
      .map(rows -> {
        JsonArray array = new JsonArray();
        for (Row row : rows) {
          array.add(new JsonObject()
            .put("id", row.getInteger("id"))
            .put("login", row.getString("login"))
            .put("name", row.getString("name"))
            .put("created", row.getLocalDateTime("created") != null ?
              row.getLocalDateTime("created").toString() : null)
            .put("updated", row.getLocalDateTime("updated") != null ?
              row.getLocalDateTime("updated").toString() : null)
            .put("https", row.getBoolean("https"))
            .put("host", row.getString("host")));
        }
        return array;
      });
  }

  public Future<JsonObject> findById(int id) {
    return SqlTemplate.forQuery(pool,
        "SELECT id, name, login, password, https, host, created, updated FROM restaurants WHERE id = #{id}")
      .mapTo(row -> new JsonObject()
        .put("id", row.getInteger("id"))
        .put("name", row.getString("name"))
        .put("login", row.getString("login"))
        .put("password", row.getString("password"))
        .put("https", row.getBoolean("https"))
        .put("host", row.getString("host"))
        .put("created", row.getLocalDateTime("created") != null ? row.getLocalDateTime("created").toString() : null)
        .put("updated", row.getLocalDateTime("updated") != null ? row.getLocalDateTime("updated").toString() : null))
      .execute(Collections.singletonMap("id", id))
      .map(rows -> rows.iterator().hasNext() ? rows.iterator().next() : null);
  }

  public Future<Void> updateRestaurant(int id, String name, String login, String password, String host, boolean https) {
    Map<String, Object> params = new HashMap<>();
    params.put("id", id);
    params.put("name", name);
    params.put("login", login);
    params.put("host", host);
    params.put("https", https);
    String sql;
    if (password != null && !password.isEmpty()) {
      String hashedPassword = hashPassword(password);
      params.put("password", hashedPassword);
      sql = "UPDATE restaurants SET name = #{name}, login = #{login}, password = #{password}, host = #{host}, https = #{https} WHERE id = #{id}";
    } else {
      sql = "UPDATE restaurants SET name = #{name}, login = #{login}, host = #{host}, https = #{https} WHERE id = #{id}";
    }
    return SqlTemplate.forUpdate(pool, sql).execute(params).mapEmpty();
  }

  public Future<Void> deleteRestaurant(int id) {
    return SqlTemplate.forUpdate(pool, "DELETE FROM restaurants WHERE id = #{id}")
      .execute(Collections.singletonMap("id", id))
      .mapEmpty();
  }
}
