#!/bin/bash

###############################################################################
# NPM 发布准备脚本 / NPM Publish Preparation Script
# 
# 用途: 自动化检查和准备 npm 发布流程
# Usage: Automate checks and preparation for npm publishing
#
# 使用方法 / Usage:
#   ./scripts/prepare-publish.sh [version_type] [options]
#   
#   version_type: patch | minor | major | prerelease
#   
# 选项 / Options:
#   --registry <url>    指定 npm registry / Specify npm registry
#   --skip-tests        跳过测试 / Skip tests
#   --dry-run          只预览，不实际发布 / Preview only, don't publish
#   
# 示例 / Examples:
#   ./scripts/prepare-publish.sh patch
#   ./scripts/prepare-publish.sh minor --registry http://localhost:4873
#   ./scripts/prepare-publish.sh patch --dry-run
###############################################################################

set -e  # Exit on error

# Load custom registry from .env.publish if exists
if [ -f ".env.publish" ]; then
    source .env.publish
fi

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

# Emoji
CHECK="✅"
CROSS="❌"
WARN="⚠️"
INFO="ℹ️"
ROCKET="🚀"

# Default options
CUSTOM_REGISTRY=""
SKIP_TESTS=false
DRY_RUN=false

###############################################################################
# Helper Functions
###############################################################################

print_header() {
    echo ""
    echo -e "${BLUE}========================================${NC}"
    echo -e "${BLUE}$1${NC}"
    echo -e "${BLUE}========================================${NC}"
    echo ""
}

print_success() {
    echo -e "${GREEN}${CHECK} $1${NC}"
}

print_error() {
    echo -e "${RED}${CROSS} $1${NC}"
}

print_warning() {
    echo -e "${YELLOW}${WARN} $1${NC}"
}

print_info() {
    echo -e "${BLUE}${INFO} $1${NC}"
}

confirm() {
    read -p "$1 [y/N] " -n 1 -r
    echo
    if [[ ! $REPLY =~ ^[Yy]$ ]]; then
        return 1
    fi
    return 0
}

###############################################################################
# Pre-flight Checks
###############################################################################

check_environment() {
    print_header "环境检查 / Environment Check"
    
    # Check Node.js
    if command -v node &> /dev/null; then
        NODE_VERSION=$(node --version)
        print_success "Node.js: $NODE_VERSION"
    else
        print_error "Node.js not found"
        exit 1
    fi
    
    # Check Yarn
    if command -v yarn &> /dev/null; then
        YARN_VERSION=$(yarn --version)
        print_success "Yarn: $YARN_VERSION"
    else
        print_error "Yarn not found"
        exit 1
    fi
    
    # Check npm
    if command -v npm &> /dev/null; then
        NPM_VERSION=$(npm --version)
        print_success "npm: $NPM_VERSION"
    else
        print_error "npm not found"
        exit 1
    fi
    
    # Check git
    if command -v git &> /dev/null; then
        GIT_VERSION=$(git --version)
        print_success "git: $GIT_VERSION"
    else
        print_error "git not found"
        exit 1
    fi
}

check_git_status() {
    print_header "Git 状态检查 / Git Status Check"
    
    # Check current branch
    CURRENT_BRANCH=$(git branch --show-current)
    if [ "$CURRENT_BRANCH" != "main" ]; then
        print_warning "Not on main branch (current: $CURRENT_BRANCH)"
        if ! confirm "Continue anyway?"; then
            exit 1
        fi
    else
        print_success "On main branch"
    fi
    
    # Check for uncommitted changes
    if [ -n "$(git status --porcelain)" ]; then
        print_error "Working directory is not clean"
        git status --short
        exit 1
    else
        print_success "Working directory is clean"
    fi
    
    # Check if up to date with remote
    git fetch origin $CURRENT_BRANCH
    LOCAL=$(git rev-parse @)
    REMOTE=$(git rev-parse @{u})
    
    if [ "$LOCAL" != "$REMOTE" ]; then
        print_warning "Local branch is not up to date with remote"
        if confirm "Pull latest changes?"; then
            git pull origin $CURRENT_BRANCH
            print_success "Pulled latest changes"
        else
            exit 1
        fi
    else
        print_success "Up to date with remote"
    fi
}

check_npm_auth() {
    print_header "NPM 认证检查 / NPM Authentication Check"
    
    local REGISTRY_OPTION=""
    if [ -n "$CUSTOM_REGISTRY" ]; then
        REGISTRY_OPTION="--registry $CUSTOM_REGISTRY"
        print_info "Using custom registry: $CUSTOM_REGISTRY"
    fi
    
    if npm whoami $REGISTRY_OPTION &> /dev/null; then
        NPM_USER=$(npm whoami $REGISTRY_OPTION)
        print_success "Logged in as: $NPM_USER"
        
        if [ -n "$CUSTOM_REGISTRY" ]; then
            print_info "Registry: $CUSTOM_REGISTRY"
        fi
    else
        print_error "Not logged in to npm"
        if [ -n "$CUSTOM_REGISTRY" ]; then
            print_info "Please run: npm adduser --registry $CUSTOM_REGISTRY"
        else
            print_info "Please run: npm login"
        fi
        exit 1
    fi
}

