#!/usr/bin/env bash
set -euo pipefail

script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

if [ -f "${script_dir}/.env.example" ]; then
  template_file="${script_dir}/.env.example"
  default_env_file="${script_dir}/.env"
  compose_file="${script_dir}/docker-compose.yml"
elif [ -f "${script_dir}/../infra/.env.example" ]; then
  template_file="${script_dir}/../infra/.env.example"
  default_env_file="${script_dir}/../infra/.env"
  compose_file="${script_dir}/../infra/docker-compose.yml"
else
  printf 'Nao encontrei .env.example.\n' >&2
  exit 1
fi

env_file="${DATAIF_ENV_FILE:-${default_env_file}}"

input_fd=0
if [ -e /dev/tty ] && (: </dev/tty) 2>/dev/null; then
  exec 3</dev/tty
  input_fd=3
fi

random_secret() {
  if command -v openssl >/dev/null 2>&1; then
    openssl rand -base64 32 | tr -d '\n'
  else
    local secret
    set +o pipefail
    secret="$(LC_ALL=C tr -dc 'A-Za-z0-9_=-' </dev/urandom | head -c 48)"
    set -o pipefail
    printf '%s' "${secret}"
  fi
}

urlencode() {
  local value="$1"
  local length="${#value}"
  local index char

  for ((index = 0; index < length; index += 1)); do
    char="${value:index:1}"
    case "${char}" in
      [a-zA-Z0-9.~_-]) printf '%s' "${char}" ;;
      *) printf '%%%02X' "'${char}" ;;
    esac
  done
}

read_value() {
  local label="$1"
  local default_value="$2"
  local value

  if ! read -r -u "${input_fd}" -p "${label} [${default_value}]: " value; then
    value=""
  fi
  printf '%s' "${value:-${default_value}}"
}

read_secret() {
  local label="$1"
  local default_value="$2"
  local value

  if ! read -r -s -u "${input_fd}" -p "${label} [Enter gera segredo]: " value; then
    value=""
  fi
  printf '\n' >&2
  printf '%s' "${value:-${default_value}}"
}

validate_metabase_password() {
  local password="$1"
  local normalized

  normalized="$(printf '%s' "${password}" | tr '[:upper:]' '[:lower:]')"
  if [ "${#password}" -lt 8 ]; then
    return 1
  fi
  case "${normalized}" in
    admin|admin123|dataif|dataif123|password|password123|senha|senha123|123456|12345678|metabase|metabase123)
      return 1
      ;;
  esac
}

is_valid_email() {
  local value="$1"
  [[ "${value}" =~ ^[^[:space:]@]+@[^[:space:]@]+\.[^[:space:]@]+$ ]]
}

read_email() {
  local label="$1"
  local default_value="$2"
  local value

  while true; do
    value="$(read_value "${label}" "${default_value}")"
    if is_valid_email "${value}"; then
      printf '%s' "${value}"
      return
    fi
    printf 'Email invalido: %s\n' "${value}" >&2
  done
}

public_url_host() {
  local url="${1#http://}"
  url="${url#https://}"
  url="${url%%/*}"
  printf '%s' "${url%%:*}"
}

public_url_port() {
  local raw="$1"
  local scheme="http"
  local url hostport

  case "${raw}" in
    https://*) scheme="https" ;;
  esac
  url="${raw#http://}"
  url="${url#https://}"
  hostport="${url%%/*}"
  if [[ "${hostport}" == *:* ]]; then
    printf '%s' "${hostport##*:}"
  elif [ "${scheme}" = "https" ]; then
    printf '443'
  else
    printf '80'
  fi
}

read_metabase_admin_password() {
  local password

  while true; do
    password="$(read_secret "Senha admin Metabase" "$(random_secret)")"
    if validate_metabase_password "${password}"; then
      printf '%s' "${password}"
      return
    fi
    printf 'Senha admin Metabase fraca. Use ao menos 8 caracteres e evite valores comuns como admin, dataif ou password.\n' >&2
  done
}

