#!/bin/bash
# =============================================================================
# Synor Contract Template Generator
# =============================================================================
# Creates a new smart contract project from template.
#
# Usage:
#   ./scripts/new-contract.sh <contract-name> [--description "Description"]
#
# Example:
#   ./scripts/new-contract.sh my-token --description "My custom token"
# =============================================================================

set -e

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
CONTRACTS_DIR="$PROJECT_DIR/contracts"

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

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

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

log_warn() {
    echo -e "${YELLOW}[WARN]${NC} $1"
}

print_usage() {
    echo "Synor Contract Template Generator"
    echo ""
    echo "Usage: $0 <contract-name> [options]"
    echo ""
    echo "Options:"
    echo "  --description, -d    Contract description"
    echo "  --help, -h           Show this help"
    echo ""
    echo "Examples:"
    echo "  $0 my-token"
    echo "  $0 my-token --description \"Custom fungible token\""
}

# Parse arguments
CONTRACT_NAME=""
DESCRIPTION="A Synor smart contract"

while [[ $# -gt 0 ]]; do
    case $1 in
        --description|-d)
            DESCRIPTION="$2"
            shift 2
            ;;
        --help|-h)
            print_usage
            exit 0
            ;;
        -*)
            echo "Unknown option: $1"
            print_usage
            exit 1
            ;;
        *)
            if [[ -z "$CONTRACT_NAME" ]]; then
                CONTRACT_NAME="$1"
            fi
            shift
            ;;
    esac
done

if [[ -z "$CONTRACT_NAME" ]]; then
    echo "Error: Contract name required"
    print_usage
    exit 1
fi

# Validate contract name (lowercase, alphanumeric, hyphens)
if ! [[ "$CONTRACT_NAME" =~ ^[a-z][a-z0-9-]*$ ]]; then
    echo "Error: Contract name must be lowercase, start with a letter, and contain only letters, numbers, and hyphens"
    exit 1
fi

# Convert to Rust package name (hyphens to underscores for module)
RUST_NAME=$(echo "$CONTRACT_NAME" | tr '-' '_')
PACKAGE_NAME="synor-$CONTRACT_NAME"

CONTRACT_DIR="$CONTRACTS_DIR/$CONTRACT_NAME"

# Check if already exists
if [[ -d "$CONTRACT_DIR" ]]; then
    log_warn "Contract directory already exists: $CONTRACT_DIR"
    read -p "Overwrite? (y/N) " -n 1 -r
    echo
    if [[ ! $REPLY =~ ^[Yy]$ ]]; then
        exit 1
    fi
    rm -rf "$CONTRACT_DIR"
fi

log_info "Creating contract: $CONTRACT_NAME"

# Create directory structure
mkdir -p "$CONTRACT_DIR/src"

# Create Cargo.toml
cat > "$CONTRACT_DIR/Cargo.toml" << EOF
[package]
name = "$PACKAGE_NAME"
version = "0.1.0"
edition = "2021"
description = "$DESCRIPTION"
authors = ["Your Name <your@email.com>"]
license = "MIT"

[lib]
crate-type = ["cdylib"]

[dependencies]
synor-sdk = { path = "../../crates/synor-sdk", default-features = false }
borsh = { version = "1.3", default-features = false, features = ["derive"] }

[profile.release]
opt-level = "z"      # Optimize for size
lto = true           # Link-time optimization
codegen-units = 1    # Single codegen unit for better optimization
panic = "abort"      # Abort on panic (smaller binaries)
strip = true         # Strip symbols
EOF

# Create lib.rs template
cat > "$CONTRACT_DIR/src/lib.rs" << 'EOF'
//! CONTRACT_DESCRIPTION
//!
//! # Methods
//! - `init(...)` - Initialize the contract
//! - Add more methods here...

#![no_std]

extern crate alloc;

use alloc::vec::Vec;
use borsh::BorshDeserialize;
use synor_sdk::prelude::*;
use synor_sdk::require;

// ==================== Storage Keys ====================

mod keys {
    pub const OWNER: &[u8] = b"CONTRACT_NAME:owner";
    pub const INITIALIZED: &[u8] = b"CONTRACT_NAME:initialized";
    // Add more storage keys here...
}

// ==================== Data Structures ====================

// Add your custom structs here...
// #[derive(BorshSerialize, BorshDeserialize)]
// pub struct MyStruct {
//     pub field: u64,
// }

// ==================== Storage Helpers ====================

fn get_owner() -> Option<Address> {
    storage::get::<Address>(keys::OWNER)
}

fn is_initialized() -> bool {
    storage::get::<bool>(keys::INITIALIZED).unwrap_or(false)
}

// ==================== Entry Points ====================

synor_sdk::entry_point!(init, call);

/// Initialize the contract.
fn init(params: &[u8]) -> Result<()> {
    require!(!is_initialized(), Error::invalid_args("Already initialized"));

    #[derive(BorshDeserialize)]
    struct InitParams {
        // Add your initialization parameters here
        // name: String,
        // value: u64,
    }

    let _params = InitParams::try_from_slice(params)
        .map_err(|_| Error::invalid_args("Invalid init params"))?;

    // Store owner
    storage::set(keys::OWNER, &caller());
    storage::set(keys::INITIALIZED, &true);

    // Initialize your contract state here...

    Ok(())
}

/// Handle contract calls.
fn call(selector: &[u8], params: &[u8]) -> Result<Vec<u8>> {
    // Define method selectors
    let owner_sel = synor_sdk::method_selector("owner");
    let example_sel = synor_sdk::method_selector("example_method");

    match selector {
        s if s == owner_sel => {
            let owner = get_owner().unwrap_or(Address::zero());
            Ok(borsh::to_vec(&owner).unwrap())
        }

        s if s == example_sel => {
            #[derive(BorshDeserialize)]
            struct Args {
                value: u64,
            }
            let args = Args::try_from_slice(params)
                .map_err(|_| Error::invalid_args("Expected value"))?;

            // Implement your logic here
            let result = args.value * 2;

            Ok(borsh::to_vec(&result).unwrap())
        }

        _ => Err(Error::InvalidMethod),
    }
}

// ==================== Internal Functions ====================

// Add your internal helper functions here...

// ==================== Events ====================

// Define your events here...
// #[derive(borsh::BorshSerialize)]
// struct MyEvent {
//     field: u64,
// }
EOF

# Replace placeholders
sed -i '' "s/CONTRACT_DESCRIPTION/$DESCRIPTION/g" "$CONTRACT_DIR/src/lib.rs" 2>/dev/null || \
sed -i "s/CONTRACT_DESCRIPTION/$DESCRIPTION/g" "$CONTRACT_DIR/src/lib.rs"

sed -i '' "s/CONTRACT_NAME/$RUST_NAME/g" "$CONTRACT_DIR/src/lib.rs" 2>/dev/null || \
sed -i "s/CONTRACT_NAME/$RUST_NAME/g" "$CONTRACT_DIR/src/lib.rs"

log_success "Contract created: $CONTRACT_DIR"
echo ""
echo "Next steps:"
echo "  1. Edit $CONTRACT_DIR/src/lib.rs to implement your contract"
echo "  2. Build with:"
echo "     cargo build --manifest-path $CONTRACT_DIR/Cargo.toml --target wasm32-unknown-unknown --release"
echo "  3. Deploy with:"
echo "     synor contract deploy target/wasm32-unknown-unknown/release/${PACKAGE_NAME//-/_}.wasm"
echo ""
