#!/bin/bash

set -euo pipefail # Exit on error, undefined vars, and pipe failures

# Configuration
HEADER_KEY="THIS HEADER IS AUTOGENERATED. DO NOT MODIFY MANUALLY."
HEADER="
/**
* ${HEADER_KEY}
* ! For any changes, please update the '/openvidu-meet/typings' directory.
**/"
SOURCE_DIR="src"

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

# Directory mapping configuration
declare -A TARGET_DIRECTORIES=(
    ["frontend"]="../frontend/projects/shared-meet-components/src/lib/typings/ce"
    ["backend"]="../backend/src/typings/ce"
    ["webcomponent"]="../frontend/webcomponent/src/typings/ce"
    ["pro"]="../../openvidu-meet-pro/types/src/ce"
)

# Target groups for convenience
declare -A TARGET_GROUPS=(
    ["ce"]="frontend backend webcomponent"
    ["pro"]="pro"
    ["all"]="frontend backend webcomponent pro"
)

# 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" >&2
}

# Help function
show_help() {
    cat <<EOF
Usage: $0 [OPTIONS] [TARGET]

Synchronize TypeScript declaration files from the source directory to target directories.

TARGETS:
    ce          Sync to Community Edition targets (frontend, backend, webcomponent)
    pro         Sync to Professional Edition target
    all         Sync to all targets (default)
    frontend    Sync only to frontend directory
    backend     Sync only to backend directory
    webcomponent Sync only to webcomponent directory

OPTIONS:
    -h, --help      Show this help message
    -v, --verbose   Verbose output
    -n, --dry-run   Show what would be done without actually doing it
    --add-headers   Add headers to source files (modifies source)
    --list-targets  List all available targets and their paths

EXAMPLES:
    $0              # Sync to all targets
    $0 ce           # Sync to CE targets only
    $0 frontend     # Sync to frontend only
    $0 --dry-run ce # Show what would be synced to CE targets
    $0 --add-headers # Add headers to source files and sync to all targets

EOF
}

# List targets function
list_targets() {
    log_info "Available targets and their paths:"
    echo
    for target in "${!TARGET_DIRECTORIES[@]}"; do
        local target_dir="${TARGET_DIRECTORIES[$target]}"
        local status=""
        if [ -d "$target_dir" ]; then
            status=" ${GREEN}[EXISTS]${NC}"
        else
            status=" ${YELLOW}[WILL BE CREATED]${NC}"
        fi
        echo -e "  ${BLUE}${target}${NC}: ${target_dir}${status}"
    done
    echo
    log_info "Available target groups:"
    for group in "${!TARGET_GROUPS[@]}"; do
        echo -e "  ${BLUE}${group}${NC}: ${TARGET_GROUPS[$group]}"
    done
}

# Validate source directory
validate_source() {
    if [ ! -d "$SOURCE_DIR" ]; then
        log_error "Source directory '$SOURCE_DIR' does not exist!"
        exit 1
    fi

    local d_ts_files
    d_ts_files=$(find "$SOURCE_DIR" -type f -name "*.ts" 2>/dev/null | wc -l)
    if [ "$d_ts_files" -eq 0 ]; then
        log_warning "No TypeScript declaration files found in source directory '$SOURCE_DIR'"
        return 1
    fi

    log_info "Found $d_ts_files TypeScript declaration files in source directory"
    return 0
}

# Validate and prepare target directories
validate_targets() {
    local targets="$1"
    local failed_targets=""

    log_info "Validating target directories..."

    for target in $targets; do
        local target_dir="${TARGET_DIRECTORIES[$target]}"

        if [ -z "$target_dir" ]; then
            log_error "No directory configured for target: $target"
            failed_targets="$failed_targets $target"
            continue
        fi

        # Try to create the directory structure to validate the path
        if [ "$DRY_RUN" = "false" ]; then
            local test_dir="$target_dir"
            if ! mkdir -p "$test_dir" 2>/dev/null; then
                log_error "Cannot create directory for target '$target': $test_dir"
                failed_targets="$failed_targets $target"
                continue
            fi
        fi

        [ "$VERBOSE" = "true" ] && log_info "Target '$target' validated: $target_dir"
    done

    if [ -n "$failed_targets" ]; then
        log_error "Failed to validate targets:$failed_targets"
        return 1
    fi

    return 0
}

# Add headers to source files
add_headers_to_source() {
    log_info "Adding headers to source files..."
    local count=0
    local temp_file_list
    temp_file_list=$(mktemp)

    find "$SOURCE_DIR" -type f -name "*.ts" >"$temp_file_list"

    while IFS= read -r file; do
        if ! grep -qF "$HEADER_KEY" "$file"; then
            if [ "$DRY_RUN" = "true" ]; then
                echo "  Would add header to: $file"
            else
                if printf "%s\n\n%s" "$HEADER" "$(cat "$file")" >"${file}.tmp" && mv "${file}.tmp" "$file"; then
                    [ "$VERBOSE" = "true" ] && echo "  Added header to: $file"
                    count=$((count + 1))
                else
                    log_error "Failed to add header to: $file"
                    rm -f "$temp_file_list"
                    return 1
                fi
            fi
        else
            [ "$VERBOSE" = "true" ] && echo "  Header already exists in: $file"
        fi
    done <"$temp_file_list"

    rm -f "$temp_file_list"

    if [ "$DRY_RUN" = "false" ]; then
        log_success "Headers added to $count files"
    fi
}

