#!/bin/bash

# forge - A home-manager like script for Fedora
# Provides dotfile management and package installation functionality

set -euo pipefail

# Configuration
FORGE_DIR="${FORGE_DIR:-$HOME/.config/forge}"
FORGE_TOML="$FORGE_DIR/forge.toml"

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

# Logging functions
log_info() {
  echo -e "${BLUE}[INFO]${NC} $1"
}

log_success() {
  echo -e "${GREEN}[SUCCESS]${NC} $1"
}

log_warning() {
  echo -e "${YELLOW}[WARNING]${NC} $1"
}

log_error() {
  echo -e "${RED}[ERROR]${NC} $1"
}

# Initialize command - creates forge.toml and .config directory
init() {
  log_info "Initializing forge..."
  
  # Create directory
  mkdir -p "$FORGE_DIR"

  # Create initial forge.toml if it doesn't exist
  if [[ ! -f "$FORGE_TOML" ]]; then
    cat >"$FORGE_TOML" <<'EOF'
# Forge Configuration File
# User-level configuration similar to home-manager/nixos

[forge]
version = "1.0"
last_switch = null

[packages]
# List of packages to install using dnf
# Just list package names - presence means install, absence means don't install
# Examples:
# git
# vim
# curl

[dotfiles]
# Dotfiles to manage with symlinks
# Format: "target_path" = "source_path"
# target_path: where the symlink should be created (relative to home directory)
# source_path: where the actual file is stored (relative to forge directory)
# Examples:
# ".bashrc" = "dotfiles/.bashrc"
# ".config/vimrc" = "dotfiles/vimrc"

[options]
# Additional options
backup = true
backup_dir = "backup"
EOF
    log_success "Created forge.toml: $FORGE_TOML"
  fi

  log_success "Initialization complete!"
  log_info "Edit $FORGE_TOML to configure packages and dotfiles"
  log_info "Run 'forge switch' to apply your configuration"
}

