import gradio as gr
import json
from datetime import datetime
from datasets import Dataset
from huggingface_hub import login, HfApi
import pandas as pd
import os
import time
import tempfile
import logging
# Setup logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# Authenticate with Hugging Face
HF_TOKEN = os.environ.get("HF_TOKEN")
if HF_TOKEN:
    login(token=HF_TOKEN)
    logger.info("✅ Authenticated with Hugging Face")
else:
    logger.warning("⚠️ HF_TOKEN not found - running without authentication")
    
# Replace with your actual dataset name for Winter 2025
DATASET_NAME = "ysharma/gradio-hackathon-registrations-winter-2025"
COUNTER = """
    
    
    Hackathon Countdown
    
    
        Countdown to the Global Event Has Begun. Registrations are now open!
        
     
    
"""
def safe_add_to_dataset(registration_data, max_retries=5, retry_delay=3):
    """
    Safely add new registration data with bulletproof error handling
    NEVER creates new datasets - only adds to existing ones
    """
    try:
        logger.info("Starting new registration process")
        
        # Create new row with updated fields
        new_row = {
            "timestamp": registration_data["timestamp"],
            "full_name": registration_data["personal_info"]["full_name"],
            "email": registration_data["personal_info"]["email"],
            "hf_username": registration_data["personal_info"]["hf_username"],
            "gradio_usage": registration_data["personal_info"]["gradio_usage"],
            "track_interest": str(registration_data["participation"]["track_interest"]),
            "previous_participation": registration_data["participation"]["previous_participation"],
            "experience_level": registration_data["participation"]["experience_level"],
            "how_heard": registration_data["participation"]["how_heard"],
            "project_description": registration_data["additional"]["project_description"] or "",
        }
        
        logger.info("Created new row data")
        
        # Multi-attempt loading with different strategies
        existing_df = None
        load_successful = False
        
        for attempt in range(max_retries):
            logger.info(f"Loading attempt {attempt + 1}/{max_retries}")
            
            try:
                # Strategy 1: Direct parquet file access (most reliable)
                api = HfApi()
                files = api.list_repo_files(DATASET_NAME, repo_type="dataset")
                
                parquet_files = [f for f in files if f.endswith('.parquet') and 'train' in f]
                
                if parquet_files:
                    logger.info(f"Found parquet file: {parquet_files[0]}")
                    
                    # Download to temporary location
                    with tempfile.TemporaryDirectory() as temp_dir:
                        parquet_file = api.hf_hub_download(
                            repo_id=DATASET_NAME,
                            filename=parquet_files[0],
                            repo_type="dataset",
                            cache_dir=temp_dir,
                            force_download=True
                        )
                        
                        existing_df = pd.read_parquet(parquet_file)
                        logger.info(f"Successfully loaded {len(existing_df)} existing rows")
                        load_successful = True
                        break
                        
                else:
                    logger.warning("No parquet files found")
                    
            except Exception as load_error:
                logger.warning(f"Attempt {attempt + 1} failed: {str(load_error)[:100]}")
                
                if attempt < max_retries - 1:
                    logger.info(f"Waiting {retry_delay} seconds before retry...")
                    time.sleep(retry_delay)
                    continue
        
        # CRITICAL SAFETY CHECK: Never proceed without existing data
        if not load_successful or existing_df is None:
            error_msg = "🚨 CRITICAL SAFETY ERROR: Could not load existing dataset after multiple attempts."
            logger.error(error_msg)
            logger.error("🚨 REFUSING to proceed to prevent data loss!")
            logger.error("🚨 Please check dataset manually or contact administrators.")
            
            return False, (
                "❌ Registration temporarily unavailable due to technical issues. "
                "Please try again in a few minutes. If the problem persists, contact support."
            )
        
        # Check for duplicates
        duplicate_check = existing_df[
            (existing_df['email'].str.lower() == new_row['email'].lower()) | 
            (existing_df['hf_username'].str.lower() == new_row['hf_username'].lower())
        ]
        
        if len(duplicate_check) > 0:
            logger.warning("Duplicate registration attempt detected")
            return False, "❌ Error: This email or Hugging Face username is already registered."
        
        # Add new row safely
        combined_df = pd.concat([existing_df, pd.DataFrame([new_row])], ignore_index=True)
        logger.info(f"Combined data now has {len(combined_df)} rows (was {len(existing_df)})")
        
        # Create timestamped backup before upload
        backup_timestamp = int(time.time())
        
        try:
            # Convert to Dataset and upload
            logger.info("Converting to HuggingFace Dataset format...")
            updated_dataset = Dataset.from_pandas(combined_df)
            
            # Create backup first
            backup_name = f"{DATASET_NAME}-auto-backup-{backup_timestamp}"
            logger.info(f"Creating backup: {backup_name}")
            updated_dataset.push_to_hub(backup_name, private=True)
            
            logger.info("Pushing to main dataset...")
            updated_dataset.push_to_hub(DATASET_NAME, private=True)
            
            logger.info("✅ Successfully saved new registration")
            logger.info(f"Total rows in dataset: {len(combined_df)}")
            
            # Quick verification
            time.sleep(2)
            try:
                verify_files = api.list_repo_files(DATASET_NAME, repo_type="dataset")
                logger.info("✅ Upload verification: Files updated successfully")
            except:
                logger.warning("⚠️  Could not verify upload (this may be normal)")
            
            return True, "Registration successful!"
            
        except Exception as upload_error:
            error_msg = str(upload_error).lower()
            if any(indicator in error_msg for indicator in ['rate limit', '429', 'too many requests']):
                logger.warning("🚨 Rate limit hit - registration system temporarily busy")
                return False, "⏳ Registration temporarily unavailable due to high server load. Please try again in 10-15 minutes."
            else:
                logger.error(f"Upload failed: {upload_error}")
                return False, f"❌ Registration failed during upload: {str(upload_error)}"
        
    except Exception as e:
        logger.error(f"❌ Unexpected error in registration: {e}")
        import traceback
        traceback.print_exc()
        return False, f"❌ Registration failed: {str(e)}"
