#!/bin/bash

# Dotfiles sync script
set -euo pipefail

# Configuration
checkout_dir=$HOME/.dofiles
script_dir=$checkout_dir/dotfiles
dots_dir=$checkout_dir/dotfiles/dots
repo="https://git.capella.pro/capella/dotfiles.git"
ProgName=$(basename "$0")

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

# Logging functions
log_info() { echo -e "${GREEN}[INFO]${NC} $*"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $*" >&2; }
log_error() { echo -e "${RED}[ERROR]${NC} $*" >&2; }

# Ensure we cleanup on exit
trap 'cd "$HOME"' EXIT

# Create checkout directory if needed
mkdir -p "$checkout_dir"


sub_help(){
    cat << EOF
Usage: $ProgName <subcommand> [options]

Subcommands:
    sync [dot_file_to_add]    Sync dotfiles (optionally add a new dotfile to track)
    list                      List currently synced dotfiles
    status                    Show git status of dotfiles repo

For help with each subcommand run:
    $ProgName <subcommand> -h|--help

EOF
}

sub_sync(){
    # Clone repo if it doesn't exist
    if [[ ! -d "$checkout_dir/dotfiles/.git" ]]; then
        log_info "Cloning dotfiles repository..."
        cd "$checkout_dir"
        if ! git clone "$repo"; then
            log_error "Failed to clone repository"
            exit 1
        fi
        cd "$script_dir"
        git submodule init
        git submodule update
    fi

    # Navigate to script directory
    cd "$script_dir"

    # Get current branch
    current_branch=$(git branch --show-current)
    log_info "Pulling latest changes from $current_branch..."
    git pull origin "$current_branch" || log_warn "Git pull failed, continuing anyway"
    git submodule update --init --recursive

    # Add new dotfile if provided
    if [ -n "${1:-}" ]; then
        local file_to_add="$1"

        # Validate that file exists
        if [[ ! -e "$HOME/$file_to_add" ]]; then
            log_error "File $HOME/$file_to_add does not exist"
            exit 1
        fi

        log_info "Adding new dotfile: $file_to_add"

        real_path=$(realpath "$HOME/$file_to_add")
        to_copy=${real_path#"$HOME/"}

        # Create parent directory structure in dots_dir
        mkdir -p "$(dirname "$dots_dir/$to_copy")"

        # Copy to dots directory
        if cp -R "$real_path" "$dots_dir/$to_copy"; then
            log_info "Copied $file_to_add to $dots_dir/$to_copy"
        else
            log_error "Failed to copy $file_to_add"
            exit 1
        fi

        # Add to to_sync file if not already there
        if ! grep -qxF "$to_copy" "$script_dir/to_sync" 2>/dev/null; then
            echo "$to_copy" >> "$script_dir/to_sync"
            log_info "Added $to_copy to sync list"
        else
            log_info "$to_copy already in sync list"
        fi

        # Remove original and create symlink
        rm -rf "$real_path"
        ln -s "$dots_dir/$to_copy" "$real_path"
        log_info "Created symlink: $real_path -> $dots_dir/$to_copy"
    fi

    # Add tracked files to git
    log_info "Staging changes..."
    while IFS= read -r p; do
        [[ -z "$p" ]] && continue  # Skip empty lines
        file="$dots_dir/$p"
        if [[ -e "$file" ]]; then
            git add "$file"
        else
            log_warn "Tracked file $file does not exist"
        fi
    done < "$script_dir/to_sync"

    git add start to_sync

    # Commit and push if there are changes
    if git diff --cached --quiet; then
        log_info "No changes to commit"
    else
        log_info "Committing changes..."
        if git commit -m "Sync: $(date '+%Y-%m-%d %H:%M:%S')"; then
            log_info "Pushing to remote..."
            git remote add origin "$repo" 2>/dev/null || true
            if git push -u origin "$current_branch"; then
                log_info "Successfully pushed changes"
            else
                log_error "Failed to push changes"
                exit 1
            fi
        else
            log_error "Failed to commit changes"
            exit 1
        fi
    fi

    # Create symlinks for all tracked dotfiles
    log_info "Creating symlinks..."
    while IFS= read -r p; do
        [[ -z "$p" ]] && continue  # Skip empty lines
        destination="$HOME/$p"
        source="$dots_dir/$p"

        if [[ ! -e "$source" ]]; then
            log_warn "Source file $source does not exist, skipping"
            continue
        fi

        # Check if destination is already a correct symlink
        if [[ -L "$destination" ]] && [[ "$(readlink "$destination")" == "$source" ]]; then
            continue  # Already correctly linked
        fi

        # Remove destination if it exists
        if [[ -e "$destination" ]] || [[ -L "$destination" ]]; then
            log_warn "Removing existing $destination"
            rm -rf "$destination"
        fi

        # Create parent directory if needed
        mkdir -p "$(dirname "$destination")"

        # Create symlink
        if ln -s "$source" "$destination"; then
            log_info "Linked: $destination -> $source"
        else
            log_error "Failed to create symlink for $p"
        fi
    done < "$script_dir/to_sync"

    log_info "Sync complete!"
}

sub_list(){
    if [[ ! -f "$script_dir/to_sync" ]]; then
        log_error "No to_sync file found"
        exit 1
    fi

    echo "Currently synced dotfiles:"
    while IFS= read -r p; do
        [[ -z "$p" ]] && continue
        if [[ -L "$HOME/$p" ]]; then
            echo "  ✓ $p"
        else
            echo "  ✗ $p (not linked)"
        fi
    done < "$script_dir/to_sync"
}

sub_status(){
    if [[ ! -d "$script_dir/.git" ]]; then
        log_error "Dotfiles repository not found"
        exit 1
    fi

    cd "$script_dir"
    log_info "Git status:"
    git status
}


subcommand=${1:-}
case $subcommand in
    "" | "-h" | "--help")
        sub_help
        ;;
    sync|list|status)
        shift
        "sub_${subcommand}" "$@"
        ;;
    *)
        log_error "'$subcommand' is not a known subcommand."
        echo "       Run '$ProgName --help' for a list of known subcommands." >&2
        exit 1
        ;;
esac