#!/usr/bin/env bash

################################################################################
# syntaxis One-Line Installer
#
# Usage:
#   curl -sSL https://raw.githubusercontent.com/syntaxis/main/install.sh | bash
#   curl -sSL https://raw.githubusercontent.com/syntaxis/main/install.sh | bash -s -- --help
#
# Options:
#   --help                 Show this help message
#   --version TAG          Install specific version/tag
#   --prefix DIR           Custom installation directory
#   --skip-deps            Skip dependency installation
#   --no-verify            Skip test verification (faster, not recommended)
#   --unattended           Non-interactive mode
#   --keep-build           Keep build artifacts
#   --config-only          Only deploy configurations (skip build)
#   --dry-run              Show what would be installed
#
# Environment Variables:
#   WORKSPACE_INSTALL_DIR  Installation directory (default: ~/.local/share/syntaxis)
#   WORKSPACE_NO_COLOR     Disable colored output
#   WORKSPACE_SKIP_TESTS   Skip test verification
#   CARGO_HOME             Cargo installation directory
#
################################################################################

set -euo pipefail

# Color codes
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# Configuration
INSTALLER_VERSION="1.0.0"
PROJECT_REPO="https://github.com/syntaxis.git"
INSTALL_DIR="${WORKSPACE_INSTALL_DIR:-$HOME/.local/share/syntaxis}"
LOG_FILE="$HOME/.syntaxis/install.log"
MANIFEST_DIR="$HOME/.syntaxis"
CONFIG_DIR="$HOME/.config/syntaxis"
DATA_DIR="$HOME/.local/share/syntaxis"

# Script state
STEP=0
TOTAL_STEPS=8
DRY_RUN=false
SKIP_DEPS=false
NO_VERIFY=false
UNATTENDED=false
KEEP_BUILD=false
CONFIG_ONLY=false
VERSION_TAG="main"
CLEANUP_ON_ERROR=true

# Initialize log file
mkdir -p "$MANIFEST_DIR"
: > "$LOG_FILE"

################################################################################
# Utility Functions
################################################################################

log() {
  local msg="$*"
  echo -e "[$(date +'%Y-%m-%d %H:%M:%S')] $msg" | tee -a "$LOG_FILE"
}

log_error() {
  local msg="$*"
  echo -e "${RED}[ERROR]${NC} $msg" | tee -a "$LOG_FILE" >&2
}

log_success() {
  local msg="$*"
  echo -e "${GREEN}✅${NC} $msg" | tee -a "$LOG_FILE"
}

log_info() {
  local msg="$*"
  echo -e "${BLUE}ℹ️${NC}  $msg" | tee -a "$LOG_FILE"
}

log_warn() {
  local msg="$*"
  echo -e "${YELLOW}⚠️${NC}  $msg" | tee -a "$LOG_FILE"
}

step() {
  STEP=$((STEP + 1))
  echo ""
  echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
  echo -e "${BLUE}[$STEP/$TOTAL_STEPS]${NC} $*"
  echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
}

check_command() {
  local cmd="$1"
  if command -v "$cmd" &> /dev/null; then
    return 0
  else
    return 1
  fi
}

prompt_yes_no() {
  local question="$1"
  local default="${2:-y}"

  if [[ "$UNATTENDED" == "true" ]]; then
    return 0 # Default to yes in unattended mode
  fi

  local prompt="$question (y/n) [$default]: "
  local response
  read -p "$prompt" response
  response="${response:-$default}"

  if [[ "$response" =~ ^[Yy] ]]; then
    return 0
  else
    return 1
  fi
}

detect_os() {
  case "$(uname -s)" in
    Darwin*)  echo "macos" ;;
    Linux*)   echo "linux" ;;
    *)        echo "unknown" ;;
  esac
}

detect_arch() {
  case "$(uname -m)" in
    x86_64)   echo "x86_64" ;;
    aarch64)  echo "aarch64" ;;
    arm64)    echo "aarch64" ;; # macOS Apple Silicon
    *)        echo "unknown" ;;
  esac
}

