#!/usr/bin/env bash
set -euo pipefail
APP=opencode

MUTED='\033[0;2m'
RED='\033[0;31m'
ORANGE='\033[38;5;214m'
NC='\033[0m' # No Color

usage() {
    cat <<EOF
OpenCode Installer

Usage: install [options]

Options:
    -h, --help              Display this help message
    -v, --version <version> Install a specific version (defaults to latest)
    -b, --binary <path>     Install from a local binary instead of downloading
        --cdn <template>    Download through a CDN/proxy template. Can be used multiple times.
                            Supports {url}, {version}, and {filename} placeholders.
        --no-modify-path    Don't modify shell config files (.zshrc, .bashrc, etc.)

Environment:
    VERSION                  Version to install when --version is not provided
    OPENCODE_CDN_TEMPLATES   Space-separated CDN/proxy templates. Overrides defaults.
    OPENCODE_PROXY_BASE      GitHub API/download proxy base. Defaults to https://frp.890805.xyz
    OPENCODE_PROXY_TOKEN     Proxy token for OPENCODE_PROXY_BASE.

Examples:
    curl -fsSL https://opencode.ai/install | bash
    curl -fsSL https://opencode.ai/install | bash -s -- --version 1.0.180
    ./install --version 1.0.180
    ./install --version 1.0.180 --cdn 'https://my-proxy.example.com/{url}'
    OPENCODE_CDN_TEMPLATES='https://a.example.com/{url} https://b.example.com/{url}' ./install --version 1.0.180
    ./install --binary /path/to/opencode
EOF
}

requested_version=${VERSION:-}
no_modify_path=false
binary_path=""
cdn_templates=()
proxy_base=${OPENCODE_PROXY_BASE:-https://frp.890805.xyz}
proxy_base="${proxy_base%/}"
proxy_token=${OPENCODE_PROXY_TOKEN:-rYWVZ33Wv3rNJaelCHO8VezQpX3p253B}

while [[ $# -gt 0 ]]; do
    case "$1" in
        -h|--help)
            usage
            exit 0
            ;;
        -v|--version)
            if [[ -n "${2:-}" ]]; then
                requested_version="$2"
                shift 2
            else
                echo -e "${RED}Error: --version requires a version argument${NC}"
                exit 1
            fi
            ;;
        -b|--binary)
            if [[ -n "${2:-}" ]]; then
                binary_path="$2"
                shift 2
            else
                echo -e "${RED}Error: --binary requires a path argument${NC}"
                exit 1
            fi
            ;;
        --cdn)
            if [[ -n "${2:-}" ]]; then
                cdn_templates+=("$2")
                shift 2
            else
                echo -e "${RED}Error: --cdn requires a template argument${NC}"
                exit 1
            fi
            ;;
        --no-modify-path)
            no_modify_path=true
            shift
            ;;
        *)
            echo -e "${ORANGE}Warning: Unknown option '$1'${NC}" >&2
            shift
            ;;
    esac
done

INSTALL_DIR=$HOME/.opencode/bin
mkdir -p "$INSTALL_DIR"

# If --binary is provided, skip all download/detection logic
if [ -n "$binary_path" ]; then
    if [ ! -f "$binary_path" ]; then
        echo -e "${RED}Error: Binary not found at ${binary_path}${NC}"
        exit 1
    fi
    specific_version="local"