set_env() {
  local key="$1"
  local value="$2"
  local tmp_file

  tmp_file="$(mktemp)"
  awk -v key="${key}" -v value="${value}" '
    BEGIN { done = 0 }
    $0 ~ "^" key "=" {
      print key "=" value
      done = 1
      next
    }
    { print }
    END {
      if (!done) {
        print key "=" value
      }
    }
  ' "${env_file}" > "${tmp_file}"
  mv "${tmp_file}" "${env_file}"
}

prompt_section() {
  printf '\n== %s ==\n' "$1"
}

printf 'Configurando DataIF .env\n'
printf 'Template: %s\n' "${template_file}"
printf 'Destino: %s\n\n' "${env_file}"

if [ -f "${env_file}" ] && [ "${DATAIF_FORCE_ENV:-false}" = "true" ]; then
  cp "${template_file}" "${env_file}"
elif [ -f "${env_file}" ]; then
  overwrite="$(read_value "Sobrescrever .env existente? (s/N)" "N")"
  case "${overwrite}" in
    s|S|sim|SIM) cp "${template_file}" "${env_file}" ;;
    *) printf 'Mantendo arquivo existente.\n' ;;
  esac
else
  cp "${template_file}" "${env_file}"
fi

prompt_section "URLs e portas"
public_base_url="$(read_value "URL publica da aplicacao" "http://localhost:5173")"
public_base_url="${public_base_url%/}"
public_host="$(public_url_host "${public_base_url}")"
public_port="$(public_url_port "${public_base_url}")"
web_port="$(read_value "Porta Web" "5173")"
api_port="$(read_value "Porta API" "8000")"
postgres_port="$(read_value "Porta Postgres host" "5433")"
metabase_port="$(read_value "Porta Metabase host" "3000")"
airflow_port="$(read_value "Porta Airflow host" "8088")"
keycloak_port="$(read_value "Porta Keycloak host" "8081")"
vanna_port="$(read_value "Porta Vanna host" "9000")"

prompt_section "Imagens"
image_registry="$(read_value "Registry imagens" "docker.io/dataif")"
image_tag="$(read_value "Tag imagens" "0.1.5")"

prompt_section "Usuarios administrativos"
admin_email="$(read_email "Email admin Metabase/Airflow" "admin@dataif.local")"
dataif_admin_user="$(read_value "Usuario admin DataIF" "dataif-admin")"
dataif_admin_email="$(read_email "Email admin DataIF" "${admin_email}")"
dataif_admin_first_name="$(read_value "Nome admin DataIF" "DataIF")"
dataif_admin_last_name="$(read_value "Sobrenome admin DataIF" "Admin")"
airflow_admin_user="$(read_value "Usuario admin Airflow" "admin")"
keycloak_admin_user="$(read_value "Usuario admin Keycloak" "admin")"

prompt_section "LLM"
llm_provider="$(read_value "Provider Vanna (ollama/maritaca)" "ollama")"
maritaca_key=""

if [ "${llm_provider}" = "maritaca" ]; then
  maritaca_key="$(read_secret "Chave Maritaca" "")"
fi