detect_linux_distro() {
  if [[ -f /etc/os-release ]]; then
    . /etc/os-release
    echo "$ID"
  else
    echo "unknown"
  fi
}

show_help() {
  cat << 'EOF'
syntaxis One-Line Installer

USAGE:
  curl -sSL https://raw.githubusercontent.com/syntaxis/main/install.sh | bash
  bash install.sh [OPTIONS]

OPTIONS:
  -h, --help              Show this help message
  -v, --version TAG       Install specific version/tag (default: main)
  --prefix DIR            Custom installation directory
  --skip-deps             Skip dependency installation (assume already installed)
  --no-verify             Skip test verification (faster, not recommended)
  --unattended            Non-interactive mode (use all defaults)
  --keep-build            Keep build artifacts (default: cleanup)
  --config-only           Only deploy configurations (skip build)
  --dry-run               Show what would be installed

ENVIRONMENT VARIABLES:
  WORKSPACE_INSTALL_DIR   Installation directory
  WORKSPACE_NO_COLOR      Disable colored output
  WORKSPACE_SKIP_TESTS    Skip test verification
  CARGO_HOME              Cargo installation directory

EXAMPLES:
  # Standard installation
  bash install.sh

  # Unattended installation with custom prefix
  bash install.sh --unattended --prefix /opt/workspace

  # Only deploy configurations (binaries already installed)
  bash install.sh --config-only

  # See what would be installed without making changes
  bash install.sh --dry-run

For more information, visit: https://github.com/syntaxis
EOF
}

rollback_on_error() {
  if [[ "$DRY_RUN" == "true" ]] || [[ "$CLEANUP_ON_ERROR" != "true" ]]; then
    return
  fi

  log_warn "Rolling back installation..."

  # Remove partially installed binaries
  rm -f "$HOME/.cargo/bin/workspace"* 2>/dev/null || true

  # Note: Don't remove installation directory as it might be user repo
  log_warn "Installation failed. See $LOG_FILE for details."
}

trap rollback_on_error ERR

################################################################################
# Phase 1: Pre-Flight Checks
################################################################################

preflight_checks() {
  step "Pre-Flight Checks"

  local os=$(detect_os)
  local arch=$(detect_arch)

  log "Detected OS: $os ($arch)"

  if [[ "$os" == "unknown" ]] || [[ "$arch" == "unknown" ]]; then
    log_error "Unsupported OS or architecture"
    return 1
  fi

  # Check basic tools
  local missing_tools=()

  for tool in git curl; do
    if ! check_command "$tool"; then
      missing_tools+=("$tool")
    fi
  done

  if [[ ${#missing_tools[@]} -gt 0 ]]; then
    log_error "Missing required tools: ${missing_tools[*]}"
    log "Please install: ${missing_tools[*]}"

    if [[ "$os" == "macos" ]]; then
      log "  brew install ${missing_tools[*]}"
    elif [[ "$os" == "linux" ]]; then
      local distro=$(detect_linux_distro)
      case "$distro" in
        ubuntu|debian)
          log "  sudo apt-get update && sudo apt-get install -y ${missing_tools[*]}"
          ;;
        fedora|rhel)
          log "  sudo dnf install -y ${missing_tools[*]}"
          ;;
        arch)
          log "  sudo pacman -S --noconfirm ${missing_tools[*]}"
          ;;
      esac
    fi
    return 1
  fi

  log_success "Pre-flight checks passed"
}

################################################################################
# Phase 2: Install Core Dependencies
################################################################################

install_rust() {
  if check_command "rustc"; then
    local rust_version=$(rustc --version | awk '{print $2}')
    log_success "Rust already installed: $rust_version"
    return 0
  fi

  log_info "Installing Rust toolchain..."

  if [[ "$DRY_RUN" == "true" ]]; then
    log "[DRY RUN] Would install Rust via: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs"
    return 0
  fi

  curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain 1.75 2>&1 | tee -a "$LOG_FILE"

  # Source cargo environment
  if [[ -f "$HOME/.cargo/env" ]]; then
    # shellcheck disable=SC1090
    source "$HOME/.cargo/env"
  fi

  if ! check_command "rustc"; then
    log_error "Rust installation failed"
    return 1
  fi

  log_success "Rust installed: $(rustc --version)"
}