def submit_registration(full_name, email, hf_username, gradio_usage,
                        track_interest, previous_participation, experience_level, how_heard,
                        acknowledgment, project_description):
    """Process the registration form submission with enhanced validation"""
    
    # Enhanced validation
    if not full_name or not full_name.strip():
        return "❌ Error: Please enter your full name"
    
    if not email or not email.strip():
        return "❌ Error: Please enter your email address"
    
    if not hf_username or not hf_username.strip():
        return "❌ Error: Please enter your Hugging Face username"
    
    if not gradio_usage:
        return "❌ Error: Please select how you're currently using Gradio"
    
    if not track_interest:
        return "❌ Error: Please select at least one track of interest"
    
    if not previous_participation:
        return "❌ Error: Please select your hackathon experience"
    
    if not experience_level:
        return "❌ Error: Please select your experience level"
    
    if not how_heard:
        return "❌ Error: Please select how you heard about this hackathon"
        
    if not acknowledgment:
        return "❌ Error: Please confirm your acknowledgment to participate"
    
    # Email format validation
    import re
    email_pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
    if not re.match(email_pattern, email.strip()):
        return "❌ Error: Please enter a valid email address"
    
    # Process the registration data
    registration_data = {
        "timestamp": datetime.now().isoformat(),
        "personal_info": {
            "full_name": full_name.strip(),
            "email": email.strip().lower(),
            "hf_username": hf_username.strip(),
            "gradio_usage": gradio_usage,
        },
        "participation": {
            "track_interest": track_interest,
            "previous_participation": previous_participation,
            "experience_level": experience_level,
            "how_heard": how_heard,
        },
        "additional": {
            "project_description": project_description.strip() if project_description else None,
        }
    }
    
    # Save to Hugging Face dataset with bulletproof error handling
    success, message = safe_add_to_dataset(registration_data)
    
    if not success:
        return f"❌ Registration failed: {message}"
    
    return f"""✅ Registration Successful!
    
Thank you, {full_name}! Your registration has been received and saved.
📧 You will receive information about API credits as we finalize sponsor partnerships.
🔑 API and Compute credits will be distributed before or during the Hackathon starting date.
💬 Be sure to **join the Huggingface organization** for regular updates on the hackathon and **to submit your entries**. Join our Discord community channel `agents-mcp-hackathon-winter25🏆` for updates and support during the event: https://discord.gg/YgswRqxQ
**See you at the hackathon! 🚀**"""
# Health check function
def check_dataset_health():
    """Check if the dataset is accessible and healthy"""
    try:
        api = HfApi()
        files = api.list_repo_files(DATASET_NAME, repo_type="dataset")
        parquet_files = [f for f in files if f.endswith('.parquet')]
        
        if parquet_files:
            logger.info(f"✅ Dataset health check passed - found {len(parquet_files)} parquet files")
            return True
        else:
            logger.warning("⚠️  Dataset health check: No parquet files found")
            return False
    except Exception as e:
        logger.error(f"❌ Dataset health check failed: {e}")
        return False