set_env COMPOSE_PROJECT_NAME "$(read_value "Nome projeto Compose" "dataif")"
set_env DATAIF_IMAGE_REGISTRY "${image_registry}"
set_env DATAIF_IMAGE_TAG "${image_tag}"
set_env DATAIF_PUBLIC_BASE_URL "${public_base_url}"
set_env DATAIF_PUBLIC_HOST "${public_host}"
set_env DATAIF_PUBLIC_PORT "${public_port}"
set_env WEB_PORT "${web_port}"
set_env API_PORT "${api_port}"
set_env POSTGRES_EXPOSE_PORT "${postgres_port}"
set_env METABASE_PORT "${metabase_port}"
set_env AIRFLOW_PORT "${airflow_port}"
set_env KEYCLOAK_PORT "${keycloak_port}"
set_env VANNA_PORT "${vanna_port}"
set_env METABASE_SITE_URL "${public_base_url%/}/metabase"
set_env AIRFLOW_PUBLIC_URL "${public_base_url%/}/airflow"
set_env AIRFLOW_API_URL "http://airflow-webserver:8080/airflow"
set_env AIRFLOW_DAG_REGISTRATION_TIMEOUT_SECONDS "240"
set_env CORS_ALLOW_ORIGINS "${public_base_url}"
set_env METABASE_ADMIN_EMAIL "${admin_email}"
set_env AIRFLOW_ADMIN_USER "${airflow_admin_user}"
set_env AIRFLOW_ADMIN_EMAIL "${admin_email}"
set_env KEYCLOAK_ADMIN "${keycloak_admin_user}"
set_env DATAIF_ADMIN_USERNAME "${dataif_admin_user}"
set_env DATAIF_ADMIN_EMAIL "${dataif_admin_email}"
set_env DATAIF_ADMIN_FIRST_NAME "${dataif_admin_first_name}"
set_env DATAIF_ADMIN_LAST_NAME "${dataif_admin_last_name}"
set_env VANNA_LLM_PROVIDER "${llm_provider}"
set_env VANNA_MARITACA_API_KEY "${maritaca_key}"

prompt_section "Senhas"
postgres_superuser_password="$(read_secret "Senha Postgres superuser" "$(random_secret)")"
dataif_etl_password="$(read_secret "Senha usuario ETL" "$(random_secret)")"
dataif_metabase_password="$(read_secret "Senha usuario Metabase" "$(random_secret)")"
dataif_vanna_password="$(read_secret "Senha usuario Vanna" "$(random_secret)")"
airflow_db_password="$(read_secret "Senha banco Airflow" "$(random_secret)")"
metabase_app_db_password="$(read_secret "Senha banco Metabase" "$(random_secret)")"
airflow_admin_password="$(read_secret "Senha admin Airflow" "$(random_secret)")"
metabase_admin_password="$(read_metabase_admin_password)"
keycloak_admin_password="$(read_secret "Senha admin Keycloak" "$(random_secret)")"
dataif_admin_password="$(read_secret "Senha admin DataIF" "${keycloak_admin_password}")"
metabase_embed_secret="$(read_secret "Segredo embed Metabase" "$(random_secret)")"

set_env POSTGRES_SUPERUSER_PASSWORD "${postgres_superuser_password}"
set_env DATAIF_ETL_PASSWORD "${dataif_etl_password}"
set_env DATAIF_ETL_PASSWORD_URLENC "$(urlencode "${dataif_etl_password}")"
set_env DATAIF_METABASE_PASSWORD "${dataif_metabase_password}"
set_env DATAIF_VANNA_PASSWORD "${dataif_vanna_password}"
set_env DATAIF_VANNA_PASSWORD_URLENC "$(urlencode "${dataif_vanna_password}")"
set_env AIRFLOW_DB_PASSWORD "${airflow_db_password}"
set_env AIRFLOW_DB_PASSWORD_URLENC "$(urlencode "${airflow_db_password}")"
set_env METABASE_APP_DB_PASSWORD "${metabase_app_db_password}"
set_env AIRFLOW_ADMIN_PASSWORD "${airflow_admin_password}"
set_env METABASE_ADMIN_PASSWORD "${metabase_admin_password}"
set_env KEYCLOAK_ADMIN_PASSWORD "${keycloak_admin_password}"
set_env DATAIF_ADMIN_PASSWORD "${dataif_admin_password}"
set_env METABASE_EMBED_SECRET "${metabase_embed_secret}"

chmod 600 "${env_file}"

printf '\n.env configurado: %s\n' "${env_file}"
printf 'Valide com: docker compose --env-file %s -f %s config >/dev/null\n' "${env_file}" "${compose_file}"