install_nushell() {
  if check_command "nu"; then
    local nu_version=$(nu --version 2>&1 | head -1)
    log_success "NuShell already installed: $nu_version"
    return 0
  fi

  log_info "Installing NuShell..."

  if [[ "$DRY_RUN" == "true" ]]; then
    log "[DRY RUN] Would install NuShell via: cargo install nu"
    return 0
  fi

  # Try system package manager first
  local os=$(detect_os)

  if [[ "$os" == "macos" ]] && check_command "brew"; then
    log_info "Installing NuShell via Homebrew..."
    brew install nushell 2>&1 | tee -a "$LOG_FILE" || true
  fi

  # Fallback to cargo
  if ! check_command "nu"; then
    log_info "Installing NuShell via cargo..."
    cargo install nu --locked 2>&1 | tee -a "$LOG_FILE"
  fi

  if ! check_command "nu"; then
    log_error "NuShell installation failed"
    return 1
  fi

  log_success "NuShell installed: $(nu --version 2>&1 | head -1)"
}

install_just() {
  if check_command "just"; then
    local just_version=$(just --version)
    log_success "Just already installed: $just_version"
    return 0
  fi

  log_info "Installing Just task runner..."

  if [[ "$DRY_RUN" == "true" ]]; then
    log "[DRY RUN] Would install Just via: cargo install just"
    return 0
  fi

  cargo install just 2>&1 | tee -a "$LOG_FILE"

  if ! check_command "just"; then
    log_error "Just installation failed"
    return 1
  fi

  log_success "Just installed: $(just --version)"
}

install_system_deps() {
  local os=$(detect_os)

  log_info "Checking system dependencies..."

  case "$os" in
    macos)
      if ! check_command "cc"; then
        log_info "Installing Xcode Command Line Tools..."
        if [[ "$DRY_RUN" != "true" ]]; then
          xcode-select --install 2>&1 | tee -a "$LOG_FILE" || true
          # Wait for installation
          sudo xcode-select --switch /Library/Developer/CommandLineTools 2>/dev/null || true
        fi
      fi
      log_success "System dependencies ready"
      ;;

    linux)
      local distro=$(detect_linux_distro)
      local deps=()

      # Check for required tools
      check_command "gcc" || deps+=("gcc")
      check_command "make" || deps+=("make")
      check_command "pkg-config" || deps+=("pkg-config")

      # Check for sqlite development headers
      if ! pkg-config --exists sqlite3 2>/dev/null; then
        case "$distro" in
          ubuntu|debian)  deps+=("libsqlite3-dev") ;;
          fedora|rhel)    deps+=("sqlite-devel") ;;
          arch)           deps+=("sqlite") ;;
        esac
      fi

      if [[ ${#deps[@]} -gt 0 ]]; then
        log_info "Installing dependencies: ${deps[*]}"

        if [[ "$DRY_RUN" != "true" ]]; then
          case "$distro" in
            ubuntu|debian)
              sudo apt-get update && sudo apt-get install -y build-essential pkg-config libsqlite3-dev 2>&1 | tee -a "$LOG_FILE"
              ;;
            fedora|rhel)
              sudo dnf install -y gcc gcc-c++ make pkg-config sqlite-devel 2>&1 | tee -a "$LOG_FILE"
              ;;
            arch)
              sudo pacman -S --noconfirm base-devel pkg-config sqlite 2>&1 | tee -a "$LOG_FILE"
              ;;
            *)
              log_warn "Unknown Linux distribution. Install build essentials manually."
              ;;
          esac
        fi
      fi

      log_success "System dependencies ready"
      ;;
  esac
}