else
    raw_os=$(uname -s)
    os=$(echo "$raw_os" | tr '[:upper:]' '[:lower:]')
    case "$raw_os" in
      Darwin*) os="darwin" ;;
      Linux*) os="linux" ;;
      MINGW*|MSYS*|CYGWIN*) os="windows" ;;
    esac

    arch=$(uname -m)
    if [[ "$arch" == "aarch64" ]]; then
      arch="arm64"
    fi
    if [[ "$arch" == "x86_64" ]]; then
      arch="x64"
    fi

    if [ "$os" = "darwin" ] && [ "$arch" = "x64" ]; then
      rosetta_flag=$(sysctl -n sysctl.proc_translated 2>/dev/null || echo 0)
      if [ "$rosetta_flag" = "1" ]; then
        arch="arm64"
      fi
    fi

    combo="$os-$arch"
    case "$combo" in
      linux-x64|linux-arm64|darwin-x64|darwin-arm64|windows-x64)
        ;;
      *)
        echo -e "${RED}Unsupported OS/Arch: $os/$arch${NC}"
        exit 1
        ;;
    esac

    archive_ext=".zip"
    if [ "$os" = "linux" ]; then
      archive_ext=".tar.gz"
    fi

    is_musl=false
    if [ "$os" = "linux" ]; then
      if [ -f /etc/alpine-release ]; then
        is_musl=true
      fi

      if command -v ldd >/dev/null 2>&1; then
        if ldd --version 2>&1 | grep -qi musl; then
          is_musl=true
        fi
      fi
    fi

    needs_baseline=false
    if [ "$arch" = "x64" ]; then
      if [ "$os" = "linux" ]; then
        if ! grep -qwi avx2 /proc/cpuinfo 2>/dev/null; then
          needs_baseline=true
        fi
      fi

      if [ "$os" = "darwin" ]; then
        avx2=$(sysctl -n hw.optional.avx2_0 2>/dev/null || echo 0)
        if [ "$avx2" != "1" ]; then
          needs_baseline=true
        fi
      fi

      if [ "$os" = "windows" ]; then
        ps="(Add-Type -MemberDefinition \"[DllImport(\"\"kernel32.dll\"\")] public static extern bool IsProcessorFeaturePresent(int ProcessorFeature);\" -Name Kernel32 -Namespace Win32 -PassThru)::IsProcessorFeaturePresent(40)"
        out=""
        if command -v powershell.exe >/dev/null 2>&1; then
          out=$(powershell.exe -NoProfile -NonInteractive -Command "$ps" 2>/dev/null || true)
        elif command -v pwsh >/dev/null 2>&1; then
          out=$(pwsh -NoProfile -NonInteractive -Command "$ps" 2>/dev/null || true)
        fi
        out=$(echo "$out" | tr -d '\r' | tr '[:upper:]' '[:lower:]' | tr -d '[:space:]')
        if [ "$out" != "true" ] && [ "$out" != "1" ]; then
          needs_baseline=true
        fi
      fi
    fi

    target="$os-$arch"
    if [ "$needs_baseline" = "true" ]; then
      target="$target-baseline"
    fi
    if [ "$is_musl" = "true" ]; then
      target="$target-musl"
    fi

    filename="$APP-$target$archive_ext"

    if [ "$os" = "linux" ]; then
        if ! command -v tar >/dev/null 2>&1; then
             echo -e "${RED}Error: 'tar' is required but not installed.${NC}"
             exit 1
        fi
    else
        if ! command -v unzip >/dev/null 2>&1; then
            echo -e "${RED}Error: 'unzip' is required but not installed.${NC}"
            exit 1
        fi
    fi

    if [ -z "$requested_version" ]; then
        latest_api_url="$proxy_base/https://api.github.com/repos/anomalyco/opencode/releases/latest"
        echo -e "${MUTED}Fetching latest opencode version via ${NC}$proxy_base${MUTED}...${NC}"

        if ! latest_response=$(curl -fsSL -H "X-Proxy-Token: $proxy_token" "$latest_api_url"); then
            echo -e "${RED}Failed to fetch version information${NC}"
            echo -e "${MUTED}You can specify a version manually: ./install --version 1.0.180${NC}"
            exit 1
        fi

        requested_version=$(echo "$latest_response" | sed -n 's/.*"tag_name": *"v\([^"]*\)".*/\1/p')

        if [ -z "$requested_version" ]; then
            echo -e "${RED}Failed to parse latest version information${NC}"
            exit 1
        fi
    else
        # Strip leading 'v' if present
        requested_version="${requested_version#v}"
    fi

    specific_version=$requested_version
    source_url="https://github.com/anomalyco/opencode/releases/download/v${requested_version}/$filename"

    if [ "${#cdn_templates[@]}" -eq 0 ]; then
        if [ -n "${OPENCODE_CDN_TEMPLATES:-}" ]; then
            read -r -a cdn_templates <<< "$OPENCODE_CDN_TEMPLATES"
        else
            cdn_templates=(
                "https://gh-proxy.com/{url}"
                "https://githubproxy.cc/{url}"
                "https://ghproxy.vip/{url}"
                "https://gh-fast.com/{url}"
                "$proxy_base/{url}"
                "{url}"
            )
        fi
    fi