# Copy files with headers to target directory
copy_files_with_headers() {
    local target_dir="$1"
    local target_name="$2"

    log_info "Syncing types to $target_name ($target_dir)..."

    # Create target directory and all necessary parent directories
    if [ "$DRY_RUN" = "true" ]; then
        echo "  Would create directory: $target_dir"
    else
        if ! mkdir -p "$target_dir"; then
            log_error "Failed to create target directory: $target_dir"
            return 1
        fi
        [ "$VERBOSE" = "true" ] && log_info "Created/verified target directory: $target_dir"
    fi

    # Determine source path based on target
    local source_path="$SOURCE_DIR"
    if [ "$target_name" = "webcomponent" ]; then
        source_path="$SOURCE_DIR/webcomponent"
        if [ ! -d "$source_path" ]; then
            log_warning "Webcomponent source directory '$source_path' does not exist. Skipping webcomponent sync."
            return 0
        fi
    fi

    local file_count=0
    local temp_file_list
    temp_file_list=$(mktemp)

    find "$source_path" -type f -name "*.ts" >"$temp_file_list"

    while IFS= read -r file; do
        local relative_path
        if [ "$target_name" = "webcomponent" ]; then
            # For webcomponent, remove the webcomponent prefix from path
            relative_path="${file#$SOURCE_DIR/webcomponent/}"
        else
            relative_path="${file#$SOURCE_DIR/}"
        fi
        local dest_file="$target_dir/$relative_path"
        local dest_dir
        dest_dir=$(dirname "$dest_file")

        if [ "$DRY_RUN" = "true" ]; then
            echo "  Would copy: $file -> $dest_file"
        else
            if ! mkdir -p "$dest_dir"; then
                log_error "Failed to create directory: $dest_dir"
                rm -f "$temp_file_list"
                return 1
            fi

            if printf "%s\n\n%s" "$HEADER" "$(cat "$file")" >"$dest_file"; then
                [ "$VERBOSE" = "true" ] && echo "  Copied: $file -> $dest_file"
                file_count=$((file_count + 1))
            else
                log_error "Failed to copy: $file -> $dest_file"
                rm -f "$temp_file_list"
                return 1
            fi
        fi
    done <"$temp_file_list"

    rm -f "$temp_file_list"

    if [ "$DRY_RUN" = "false" ]; then
        log_success "Synced $file_count files to $target_name"
    fi
}

# Resolve targets from input
resolve_targets() {
    local input="$1"
    local targets=""

    # Check if input is a group
    if [ -n "${TARGET_GROUPS[$input]:-}" ]; then
        targets="${TARGET_GROUPS[$input]}"
    # Check if input is a single target
    elif [ -n "${TARGET_DIRECTORIES[$input]:-}" ]; then
        targets="$input"
    else
        log_error "Unknown target or group: '$input'"
        log_info "Use --list-targets to see available options"
        exit 1
    fi

    echo "$targets"
}

# Main sync function
sync_types() {
    local targets="$1"

    log_info "Starting type declaration synchronization..."
    [ "$DRY_RUN" = "true" ] && log_warning "DRY RUN MODE - No files will be modified"

    # Validate source directory
    validate_source || exit 1

    # Validate target directories
    validate_targets "$targets" || exit 1

    # Add headers to source if requested
    [ "$ADD_HEADERS" = "true" ] && add_headers_to_source

    # Process each target
    local success_count=0
    local total_count=0

    for target in $targets; do
        total_count=$((total_count + 1))
        local target_dir="${TARGET_DIRECTORIES[$target]}"

        if [ -z "$target_dir" ]; then
            log_error "No directory configured for target: $target"
            continue
        fi

        if copy_files_with_headers "$target_dir" "$target"; then
            success_count=$((success_count + 1))
        fi
    done

    # Summary
    echo
    if [ "$DRY_RUN" = "true" ]; then
        log_info "Dry run completed. $total_count targets would be processed."
    else
        log_success "Type declaration synchronization completed: $success_count/$total_count targets successful"
    fi
}

# Parse command line arguments
DRY_RUN="false"
VERBOSE="false"
ADD_HEADERS="false"
TARGET_INPUT=""

while [ $# -gt 0 ]; do
    case $1 in
    -h | --help)
        show_help
        exit 0
        ;;
    -v | --verbose)
        VERBOSE="true"
        shift
        ;;
    -n | --dry-run)
        DRY_RUN="true"
        shift
        ;;
    --add-headers)
        ADD_HEADERS="true"
        shift
        ;;
    --list-targets)
        list_targets
        exit 0
        ;;
    -*)
        log_error "Unknown option: $1"
        show_help
        exit 1
        ;;
    *)
        if [ -n "$TARGET_INPUT" ]; then
            log_error "Multiple targets specified. Use 'all' or a specific target/group."
            exit 1
        fi
        TARGET_INPUT="$1"
        shift
        ;;
    esac
done

# Default to 'all' if no target specified
TARGET_INPUT="${TARGET_INPUT:-all}"

# Resolve and execute
targets=$(resolve_targets "$TARGET_INPUT")
sync_types "$targets"