install_dependencies() {
  if [[ "$SKIP_DEPS" == "true" ]]; then
    log_warn "Skipping dependency installation (--skip-deps)"
    return 0
  fi

  step "Install Core Dependencies"

  install_rust
  install_nushell
  install_just
  install_system_deps

  log_success "All dependencies installed"
}

################################################################################
# Phase 3: Clone/Verify Repository
################################################################################

clone_or_verify_repo() {
  step "Clone/Verify Repository"

  # Check if already in a git repository
  if git rev-parse --git-dir &> /dev/null; then
    log_success "Already in a git repository"
    INSTALL_DIR="$(pwd)"
    cd "$INSTALL_DIR"
  else
    log_info "Cloning syntaxis repository..."

    if [[ "$DRY_RUN" == "true" ]]; then
      log "[DRY RUN] Would clone: $PROJECT_REPO to $INSTALL_DIR"
      return 0
    fi

    if [[ -d "$INSTALL_DIR" ]]; then
      if [[ -d "$INSTALL_DIR/.git" ]]; then
        log_info "Repository already exists, updating..."
        cd "$INSTALL_DIR"
        git pull origin "$VERSION_TAG" 2>&1 | tee -a "$LOG_FILE"
      else
        log_error "Directory exists but is not a git repository: $INSTALL_DIR"
        return 1
      fi
    else
      mkdir -p "$(dirname "$INSTALL_DIR")"
      git clone -b "$VERSION_TAG" "$PROJECT_REPO" "$INSTALL_DIR" 2>&1 | tee -a "$LOG_FILE"
      cd "$INSTALL_DIR"
    fi
  fi

  # Verify repository structure
  local required_files=("Cargo.toml" "workspace-manager/Cargo.toml" "Justfile")
  for file in "${required_files[@]}"; do
    if [[ ! -f "$file" ]]; then
      log_error "Missing required file: $file"
      return 1
    fi
  done

  log_success "Repository verified: $INSTALL_DIR"
}

################################################################################
# Phase 4: Build Workspace
################################################################################

build_workspace() {
  if [[ "$CONFIG_ONLY" == "true" ]]; then
    log_warn "Skipping build (--config-only)"
    return 0
  fi

  step "Build Workspace"

  log_info "Building workspace binaries (this may take 10-20 minutes)..."

  if [[ "$DRY_RUN" == "true" ]]; then
    log "[DRY RUN] Would run: cargo build --release --workspace (excluding workspace-api, workspace-vapora)"
    return 0
  fi

  # Build release binaries
  RUST_BACKTRACE=1 cargo build --release --workspace \
    --exclude workspace-api \
    --exclude workspace-vapora \
    2>&1 | tee -a "$LOG_FILE"

  if [[ $? -ne 0 ]]; then
    log_error "Build failed"
    return 1
  fi

  # Run tests
  if [[ "$NO_VERIFY" != "true" ]]; then
    log_info "Running tests..."
    cargo test --release --workspace --lib \
      --exclude workspace-api \
      --exclude workspace-vapora \
      2>&1 | tee -a "$LOG_FILE"

    if [[ $? -ne 0 ]]; then
      log_warn "Some tests failed, continuing anyway..."
    fi
  fi

  log_success "Build completed"
}

################################################################################
# Phase 5: Install Binaries
################################################################################

install_binaries() {
  if [[ "$CONFIG_ONLY" == "true" ]]; then
    log_warn "Skipping binary installation (--config-only)"
    return 0
  fi

  step "Install Binaries"

  log_info "Installing binaries to ~/.cargo/bin..."

  if [[ "$DRY_RUN" == "true" ]]; then
    log "[DRY RUN] Would install: workspace, workspace-tui, workspace-dashboard"
    return 0
  fi

  local binaries=("workspace-cli" "workspace-tui" "workspace-dashboard")

  for binary in "${binaries[@]}"; do
    log_info "Installing $binary..."

    if ! cargo install --path "workspace-manager/crates/$binary" 2>&1 | tee -a "$LOG_FILE"; then
      log_error "Failed to install $binary"
      return 1
    fi
  done

  # Verify installations
  for binary in "workspace" "workspace-tui" "workspace-dashboard"; do
    if ! check_command "$binary"; then
      log_error "Binary not found in PATH: $binary"
      return 1
    fi
  done

  log_success "All binaries installed: workspace, workspace-tui, workspace-dashboard"
}