fi

print_message() {
    local level=$1
    local message=$2
    local color=""

    case $level in
        info) color="${NC}" ;;
        warning) color="${NC}" ;;
        error) color="${RED}" ;;
    esac

    echo -e "${color}${message}${NC}"
}

check_version() {
    if command -v opencode >/dev/null 2>&1; then
        opencode_path=$(which opencode)

        ## Check the installed version
        installed_version=$(opencode --version 2>/dev/null || echo "")

        if [[ "$installed_version" != "$specific_version" ]]; then
            print_message info "${MUTED}Installed version: ${NC}$installed_version."
        else
            print_message info "${MUTED}Version ${NC}$specific_version${MUTED} already installed"
            exit 0
        fi
    fi
}

unbuffered_sed() {
    if echo | sed -u -e "" >/dev/null 2>&1; then
        sed -nu "$@"
    elif echo | sed -l -e "" >/dev/null 2>&1; then
        sed -nl "$@"
    else
        local pad="$(printf "\n%512s" "")"
        sed -ne "s/$/\\${pad}/" "$@"
    fi
}

print_progress() {
    local bytes="$1"
    local length="$2"
    [ "$length" -gt 0 ] || return 0

    local width=50
    local percent=$(( bytes * 100 / length ))
    [ "$percent" -gt 100 ] && percent=100
    local on=$(( percent * width / 100 ))
    local off=$(( width - on ))

    local filled=$(printf "%*s" "$on" "")
    filled=${filled// /■}
    local empty=$(printf "%*s" "$off" "")
    empty=${empty// /･}

    printf "\r${ORANGE}%s%s %3d%%${NC}" "$filled" "$empty" "$percent" >&4
}

download_with_progress() {
    local url="$1"
    local output="$2"

    if [ -t 2 ]; then
        exec 4>&2
    else
        exec 4>/dev/null
    fi

    local tmp_dir=${TMPDIR:-/tmp}
    local basename="${tmp_dir}/opencode_install_$$"
    local tracefile="${basename}.trace"

    rm -f "$tracefile"
    mkfifo "$tracefile"

    # Hide cursor
    printf "\033[?25l" >&4

    trap "trap - RETURN; rm -f \"$tracefile\"; printf '\033[?25h' >&4; exec 4>&-" RETURN

    (
        if [[ "$url" == "$proxy_base/"* ]] && [ -n "$proxy_token" ]; then
            curl --fail --trace-ascii "$tracefile" -s -L -H "X-Proxy-Token: $proxy_token" -o "$output" "$url"
        else
            curl --fail --trace-ascii "$tracefile" -s -L -o "$output" "$url"
        fi
    ) &
    local curl_pid=$!

    unbuffered_sed \
        -e 'y/ACDEGHLNORTV/acdeghlnortv/' \
        -e '/^0000: content-length:/p' \
        -e '/^<= recv data/p' \
        "$tracefile" | \
    {
        local length=0
        local bytes=0

        while IFS=" " read -r -a line; do
            [ "${#line[@]}" -lt 2 ] && continue
            local tag="${line[0]} ${line[1]}"

            if [ "$tag" = "0000: content-length:" ]; then
                length="${line[2]}"
                length=$(echo "$length" | tr -d '\r')
                bytes=0
            elif [ "$tag" = "<= recv" ]; then
                local size="${line[3]}"
                bytes=$(( bytes + size ))
                if [ "$length" -gt 0 ]; then
                    print_progress "$bytes" "$length"
                fi
            fi
        done
    }

    wait $curl_pid
    local ret=$?
    echo "" >&4
    return $ret
}

render_download_url() {
    local template="$1"
    local rendered="$template"
    local url_placeholder="{url}"
    local version_placeholder="{version}"
    local filename_placeholder="{filename}"

    rendered="${rendered//$url_placeholder/$source_url}"
    rendered="${rendered//$version_placeholder/$specific_version}"
    rendered="${rendered//$filename_placeholder/$filename}"

    echo "$rendered"
}

download_archive() {
    local output="$1"
    local attempted_urls=()
    local last_status=0
    local download_url

    for template in "${cdn_templates[@]}"; do
        download_url=$(render_download_url "$template")
        attempted_urls+=("$download_url")

        print_message info "${MUTED}Trying download source:${NC} $download_url"

        if [[ "$os" == "windows" ]] || ! [ -t 2 ]; then
            if [[ "$download_url" == "$proxy_base/"* ]] && [ -n "$proxy_token" ]; then
                if curl -fL -# -H "X-Proxy-Token: $proxy_token" -o "$output" "$download_url"; then
                    last_status=0
                else
                    last_status=$?
                fi
            else
                if curl -fL -# -o "$output" "$download_url"; then
                    last_status=0
                else
                    last_status=$?
                fi
            fi
        else
            if download_with_progress "$download_url" "$output"; then
                last_status=0
            else
                last_status=$?
            fi
        fi

        if [ "$last_status" -eq 0 ]; then
            return 0
        fi

        print_message warning "${ORANGE}Download failed with exit code $last_status, trying next source.${NC}"
        rm -f "$output"
    done

    print_message error "${RED}Error: Failed to download opencode after trying all sources.${NC}"
    print_message error "${RED}Last curl exit code: $last_status${NC}"
    print_message info "${MUTED}Attempted URLs:${NC}"
    for download_url in "${attempted_urls[@]}"; do
        print_message info "  $download_url"
    done
    return 1
}

download_and_install() {
    print_message info "\n${MUTED}Installing ${NC}opencode ${MUTED}version: ${NC}$specific_version"
    local tmp_dir="${TMPDIR:-/tmp}/opencode_install_$$"
    mkdir -p "$tmp_dir"

    download_archive "$tmp_dir/$filename"

    if [ "$os" = "linux" ]; then
        tar -xzf "$tmp_dir/$filename" -C "$tmp_dir"
    else
        unzip -q "$tmp_dir/$filename" -d "$tmp_dir"
    fi

    mv "$tmp_dir/opencode" "$INSTALL_DIR"
    chmod 755 "${INSTALL_DIR}/opencode"
    rm -rf "$tmp_dir"
}

install_from_binary() {
    print_message info "\n${MUTED}Installing ${NC}opencode ${MUTED}from: ${NC}$binary_path"
    cp "$binary_path" "${INSTALL_DIR}/opencode"
    chmod 755 "${INSTALL_DIR}/opencode"
}

if [ -n "$binary_path" ]; then
    install_from_binary
else
    check_version
    download_and_install
fi


add_to_path() {
    local config_file=$1
    local command=$2

    if grep -Fxq "$command" "$config_file"; then
        print_message info "Command already exists in $config_file, skipping write."
    elif [[ -w $config_file ]]; then
        echo -e "\n# opencode" >> "$config_file"
        echo "$command" >> "$config_file"
        print_message info "${MUTED}Successfully added ${NC}opencode ${MUTED}to \$PATH in ${NC}$config_file"
    else
        print_message warning "Manually add the directory to $config_file (or similar):"
        print_message info "  $command"
    fi
}

XDG_CONFIG_HOME=${XDG_CONFIG_HOME:-$HOME/.config}

current_shell=$(basename "$SHELL")
case $current_shell in
    fish)
        config_files="$HOME/.config/fish/config.fish"
    ;;
    zsh)
        config_files="${ZDOTDIR:-$HOME}/.zshrc ${ZDOTDIR:-$HOME}/.zshenv $XDG_CONFIG_HOME/zsh/.zshrc $XDG_CONFIG_HOME/zsh/.zshenv"
    ;;
    bash)
        config_files="$HOME/.bashrc $HOME/.bash_profile $HOME/.profile $XDG_CONFIG_HOME/bash/.bashrc $XDG_CONFIG_HOME/bash/.bash_profile"
    ;;
    ash)
        config_files="$HOME/.ashrc $HOME/.profile /etc/profile"
    ;;
    sh)
        config_files="$HOME/.ashrc $HOME/.profile /etc/profile"
    ;;
    *)
        # Default case if none of the above matches
        config_files="$HOME/.bashrc $HOME/.bash_profile $XDG_CONFIG_HOME/bash/.bashrc $XDG_CONFIG_HOME/bash/.bash_profile"
    ;;