# Parse TOML file (basic implementation)
parse_toml() {
  local section=""
  while IFS= read -r line; do
    # Skip comments and empty lines
    [[ -z "$line" || "$line" == \#* ]] && continue
    
    # Check for section headers
    if [[ "$line" =~ ^\[(.+)\]$ ]]; then
      section="${BASH_REMATCH[1]}"
      continue
    fi
    
    # Parse key-value pairs for non-packages sections
    if [[ "$section" != "packages" && "$line" =~ ^([^=]+)=(.+)$ ]]; then
      local key="${BASH_REMATCH[1]// /}"
      local value="${BASH_REMATCH[2]// /}"
      echo "$section:$key=$value"
    # Parse package names (just keys without values in packages section)
    elif [[ "$section" == "packages" && "$line" =~ ^([^=]+)$ ]]; then
      local package="${BASH_REMATCH[1]// /}"
      echo "$section:$package"
    fi
  done <"$FORGE_TOML"
}

# Install packages from forge.toml
install_packages() {
  log_info "Installing packages..."
  
  local packages_installed=false
  
  while IFS='=' read -r entry; do
    local section="${entry%%:*}"
    local package="${entry#*:}"
    
    if [[ "$section" == "packages" && -n "$package" ]]; then
      packages_installed=true
      log_info "Installing package: $package"
      if sudo dnf install -y "$package"; then
        log_success "Installed $package"
      else
        log_error "Failed to install $package"
      fi
    fi
  done < <(parse_toml)
  
  if [[ "$packages_installed" == false ]]; then
    log_info "No packages to install"
  fi
}

# Deploy dotfiles using symlinks
deploy_dotfiles() {
  log_info "Deploying dotfiles..."
  
  local dotfiles_deployed=false
  
  while IFS='=' read -r entry; do
    local section="${entry%%:*}"
    local key_value="${entry#*:}"
    local target="${key_value%%=*}"
    local source="${key_value##*=}"
    
    if [[ "$section" == "dotfiles" ]]; then
      dotfiles_deployed=true
      
      local target_path="$HOME/$target"
      local source_path="$FORGE_DIR/$source"
      
      # Create source directory if it doesn't exist
      local source_dir=$(dirname "$source_path")
      mkdir -p "$source_dir"
      
      # Create target directory if it doesn't exist
      local target_dir=$(dirname "$target_path")
      mkdir -p "$target_dir"
      
      # Backup existing file if it exists and is not a symlink
      if [[ -f "$target_path" && ! -L "$target_path" ]]; then
        local backup_dir="$FORGE_DIR/backup"
        mkdir -p "$backup_dir"
        local backup_path="$backup_dir/$(basename "$target").$(date +%Y%m%d_%H%M%S).bak"
        cp "$target_path" "$backup_path"
        log_info "Backed up $target_path to $backup_path"
      fi
      
      # Remove existing file/symlink
      rm -f "$target_path"
      
      # Create symlink
      if ln -s "$source_path" "$target_path"; then
        log_success "Created symlink: $target_path -> $source_path"
      else
        log_error "Failed to create symlink: $target_path -> $source_path"
      fi
    fi
  done < <(parse_toml)
  
  if [[ "$dotfiles_deployed" == false ]]; then
    log_info "No dotfiles to deploy"
  fi
}

# Switch command - apply configuration
switch() {
  log_info "Starting forge switch..."
  
  # Check if forge.toml exists
  if [[ ! -f "$FORGE_TOML" ]]; then
    log_error "forge.toml not found. Run 'forge init' first."
    exit 1
  fi
  
  # Install packages
  install_packages
  
  # Deploy dotfiles
  deploy_dotfiles
  
  # Update last_switch timestamp
  if command -v sed >/dev/null 2>&1; then
    sed -i "s/last_switch = .*/last_switch = \"$(date -Iseconds)\"/" "$FORGE_TOML"
  fi
  
  log_success "Switch completed successfully!"
}

# Status command - show current configuration
status() {
  log_info "Forge Status"
  echo "  Config directory: $FORGE_DIR"
  echo "  Config file: $FORGE_TOML"
  
  if [[ -f "$FORGE_TOML" ]]; then
    echo
    log_info "Configuration:"
    
    # Show last switch time
    local last_switch=$(grep "last_switch" "$FORGE_TOML" | cut -d'=' -f2 | tr -d ' "')
    if [[ -n "$last_switch" && "$last_switch" != "null" ]]; then
      echo "  Last switch: $last_switch"
    else
      echo "  Last switch: Never"
    fi
    
    echo
    log_info "Packages:"
    local package_count=0
    while IFS='=' read -r entry; do
      local section="${entry%%:*}"
      local package="${entry#*:}"
      
      if [[ "$section" == "packages" && -n "$package" ]]; then
        echo "  $package"
        ((package_count++))
      fi
    done < <(parse_toml)
    
    if [[ $package_count -eq 0 ]]; then
      echo "  No packages configured"
    else
      echo "  Total: $package_count packages"
    fi
    
    echo
    log_info "Dotfiles:"
    local dotfile_count=0
    while IFS='=' read -r entry; do
      local section="${entry%%:*}"
      local key_value="${entry#*:}"
      local target="${key_value%%=*}"
      local source="${key_value##*=}"
      
      if [[ "$section" == "dotfiles" ]]; then
        echo "  $target -> $source"
        ((dotfile_count++))
      fi
    done < <(parse_toml)
    
    if [[ $dotfile_count -eq 0 ]]; then
      echo "  No dotfiles configured"
    else
      echo "  Total: $dotfile_count dotfiles"
    fi
  else
    echo "  No configuration file found"
  fi
}

# Show help
show_help() {
  cat <<EOF
  forge - A home-manager like script for Fedora

 USAGE:
     forge <COMMAND>

 COMMANDS:
     init            Initialize configuration structure (creates forge.toml)
     switch          Apply configuration (install packages, deploy dotfiles)
     status          Show current configuration status
     help            Show this help message

 FEATURES:
     - TOML-based configuration in forge.toml
     - Package management via dnf
     - Dotfile management via symlinks
     - Automatic backup of existing files
     - User-level configuration like home-manager/nixos

 FILES:
     $FORGE_DIR/              Main configuration directory
     $FORGE_TOML              Configuration file for packages and dotfiles

 EXAMPLES:
     forge init
     # Edit $FORGE_TOML to add packages and dotfiles
     forge switch
     forge status

EOF
}

# Main script logic
main() {
  case "${1:-}" in
  "init")
    init
    ;;
  "switch")
    switch
    ;;
  "status")
    status
    ;;
  "help" | "--help" | "-h")
    show_help
    ;;
  "")
    log_error "No command specified. Use 'help' for usage information."
    exit 1
    ;;
  *)
    log_error "Unknown command: $1"
    show_help
    exit 1
    ;;
  esac
}

# Run main function with all arguments
main "$@"