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

# DPSVR Complete Laravel Installable Application
# Server installation script
# Run this script from the root folder of the uploaded DPSVR Laravel application.

APP_TITLE="DPSVR Complete Laravel Installable Application"
MIN_PHP_VERSION="8.2.0"

GREEN="\033[0;32m"
YELLOW="\033[1;33m"
RED="\033[0;31m"
BLUE="\033[0;34m"
NC="\033[0m"

print_header() {
  echo -e "${BLUE}============================================================${NC}"
  echo -e "${BLUE}${APP_TITLE} - Server Installer${NC}"
  echo -e "${BLUE}============================================================${NC}"
}

info() { echo -e "${GREEN}[OK]${NC} $1"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
fail() { echo -e "${RED}[ERROR]${NC} $1"; exit 1; }

command_exists() {
  command -v "$1" >/dev/null 2>&1
}

confirm() {
  local prompt="$1"
  local default="${2:-Y}"
  local answer
  if [[ "$default" == "Y" ]]; then
    read -r -p "$prompt [Y/n]: " answer || true
    answer="${answer:-Y}"
  else
    read -r -p "$prompt [y/N]: " answer || true
    answer="${answer:-N}"
  fi
  [[ "$answer" =~ ^[Yy]$ ]]
}

ask() {
  local prompt="$1"
  local default="${2:-}"
  local secret="${3:-false}"
  local value
  if [[ "$secret" == "true" ]]; then
    read -r -s -p "$prompt${default:+ [$default]}: " value || true
    echo ""
  else
    read -r -p "$prompt${default:+ [$default]}: " value || true
  fi
  echo "${value:-$default}"
}

check_app_root() {
  [[ -f "artisan" ]] || fail "artisan file not found. Run this script from the Laravel application root folder."
  [[ -f "composer.json" ]] || fail "composer.json not found. Run this script from the Laravel application root folder."
  [[ -d "public" ]] || fail "public folder not found. This does not look like a Laravel application root folder."
  info "Laravel application root confirmed."
}

check_requirements() {
  command_exists php || fail "PHP CLI is not installed or not available in PATH."
  command_exists composer || fail "Composer is not installed or not available in PATH."

  local php_version
  php_version=$(php -r 'echo PHP_VERSION;')
  php -r "exit(version_compare(PHP_VERSION, '$MIN_PHP_VERSION', '>=') ? 0 : 1);" \
    || fail "PHP $MIN_PHP_VERSION or higher is required. Detected PHP $php_version."
  info "PHP version OK: $php_version"

  if command_exists mysql; then
    info "MySQL client detected."
  else
    warn "MySQL client not detected. This is okay if your database already exists and Laravel can connect to it."
  fi

  if command_exists npm; then
    info "NPM detected. Frontend assets can be built if required."
  else
    warn "NPM not detected. The installer will skip frontend asset build."
  fi
}

set_permissions() {
  mkdir -p storage/framework/cache/data storage/framework/sessions storage/framework/views storage/logs bootstrap/cache
  chmod -R ug+rw storage bootstrap/cache || warn "Could not fully set permissions. You may need to run: chmod -R 775 storage bootstrap/cache"
  info "Storage and cache folders prepared."
}

copy_env() {
  if [[ ! -f ".env" ]]; then
    [[ -f ".env.example" ]] || fail ".env not found and .env.example not found."
    cp .env.example .env
    info ".env file created from .env.example."
  else
    info ".env file already exists."
  fi
}

set_env_key() {
  local key="$1"
  local value="$2"
  php -r '
    $file = ".env";
    $key = $argv[1];
    $value = $argv[2];
    $needsQuotes = preg_match("/[\s#\"\x27]/", $value);
    $escaped = str_replace(["\\", "\""], ["\\\\", "\\\""], $value);
    $line = $key . "=" . ($needsQuotes ? "\"" . $escaped . "\"" : $escaped);
    $contents = file_exists($file) ? file_get_contents($file) : "";
    if (preg_match("/^" . preg_quote($key, "/") . "=.*/m", $contents)) {
      $contents = preg_replace("/^" . preg_quote($key, "/") . "=.*/m", $line, $contents);
    } else {
      $contents = rtrim($contents) . PHP_EOL . $line . PHP_EOL;
    }
    file_put_contents($file, $contents);
  ' "$key" "$value"
}

configure_env_interactive() {
  echo ""
  echo -e "${BLUE}Application settings${NC}"
  local app_name app_url app_env app_debug timezone
  app_name=$(ask "Application name" "DPSVR")
  app_url=$(ask "Application URL, including https:// or http://" "https://your-domain.com")
  app_env=$(ask "Application environment" "production")
  app_debug=$(ask "Enable debug mode? Use false for live server" "false")
  timezone=$(ask "Application timezone" "Africa/Lagos")

  set_env_key "APP_NAME" "$app_name"
  set_env_key "APP_URL" "$app_url"
  set_env_key "APP_ENV" "$app_env"
  set_env_key "APP_DEBUG" "$app_debug"
  set_env_key "APP_TIMEZONE" "$timezone"
  set_env_key "LOG_CHANNEL" "stack"
  set_env_key "CACHE_STORE" "database"
  set_env_key "SESSION_DRIVER" "database"
  set_env_key "QUEUE_CONNECTION" "database"

  echo ""
  echo -e "${BLUE}Database settings${NC}"
  local db_connection db_host db_port db_database db_username db_password
  db_connection=$(ask "Database connection" "mysql")
  db_host=$(ask "Database host" "127.0.0.1")
  db_port=$(ask "Database port" "3306")
  db_database=$(ask "Database name" "dpsvr")
  db_username=$(ask "Database username" "dpsvr_user")
  db_password=$(ask "Database password" "" "true")

  set_env_key "DB_CONNECTION" "$db_connection"
  set_env_key "DB_HOST" "$db_host"
  set_env_key "DB_PORT" "$db_port"
  set_env_key "DB_DATABASE" "$db_database"
  set_env_key "DB_USERNAME" "$db_username"
  set_env_key "DB_PASSWORD" "$db_password"

  echo ""
  echo -e "${BLUE}Mail settings - optional. Leave defaults if not ready.${NC}"
  if confirm "Configure SMTP mail now?" "N"; then
    local mail_mailer mail_host mail_port mail_username mail_password mail_encryption mail_from_address mail_from_name
    mail_mailer=$(ask "MAIL_MAILER" "smtp")
    mail_host=$(ask "MAIL_HOST" "smtp.mailgun.org")
    mail_port=$(ask "MAIL_PORT" "587")
    mail_username=$(ask "MAIL_USERNAME" "")
    mail_password=$(ask "MAIL_PASSWORD" "" "true")
    mail_encryption=$(ask "MAIL_ENCRYPTION" "tls")
    mail_from_address=$(ask "MAIL_FROM_ADDRESS" "no-reply@your-domain.com")
    mail_from_name=$(ask "MAIL_FROM_NAME" "$app_name")

    set_env_key "MAIL_MAILER" "$mail_mailer"
    set_env_key "MAIL_HOST" "$mail_host"
    set_env_key "MAIL_PORT" "$mail_port"
    set_env_key "MAIL_USERNAME" "$mail_username"
    set_env_key "MAIL_PASSWORD" "$mail_password"
    set_env_key "MAIL_ENCRYPTION" "$mail_encryption"
    set_env_key "MAIL_FROM_ADDRESS" "$mail_from_address"
    set_env_key "MAIL_FROM_NAME" "$mail_from_name"
  fi

  info ".env configuration completed."
}

install_dependencies() {
  echo ""
  echo -e "${BLUE}Installing PHP dependencies${NC}"
  composer install --no-dev --prefer-dist --optimize-autoloader --no-interaction
  info "Composer dependencies installed."

  if [[ -f "package.json" ]] && command_exists npm; then
    if [[ -f "vite.config.js" || -f "vite.config.mjs" || -f "vite.config.ts" ]]; then
      echo ""
      echo -e "${BLUE}Building frontend assets${NC}"
      npm install
      npm run build
      info "Frontend assets built."
    else
      warn "package.json found but no Vite config file found. Skipping npm build."
    fi
  fi
}

run_laravel_setup() {
  echo ""
  echo -e "${BLUE}Running Laravel setup${NC}"
  php artisan key:generate --force
  php artisan optimize:clear

  if confirm "Run database migrations now?" "Y"; then
    php artisan migrate --force
    info "Database migrations completed."
  else
    warn "Database migrations skipped. Run later: php artisan migrate --force"
  fi

  if confirm "Seed default roles, permissions, fuel products and demo data?" "Y"; then
    php artisan db:seed --force
    info "Database seeding completed."
  else
    warn "Database seeding skipped. Run later: php artisan db:seed --force"
  fi

  php artisan storage:link || warn "Storage link may already exist or could not be created."

  php artisan config:cache
  php artisan route:cache || warn "Route cache failed. The application can still run; check route definitions if needed."
  php artisan view:cache
  info "Laravel optimization completed."
}

create_super_admin_optional() {
  echo ""
  if confirm "Create or reset a Super Administrator account now?" "Y"; then
    local admin_name admin_email admin_password
    admin_name=$(ask "Admin full name" "Super Admin")
    admin_email=$(ask "Admin email" "admin@dpsvr.local")
    admin_password=$(ask "Admin password" "ChangeMe123!" "true")

    php artisan tinker --execute="
      \$user = \App\Models\User::updateOrCreate(
        ['email' => '$admin_email'],
        ['name' => '$admin_name', 'password' => bcrypt('$admin_password'), 'status' => 'ACTIVE']
      );
      if (method_exists(\$user, 'assignRole')) { \$user->assignRole('Super Administrator'); }
      echo 'Super Administrator ready: ' . \$user->email . PHP_EOL;
    "
    info "Super Administrator account prepared."
  fi
}

print_completion_notes() {
  echo ""
  echo -e "${GREEN}============================================================${NC}"
  echo -e "${GREEN}Installation completed.${NC}"
  echo -e "${GREEN}============================================================${NC}"
  echo ""
  echo "IMPORTANT SERVER SETTINGS:"
  echo "1. Your domain/subdomain document root must point to this application's /public folder."
  echo "2. For Apache, allow .htaccess and mod_rewrite."
  echo "3. For Nginx, route all requests to public/index.php."
  echo "4. Add a cron job for Laravel scheduler:"
  echo "   * * * * * cd $(pwd) && php artisan schedule:run >> /dev/null 2>&1"
  echo "5. If queues are enabled, run a queue worker or configure Supervisor:"
  echo "   php artisan queue:work --tries=3"
  echo ""
  echo "Recommended next test:"
  echo "- Visit your APP_URL in the browser."
  echo "- Login using the Super Administrator account created above."
  echo ""
}

main() {
  print_header
  check_app_root
  check_requirements
  set_permissions
  copy_env

  if confirm "Configure .env interactively now?" "Y"; then
    configure_env_interactive
  else
    warn "Skipped .env configuration. Make sure .env is correct before continuing."
  fi

  install_dependencies
  set_permissions
  run_laravel_setup
  create_super_admin_optional
  print_completion_notes
}

main "$@"