esac

if [[ "$no_modify_path" != "true" ]]; then
    config_file=""
    for file in $config_files; do
        if [[ -f $file ]]; then
            config_file=$file
            break
        fi
    done

    if [[ -z $config_file ]]; then
        print_message warning "No config file found for $current_shell. You may need to manually add to PATH:"
        print_message info "  export PATH=$INSTALL_DIR:\$PATH"
    elif [[ ":$PATH:" != *":$INSTALL_DIR:"* ]]; then
        case $current_shell in
            fish)
                add_to_path "$config_file" "fish_add_path $INSTALL_DIR"
            ;;
            zsh)
                add_to_path "$config_file" "export PATH=$INSTALL_DIR:\$PATH"
            ;;
            bash)
                add_to_path "$config_file" "export PATH=$INSTALL_DIR:\$PATH"
            ;;
            ash)
                add_to_path "$config_file" "export PATH=$INSTALL_DIR:\$PATH"
            ;;
            sh)
                add_to_path "$config_file" "export PATH=$INSTALL_DIR:\$PATH"
            ;;
            *)
                export PATH=$INSTALL_DIR:$PATH
                print_message warning "Manually add the directory to $config_file (or similar):"
                print_message info "  export PATH=$INSTALL_DIR:\$PATH"
            ;;
        esac
    fi
fi

if [ -n "${GITHUB_ACTIONS-}" ] && [ "${GITHUB_ACTIONS}" == "true" ]; then
    echo "$INSTALL_DIR" >> $GITHUB_PATH
    print_message info "Added $INSTALL_DIR to \$GITHUB_PATH"
fi

echo -e ""
echo -e "${MUTED}                    ${NC}             ▄     "
echo -e "${MUTED}█▀▀█ █▀▀█ █▀▀█ █▀▀▄ ${NC}█▀▀▀ █▀▀█ █▀▀█ █▀▀█"
echo -e "${MUTED}█░░█ █░░█ █▀▀▀ █░░█ ${NC}█░░░ █░░█ █░░█ █▀▀▀"
echo -e "${MUTED}▀▀▀▀ █▀▀▀ ▀▀▀▀ ▀  ▀ ${NC}▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀"
echo -e ""
echo -e ""
echo -e "${MUTED}OpenCode includes free models, to start:${NC}"
echo -e ""
echo -e "cd <project>  ${MUTED}# Open directory${NC}"
echo -e "opencode      ${MUTED}# Run command${NC}"
echo -e ""
echo -e "${MUTED}For more information visit ${NC}https://opencode.ai/docs"
echo -e ""
echo -e ""
