#!/bin/bash

setupWizardTerminal()
{
    isHeader "LibrePortal Setup Wizard"
    isNotice "Let's get your install configured. This only runs once."
    echo ""

    local install_name=$(generateInstallName)
    while true; do
        isNotice "Suggested Install Name: $install_name"
        isQuestion "Press Enter to accept, 'r' to roll a new one, or type your own : "
        read -p "" install_name_input
        if [[ -z "$install_name_input" ]]; then
            break
        elif [[ "$install_name_input" =~ ^[rR]$ ]]; then
            install_name=$(generateInstallName)
            continue
        elif [[ "$install_name_input" =~ ^[a-zA-Z0-9-]+$ ]]; then
            install_name="$install_name_input"
            break
        fi
        isNotice "Invalid input. Use letters, numbers, and hyphens only."
    done

    # Domains — optional, multi (CFG_DOMAIN_1..9). Empty input ends the loop.
    isHeader "Domains (optional)"
    isNotice "Add one or more domains pointed at this server."
    isNotice "Each domain unlocks https://app.<domain> routing via Traefik + a self-signed SSL cert."
    isNotice "Press Enter on a blank line to finish (or skip entirely for a local-only install)."
    echo ""

    local domains=()
    local domain_idx=1
    while [[ $domain_idx -le 9 ]]; do
        isQuestion "Domain $domain_idx (or blank to finish) : "
        read -p "" d
        [[ -z "$d" ]] && break
        if [[ ! "$d" =~ ^([a-zA-Z0-9]+(-[a-zA-Z0-9]+)*\.)+[a-zA-Z]{2,}$ ]]; then
            isNotice "Invalid domain — try again."
            continue
        fi
        local dns_result=$(setupCheckDomainPointsHere "$d")
        local matches=$(echo "$dns_result" | jq -r '.matches')
        local server_ip=$(echo "$dns_result" | jq -r '.server_ip')
        local domain_ip=$(echo "$dns_result" | jq -r '.domain_ip')
        if [[ "$matches" == "true" ]]; then
            isSuccessful "✓ '$d' resolves to this server ($server_ip)."
            domains+=("$d")
            ((domain_idx++))
        else
            isNotice "⚠ '$d' resolves to '$domain_ip', this server is '$server_ip'."
            isQuestion "Use it anyway? Traefik may not route this until DNS is fixed. (y/n) : "
            read -p "" use_anyway
            if [[ "$use_anyway" =~ ^[yY]$ ]]; then
                domains+=("$d")
                ((domain_idx++))
            fi
        fi
    done

    local detected_tz=""
    if command -v timedatectl >/dev/null 2>&1; then
        detected_tz=$(timedatectl show -p Timezone --value 2>/dev/null)
    fi
    if [[ -z "$detected_tz" && -r /etc/timezone ]]; then
        detected_tz=$(cat /etc/timezone 2>/dev/null | tr -d '[:space:]')
    fi

    local timezone=""
    local common_timezones=("Europe/London" "Europe/Paris" "Europe/Berlin" "America/New_York" "America/Chicago" "America/Los_Angeles" "America/Denver" "America/Phoenix" "Asia/Tokyo" "Australia/Sydney")
    while true; do
        if [[ -n "$detected_tz" ]]; then
            isNotice "Detected OS timezone: $detected_tz"
            isQuestion "Press Enter to use it, or type a number / 'c' to choose differently : "
            read -p "" tz_choice
            if [[ -z "$tz_choice" ]]; then
                timezone="$detected_tz"
                break
            fi
        else
            isNotice "Select a timezone:"
            for ((i=0; i<${#common_timezones[@]}; i++)); do
                isOption "$((i+1)). ${common_timezones[i]}"
            done
            isOption "c. Custom (enter manually)"
            isQuestion "Choice : "
            read -p "" tz_choice
        fi

        if [[ "$tz_choice" =~ ^[cC]$ ]]; then
            isQuestion "Custom timezone (e.g. Pacific/Auckland) : "
            read -p "" timezone
            [[ -n "$timezone" ]] && break
        elif [[ "$tz_choice" =~ ^[0-9]+$ && "$tz_choice" -ge 1 && "$tz_choice" -le "${#common_timezones[@]}" ]]; then
            timezone="${common_timezones[tz_choice-1]}"
            break
        else
            isNotice "Invalid selection."
        fi
    done
    isSuccessful "Timezone set to '$timezone'"

    isHeader "Recommended Apps"
    local apps=()
    local crowdsec_dashboard="false"
    isOption "  - traefik    (reverse proxy, handles LetsEncrypt SSL)"
    isOption "  - crowdsec   (host-installed intrusion prevention)"
    echo ""
    if [[ ${#domains[@]} -eq 0 ]]; then
        isNotice "No domains configured — Traefik has nothing to route. Skipping by default."
        isQuestion "Install Traefik anyway? (y/n) : "
        read -p "" want_traefik
        [[ "$want_traefik" =~ ^[yY]$ ]] && apps+=("traefik")
    else
        isQuestion "Install Traefik? (Y/n) : "
        read -p "" want_traefik
        [[ ! "$want_traefik" =~ ^[nN]$ ]] && apps+=("traefik")
    fi
    isQuestion "Install CrowdSec? (Y/n) : "
    read -p "" want_crowdsec
    if [[ ! "$want_crowdsec" =~ ^[nN]$ ]]; then
        apps+=("crowdsec")
        isQuestion "    └─ Install CrowdSec Management Console (Metabase web UI)? (Y/n) : "
        read -p "" want_console
        [[ ! "$want_console" =~ ^[nN]$ ]] && crowdsec_dashboard="true"
    fi

    isHeader "Optional Apps"
    isQuestion "Install Wireguard (VPN — secure remote access)? (y/N) : "
    read -p "" want_wireguard
    [[ "$want_wireguard" =~ ^[yY]$ ]] && apps+=("wireguard")

    # Traefik is the only app that needs an email — for LetsEncrypt cert
    # registration. We collect it now (before the install task fires) so the
    # Traefik installer doesn't have to prompt mid-task.
    local traefik_email=""
    if [[ " ${apps[*]} " == *" traefik "* ]]; then
        while true; do
            isQuestion "LetsEncrypt email for Traefik (cert-expiry notices) : "
            read -p "" traefik_email
            emailValidation "$traefik_email"
            [[ $? -eq 0 ]] && break
            isNotice "Please provide a valid email address."
        done
    fi

    isHeader "Confirm"
    isNotice "Install Name  : $install_name"
    isNotice "Timezone      : $timezone"
    if [[ ${#domains[@]} -gt 0 ]]; then
        isNotice "Domains       : ${domains[*]}"
    else
        isNotice "Domains       : (none — local install)"
    fi
    isNotice "Apps          : ${apps[*]:-none}"
    [[ " ${apps[*]} " == *" crowdsec "* ]] && isNotice "CrowdSec UI   : $crowdsec_dashboard"
    [[ -n "$traefik_email" ]] && isNotice "Traefik Email : $traefik_email"
    echo ""
    isQuestion "Apply these settings? (Y/n) : "
    read -p "" confirm
    if [[ "$confirm" =~ ^[nN]$ ]]; then
        isNotice "Setup cancelled. You can re-run from the menu."
        return 1
    fi

    local app_options="{}"
    if [[ " ${apps[*]} " == *" crowdsec "* ]]; then
        app_options=$(jq -n --argjson d "$crowdsec_dashboard" '{crowdsec:{dashboard:$d}}')
    fi

    local payload=$(jq -n \
        --arg n "$install_name" \
        --arg t "$timezone" \
        --arg te "$traefik_email" \
        --argjson a "$(printf '%s\n' "${apps[@]}" | jq -R . | jq -s .)" \
        --argjson dom "$(printf '%s\n' "${domains[@]}" | jq -R . | jq -s 'map(select(length > 0))')" \
        --argjson opts "$app_options" \
        '{install_name:$n, timezone:$t, domains:$dom, apps:$a, appOptions:$opts, traefik_email:$te}')

    local b64=$(echo -n "$payload" | base64 -w 0)
    setupApply "$b64"
}

checkConfigFirstInstall()
{
    if isSetupWizardComplete; then
        return 0
    fi
    if [[ "$unattended_setup" == "true" ]]; then
        return 0
    fi
    setupWizardTerminal
}