# Initialize with health check
logger.info("🚀 Starting Gradio Hackathon Registration System - Winter 2025")
logger.info(f"📊 Dataset: {DATASET_NAME}")
if check_dataset_health():
    logger.info("✅ System ready - dataset is healthy")
else:
    logger.warning("⚠️  System starting with dataset health warnings")
# Custom CSS for gradient theme
custom_css = """
.gradio-container {
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
}
.header-gradient {
    background: linear-gradient(135deg, #0a0a0a 0%, #FF7A00 35%, #4A90E2 70%, #ffffff 100%);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
}
/* Gradient Submit Button Styling */
#gradient-submit-btn {
    background: linear-gradient(135deg, #0a0a0a 0%, #FF7A00 35%, #4A90E2 70%, #ffffff 100%) !important;
    border: none !important;
    color: white !important;
    font-weight: 600 !important;
    font-size: 18px !important;
    padding: 16px 32px !important;
    border-radius: 12px !important;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15) !important;
    transition: all 0.3s ease !important;
    text-transform: none !important;
}
#gradient-submit-btn:hover {
    transform: translateY(-2px) !important;
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.25) !important;
}
#gradient-submit-btn:active {
    transform: translateY(0px) !important;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2) !important;
}
/* Disabled state for the button */
#gradient-submit-btn:disabled {
    opacity: 0.6 !important;
    cursor: not-allowed !important;
    transform: none !important;
}
"""
# Create the Gradio interface
with gr.Blocks(title="Gradio Agents & MCP Hackathon - Winter 2025", css=custom_css, theme="ocean") as demo:
    # Header
    gr.Markdown("""
    # 🤖 Gradio Agents & MCP Hackathon - Winter 2025 Registration 🚀
    **Join our [Discord Community](https://discord.gg/YgswRqxQ) channel `agents-mcp-hackathon-winter25🏆` for active support during the hackathon.**
    **NOTE: If the registration app says you are registered, then that information is correct and you don't need to send us anything else. NO CONFIRMATION EMAILS ARE SENT FROM OUR SIDE.**
    
    **📅 Event Dates:** November 14-30, 2025 (17 days, 3 weekends) | **🏆 Prizes: $15,000+ USD in cash prizes** | **💻 Location:** Online & Global
    
    **🎁 FREE API & Compute Credits** (Details announced soon):
    - API credits from major AI providers
    - Access to latest and strongest LLMs
    - Compute resources for building your projects
    
    **The definitive Agents & MCP event is back!** OpenAI, Microsoft, Google DeepMind, and numerous startups have already adopted MCP. Join the community that launched the MCP developer movement. Participate and stand a chance to learn the latest AI technologies and also Win BIG!
    """)
    gr.HTML(COUNTER)
    gr.Markdown("---")
    
    with gr.Row():
        with gr.Column():
            # Personal Information Section
            gr.Markdown("## 1. Personal Information")
            
            full_name = gr.Textbox(
                label="Full Name *",
                placeholder="Your full name as you'd like it on certificates",
                max_lines=1
            )
            
            email = gr.Textbox(
                label="Email Address *",
                placeholder="Primary contact email (we'll send important updates here)",
                max_lines=1
            )
            
            hf_username = gr.Textbox(
                label="Hugging Face Username *",
                placeholder="Required for organization access and submissions",
                max_lines=1
            )
            
            # NEW: Gradio Usage Question
            gradio_usage = gr.Radio(
                label="How are you currently using Gradio? *",
                choices=[
                    "Professional work - My company uses Gradio",
                    "Personal projects - Building side projects",
                    "Academic/Research - University or research work",
                    "Learning - New to Gradio, want to learn",
                    "Not using yet - Interested to start"
                ],
                info="Helps us understand our community better"
            )
        
        with gr.Column():
            # Hackathon Participation Section
            gr.Markdown("## 2. Hackathon Participation")
            
            track_interest = gr.CheckboxGroup(
                label="Which track interests you most? *",
                choices=[
                    "Track 1: MCP Tools & Servers",
                    "Track 2: Agentic Applications", 
                ]
            )
            
            # NEW: Previous participation
            previous_participation = gr.Radio(
                label="Hackathon experience *",
                choices=[
                    "I participated in June 2025 Agents & MCP Hackathon",
                    "I've done other AI hackathons before",
                    "This is my first AI hackathon"
                ]
            )
            
            # NEW: Experience level
            experience_level = gr.Radio(
                label="Your experience with AI/Agents development *",
                choices=[
                    "Beginner - New to AI development",
                    "Intermediate - Some AI projects", 
                    "Advanced - Regular AI developer",
                    "Expert - Professional AI engineer"
                ]
            )
            
            # NEW: How they heard about it
            how_heard = gr.Dropdown(
                label="How did you hear about this hackathon? *",
                choices=[
                    "Hugging Face email/newsletter",
                    "Twitter/X",
                    "LinkedIn", 
                    "Discord",
                    "From a colleague/friend",
                    "YouTube",
                    "Reddit",
                    "Sponsor announcement",
                    "I participated in June 2025",
                    "Other"
                ]
            )
        
    with gr.Row():
        with gr.Column():
            # Additional Information Section
            gr.Markdown("## 3. Additional Information")
            
            project_description = gr.Textbox(
                label="What type of project are you most excited to build?",
                placeholder="Brief description of your project idea or what interests you most",
                lines=3
            )
        with gr.Column():
            # Acknowledgment Section
            gr.Markdown("## 4. Acknowledgment")
            
            acknowledgment = gr.Checkbox(
                label="Acknowledgment *",
                info="""I commit to actively participate and submit a project by November 30, 2025. I understand that API/compute credits are provided to support hackathon participation and should be used for building my hackathon project. I commit to using these credits responsibly during the event period.""",
            )
        
    # Submit button
    submit_btn = gr.Button("🚀 Register for Hackathon", variant="primary", size="lg", elem_id="gradient-submit-btn")
    
    # Output
    output = gr.Markdown()
        
    # Enhanced submit function
    def handle_registration_with_state(*args):
        try:
            result = submit_registration(*args)
            return result, gr.Button("🚀 Register for Hackathon", interactive=True, variant="primary")
        except Exception as e:
            logger.error(f"Registration handling error: {e}")
            return f"❌ An unexpected error occurred: {str(e)}", gr.Button("🚀 Register for Hackathon", interactive=True, variant="primary")
    
    # Click event with updated inputs
    submit_btn.click(
        fn=lambda *args: (gr.Button("⏳ Processing Registration...", interactive=False, variant="secondary"), ""),
        inputs=[
            full_name, email, hf_username, gradio_usage,
            track_interest, previous_participation, experience_level, how_heard,
            acknowledgment, project_description,
        ],
        outputs=[submit_btn, output],
        queue=False
    ).then(
        fn=handle_registration_with_state,
        inputs=[
            full_name, email, hf_username, gradio_usage,
            track_interest, previous_participation, experience_level, how_heard,
            acknowledgment, project_description,
        ],
        outputs=[output, submit_btn],
        queue=True
    )
    # Footer
    gr.Markdown("""    
    **Questions?** Join Huggingface [Discord](https://discord.gg/fveShqytyh) or email: gradio-team@huggingface.co
    """)
if __name__ == "__main__":
    demo.launch(allowed_paths=["."])