###############################################################################
# Code Quality Checks
###############################################################################

run_tests() {
    if [ "$SKIP_TESTS" = true ]; then
        print_header "跳过测试 / Skipping Tests"
        print_warning "Tests skipped as requested"
        return
    fi
    
    print_header "运行测试 / Running Tests"
    
    print_info "Running linter..."
    if yarn test:lint; then
        print_success "Linter passed"
    else
        print_error "Linter failed"
        exit 1
    fi
    
    print_info "Running format check..."
    if yarn test:format; then
        print_success "Format check passed"
    else
        print_error "Format check failed"
        print_info "Try running: yarn prettier --write \"docs/**/*.md\" README.md"
        exit 1
    fi
    
    print_info "Running type check..."
    if yarn test:types; then
        print_success "Type check passed"
    else
        print_error "Type check failed"
        exit 1
    fi
}

###############################################################################
# Build Process
###############################################################################

clean_build() {
    print_header "清理构建 / Clean Build"
    
    if [ -d "lib" ]; then
        print_info "Removing old build artifacts..."
        rm -rf lib/
        print_success "Build directory cleaned"
    else
        print_info "No build directory to clean"
    fi
}

build_package() {
    print_header "构建包 / Build Package"
    
    print_info "Running build..."
    if yarn prepare; then
        print_success "Build completed"
    else
        print_error "Build failed"
        exit 1
    fi
    
    # Verify build outputs
    print_info "Verifying build outputs..."
    
    if [ -d "lib/commonjs" ] && [ -d "lib/module" ] && [ -d "lib/typescript" ]; then
        print_success "All build outputs present"
        
        # Show build size
        BUILD_SIZE=$(du -sh lib/ | cut -f1)
        print_info "Build size: $BUILD_SIZE"
    else
        print_error "Missing build outputs"
        exit 1
    fi
}

###############################################################################
# Version Management
###############################################################################

update_version() {
    local VERSION_TYPE=$1
    
    print_header "更新版本 / Update Version"
    
    CURRENT_VERSION=$(node -p "require('./package.json').version")
    print_info "Current version: $CURRENT_VERSION"
    
    if [ -z "$VERSION_TYPE" ]; then
        print_error "Version type not specified"
        print_info "Usage: $0 [patch|minor|major|prerelease]"
        exit 1
    fi
    
    print_info "Updating version: $VERSION_TYPE"
    
    if [ "$VERSION_TYPE" = "prerelease" ]; then
        npm version prerelease --preid=beta --no-git-tag-version
    else
        npm version $VERSION_TYPE --no-git-tag-version
    fi
    
    NEW_VERSION=$(node -p "require('./package.json').version")
    print_success "Version updated: $CURRENT_VERSION -> $NEW_VERSION"
    
    # Update git
    git add package.json
    git commit -m "chore: bump version to $NEW_VERSION"
    git tag -a "v$NEW_VERSION" -m "Release v$NEW_VERSION"
    
    print_success "Git commit and tag created"
    
    echo "$NEW_VERSION"
}

###############################################################################
# Publish Preview
###############################################################################

preview_publish() {
    print_header "发布预览 / Publish Preview"
    
    local REGISTRY_OPTION=""
    if [ -n "$CUSTOM_REGISTRY" ]; then
        REGISTRY_OPTION="--registry $CUSTOM_REGISTRY"
    fi
    
    print_info "Running npm publish --dry-run..."
    echo ""
    
    npm publish --dry-run --access public $REGISTRY_OPTION
    
    echo ""
    print_success "Dry run completed"
    print_warning "Please review the files that will be published above"
}

###############################################################################
# Summary
###############################################################################

print_summary() {
    local NEW_VERSION=$1
    
    print_header "发布摘要 / Publish Summary"
    
    echo -e "${GREEN}All checks passed! ${ROCKET}${NC}"
    echo ""
    echo "Package: @appzung/react-native-code-push"
    echo "Version: $NEW_VERSION"
    echo "Branch: $(git branch --show-current)"
    echo "Commit: $(git rev-parse --short HEAD)"
    
    if [ -n "$CUSTOM_REGISTRY" ]; then
        echo "Registry: $CUSTOM_REGISTRY"
    fi
    
    if [ "$DRY_RUN" = true ]; then
        echo ""
        echo -e "${YELLOW}DRY RUN MODE - No actual publishing${NC}"
        echo ""
        return
    fi
    
    echo ""
    echo -e "${YELLOW}Next steps:${NC}"
    echo "1. Review the changes above"
    if [ -n "$CUSTOM_REGISTRY" ]; then
        echo "2. Run: npm publish --access public --registry $CUSTOM_REGISTRY"
    else
        echo "2. Run: npm publish --access public"
    fi
    echo "3. Run: git push origin main"
    echo "4. Run: git push origin --tags"
    echo "5. Create GitHub Release at:"
    echo "   https://github.com/appzung/react-native-code-push/releases/new?tag=v$NEW_VERSION"
    echo ""
}