################################################################################
# Phase 6: Deploy Configurations
################################################################################

deploy_configurations() {
  step "Deploy Configurations"

  log_info "Deploying configuration files..."

  if [[ "$DRY_RUN" == "true" ]]; then
    log "[DRY RUN] Would deploy configurations to $CONFIG_DIR"
    return 0
  fi

  # Create directories
  mkdir -p "$CONFIG_DIR/features"
  mkdir -p "$DATA_DIR"
  mkdir -p "$MANIFEST_DIR"

  # Deploy main config
  if [[ -f "workspace-manager/workspace-api-config.template.toml" ]]; then
    cp "workspace-manager/workspace-api-config.template.toml" "$CONFIG_DIR/workspace-api.toml"
    log_success "Deployed: workspace-api.toml"
  else
    log_warn "Main config template not found"
  fi

  # Deploy feature configs
  if [[ -d "workspace-manager/configs/features" ]]; then
    for template in workspace-manager/configs/features/*.template; do
      if [[ -f "$template" ]]; then
        local filename=$(basename "$template" .template)
        cp "$template" "$CONFIG_DIR/features/$filename"
      fi
    done
    local count=$(find "$CONFIG_DIR/features" -type f | wc -l)
    log_success "Deployed: $count feature configurations"
  else
    log_warn "Feature configs directory not found"
  fi

  log_success "Configurations deployed to: $CONFIG_DIR"
}

################################################################################
# Phase 7: Setup Environment
################################################################################

setup_environment() {
  step "Setup Environment"

  log_info "Setting up environment variables and PATH..."

  if [[ "$DRY_RUN" == "true" ]]; then
    log "[DRY RUN] Would update shell configuration files"
    return 0
  fi

  # Detect shell
  local shell_name=$(basename "$SHELL")
  local shell_rc=""

  case "$shell_name" in
    bash)
      shell_rc="$HOME/.bashrc"
      ;;
    zsh)
      shell_rc="$HOME/.zshrc"
      ;;
    fish)
      shell_rc="$HOME/.config/fish/config.fish"
      ;;
    *)
      log_warn "Unknown shell: $shell_name"
      shell_rc="$HOME/.bashrc"
      ;;
  esac

  # Add cargo bin to PATH if not already present
  if [[ -n "$shell_rc" ]] && [[ -f "$shell_rc" ]]; then
    if ! grep -q '.cargo/bin' "$shell_rc"; then
      echo "" >> "$shell_rc"
      echo "# syntaxis" >> "$shell_rc"
      echo 'export PATH="$HOME/.cargo/bin:$PATH"' >> "$shell_rc"
      log_success "Updated $shell_rc"
    fi
  fi

  # Export environment variables for current session
  export PATH="$HOME/.cargo/bin:$PATH"
  export WORKSPACE_CONFIG_DIR="$CONFIG_DIR"
  export WORKSPACE_DATA_DIR="$DATA_DIR"

  log_success "Environment configured"
}

################################################################################
# Phase 8: Verification & Summary
################################################################################

verify_installation() {
  step "Verify Installation"

  log_info "Verifying installation..."

  if [[ "$DRY_RUN" == "true" ]]; then
    log "[DRY RUN] Would verify binaries and configurations"
    return 0
  fi

  local verification_ok=true

  # Check binaries
  for binary in workspace workspace-tui workspace-dashboard; do
    if check_command "$binary"; then
      log_success "Found: $binary"
    else
      log_warn "Not found: $binary"
      verification_ok=false
    fi
  done

  # Check configurations
  if [[ -f "$CONFIG_DIR/workspace-api.toml" ]]; then
    log_success "Found: workspace-api.toml"
  else
    log_warn "Not found: workspace-api.toml"
    verification_ok=false
  fi

  local feature_count=$(find "$CONFIG_DIR/features" -type f 2>/dev/null | wc -l)
  if [[ $feature_count -gt 0 ]]; then
    log_success "Found: $feature_count feature configurations"
  else
    log_warn "No feature configurations found"
  fi

  if [[ "$verification_ok" == "true" ]]; then
    log_success "Installation verified successfully"
    return 0
  else
    log_warn "Some components missing, but installation may still be functional"
    return 0 # Don't fail on partial verification
  fi
}

show_summary() {
  echo ""
  echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
  echo -e "${GREEN}✨ Installation Complete!${NC}"
  echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
  echo ""
  echo "Installation Details:"
  echo "  Version:         0.1.0"
  echo "  Installation:    $INSTALL_DIR"
  echo "  Binaries:        workspace, workspace-tui, workspace-dashboard"
  echo "  Config:          $CONFIG_DIR"
  echo "  Data:            $DATA_DIR"
  echo "  Log:             $LOG_FILE"
  echo ""
  echo "Quick Start:"
  echo "  workspace --help              # CLI documentation"
  echo "  workspace-tui                 # Launch TUI"
  echo "  cd $INSTALL_DIR && just run-dashboard  # Start web dashboard (port 3000)"
  echo ""
  echo "Next Steps:"
  echo "  1. Customize config: nano $CONFIG_DIR/workspace-api.toml"
  echo "  2. Create a project: workspace project create my-project"
  echo "  3. Read docs: https://github.com/syntaxis"
  echo ""

  # Remind to reload shell
  if [[ -n "$SHELL" ]]; then
    echo -e "${YELLOW}⚠️${NC}  Reload your shell for PATH changes to take effect:"
    echo "  source ~/$( basename "$SHELL" )rc"
  fi

  echo ""
  log_success "Thank you for installing syntaxis!"
}

################################################################################
# Main Installation Flow
################################################################################

main() {
  # Parse arguments
  while [[ $# -gt 0 ]]; do
    case "$1" in
      -h|--help)
        show_help
        exit 0
        ;;
      -v|--version)
        VERSION_TAG="$2"
        shift 2
        ;;
      --prefix)
        INSTALL_DIR="$2"
        shift 2
        ;;
      --skip-deps)
        SKIP_DEPS=true
        shift
        ;;
      --no-verify)
        NO_VERIFY=true
        shift
        ;;
      --unattended)
        UNATTENDED=true
        shift
        ;;
      --keep-build)
        KEEP_BUILD=true
        shift
        ;;
      --config-only)
        CONFIG_ONLY=true
        shift
        ;;
      --dry-run)
        DRY_RUN=true
        shift
        ;;
      *)
        log_error "Unknown option: $1"
        show_help
        exit 1
        ;;
    esac
  done

  # Show welcome message
  echo -e "${BLUE}"
  echo "╔════════════════════════════════════════════════════════╗"
  echo "║   syntaxis Installer v$INSTALLER_VERSION                 ║"
  echo "║   One-Command Installation for Project Management      ║"
  echo "╚════════════════════════════════════════════════════════╝"
  echo -e "${NC}"

  log "Starting installation..."
  log "Installation directory: $INSTALL_DIR"
  log "Log file: $LOG_FILE"

  # Execute installation phases
  preflight_checks || exit 1
  install_dependencies || exit 1
  clone_or_verify_repo || exit 1
  build_workspace || exit 1
  install_binaries || exit 1
  deploy_configurations || exit 1
  setup_environment || exit 1
  verify_installation || exit 1

  # Show summary
  show_summary

  # Cleanup build artifacts if requested
  if [[ "$KEEP_BUILD" != "true" ]] && [[ "$DRY_RUN" != "true" ]]; then
    log_info "Cleaning up build artifacts..."
    cd "$INSTALL_DIR"
    rm -rf target 2>/dev/null || true
    log_success "Cleanup complete"
  fi

  log_success "Installation successful"
  exit 0
}

# Run main function
main "$@"