###############################################################################
# Parse Arguments
###############################################################################

parse_args() {
    VERSION_TYPE=""
    
    while [[ $# -gt 0 ]]; do
        case $1 in
            --registry)
                CUSTOM_REGISTRY="$2"
                shift 2
                ;;
            --skip-tests)
                SKIP_TESTS=true
                shift
                ;;
            --dry-run)
                DRY_RUN=true
                shift
                ;;
            patch|minor|major|prerelease)
                VERSION_TYPE="$1"
                shift
                ;;
            *)
                echo "Unknown option: $1"
                echo "Usage: $0 [patch|minor|major|prerelease] [--registry <url>] [--skip-tests] [--dry-run]"
                exit 1
                ;;
        esac
    done
}

###############################################################################
# Main Script
###############################################################################

main() {
    # Parse command line arguments
    parse_args "$@"
    
    echo ""
    echo -e "${BLUE}╔═══════════════════════════════════════════════════════════╗${NC}"
    echo -e "${BLUE}║                                                           ║${NC}"
    echo -e "${BLUE}║     React Native CodePush - Publish Preparation          ║${NC}"
    echo -e "${BLUE}║                                                           ║${NC}"
    echo -e "${BLUE}╚═══════════════════════════════════════════════════════════╝${NC}"
    echo ""
    
    # Run all checks
    check_environment
    check_git_status
    check_npm_auth
    run_tests
    clean_build
    build_package
    
    # Update version if specified
    if [ -n "$VERSION_TYPE" ]; then
        NEW_VERSION=$(update_version $VERSION_TYPE)
    else
        NEW_VERSION=$(node -p "require('./package.json').version")
        print_warning "No version update (use: $0 [patch|minor|major|prerelease])"
    fi
    
    # Preview publish
    preview_publish
    
    # Print summary
    print_summary $NEW_VERSION
    
    # Final confirmation
    echo ""
    
    if [ "$DRY_RUN" = true ]; then
        print_info "DRY RUN MODE - Skipping actual publish"
        echo ""
        print_success "Dry run completed successfully!"
        print_info "To publish for real, run without --dry-run flag"
        echo ""
        return
    fi
    
    if confirm "${ROCKET} Ready to publish to npm?"; then
        local REGISTRY_OPTION=""
        if [ -n "$CUSTOM_REGISTRY" ]; then
            REGISTRY_OPTION="--registry $CUSTOM_REGISTRY"
        fi
        
        print_info "Publishing to npm..."
        npm publish --access public $REGISTRY_OPTION
        print_success "Published to npm!"
        
        print_info "Pushing to git..."
        git push origin $(git branch --show-current)
        git push origin --tags
        print_success "Pushed to git!"
        
        echo ""
        echo -e "${GREEN}${ROCKET} ${ROCKET} ${ROCKET} Publication complete! ${ROCKET} ${ROCKET} ${ROCKET}${NC}"
        echo ""
        echo "Don't forget to:"
        echo "- Create GitHub Release"
        echo "- Update documentation"
        echo "- Notify team and users"
        echo ""
        
        if [ -n "$CUSTOM_REGISTRY" ]; then
            echo "Published to: $CUSTOM_REGISTRY"
            echo "Verify with: npm view @appzung/react-native-code-push --registry $CUSTOM_REGISTRY"
        fi
        echo ""
    else
        echo ""
        print_info "Publication cancelled. The version has been updated locally."
        if [ -n "$CUSTOM_REGISTRY" ]; then
            print_info "You can publish manually later with: npm publish --access public --registry $CUSTOM_REGISTRY"
        else
            print_info "You can publish manually later with: npm publish --access public"
        fi
        echo ""
    fi
}

# Show usage if no arguments
if [ $# -eq 0 ]; then
    echo "Usage: $0 [patch|minor|major|prerelease] [options]"
    echo ""
    echo "Options:"
    echo "  --registry <url>    指定 npm registry"
    echo "  --skip-tests        跳过测试"
    echo "  --dry-run          只预览，不实际发布"
    echo ""
    echo "Examples:"
    echo "  $0 patch"
    echo "  $0 minor --registry http://localhost:4873"
    echo "  $0 patch --dry-run --skip-tests"
    echo ""
    exit 0
fi

# Run main script
main "$@"

