#!/usr/bin/env python3
"""
Tailwind Site Rebuilder Web Application
---------------------------------------
A web interface for analyzing websites and creating blueprints for Tailwind CSS rebuilds.
"""

from flask import Flask, render_template, request, redirect, url_for, flash, jsonify, send_from_directory
import os
import json
import sys
import re
from urllib.parse import urlparse
import threading
import time
from datetime import datetime

# Ensure we can import from our lib directory
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), "lib"))

from analyzer import create_simulation, SiteRebuilder

app = Flask(__name__, static_folder='static', template_folder='templates')
app.secret_key = 'tailwind_rebuilder_secret_key'  # For flash messages

# Add context processor to provide current date to all templates
@app.context_processor
def inject_now():
    return {'now': datetime.now()}

# Directory to store analysis results
SITES_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "sites")
os.makedirs(SITES_DIR, exist_ok=True)

# Track active analyses
active_analyses = {}

def get_domain_from_url(url):
    """Extract a clean domain name from a URL"""
    # Add scheme if missing
    if not url.startswith(('http://', 'https://')):
        url = 'https://' + url
        
    # Parse the URL to get the domain
    parsed_url = urlparse(url)
    domain = parsed_url.netloc
    
    # Remove www. prefix if present
    if domain.startswith('www.'):
        domain = domain[4:]
        
    # Clean domain name to be a valid directory name
    # Replace dots and other invalid characters with underscores
    clean_domain = re.sub(r'[^\w\-]', '_', domain)
    
    return clean_domain, url

def run_analysis(url, domain, session_id):
    """Run the analysis in a separate thread"""
    try:
        active_analyses[session_id] = {
            'url': url,
            'domain': domain,
            'status': 'running',
            'progress': 0,
            'message': 'Starting analysis...',
            'start_time': time.time()
        }
        
        # Update progress
        def update_progress(message, progress):
            active_analyses[session_id]['message'] = message
            active_analyses[session_id]['progress'] = progress
        
        update_progress('Fetching content...', 10)
        
        # Output directory
        output_dir = os.path.join(SITES_DIR, domain)
        
        # Run analysis
        update_progress('Analyzing website...', 30)
        create_simulation(url, output_dir)
        
        update_progress('Processing complete!', 100)
        active_analyses[session_id]['status'] = 'completed'
        active_analyses[session_id]['completion_time'] = time.time()
        active_analyses[session_id]['output_dir'] = output_dir
        
    except Exception as e:
        active_analyses[session_id]['status'] = 'failed'
        active_analyses[session_id]['message'] = f'Error: {str(e)}'
        active_analyses[session_id]['progress'] = 0

@app.route('/')
def index():
    """Home page with URL input form"""
    # Get list of analyzed sites
    analyzed_sites = []
    
    if os.path.exists(SITES_DIR):
        domains = os.listdir(SITES_DIR)
        for domain in domains:
            domain_dir = os.path.join(SITES_DIR, domain)
            if os.path.isdir(domain_dir):
                context_file = os.path.join(domain_dir, 'rebuild_context.json')
                if os.path.exists(context_file):
                    try:
                        with open(context_file, 'r', encoding='utf-8') as f:
                            data = json.load(f)
                            url = data.get('site_info', {}).get('url', '')
                            title = data.get('site_info', {}).get('title', domain)
                            analyzed_at = data.get('site_info', {}).get('analyzed_at', '')
                            
                            analyzed_sites.append({
                                'domain': domain,
                                'url': url,
                                'title': title,
                                'analyzed_at': analyzed_at
                            })
                    except Exception as e:
                        print(f"Error loading context for {domain}: {e}")
    
    # Sort by most recent first
    analyzed_sites.sort(key=lambda x: x.get('analyzed_at', ''), reverse=True)
    
    return render_template('index.html', analyzed_sites=analyzed_sites)

@app.route('/analyze', methods=['POST'])
def analyze():
    """Handle URL submission and start analysis"""
    url = request.form.get('url', '').strip()
    
    if not url:
        flash('Please enter a valid URL', 'error')
        return redirect(url_for('index'))
    
    domain, full_url = get_domain_from_url(url)
    session_id = f"{domain}_{int(time.time())}"
    
    # Start analysis in a separate thread
    analysis_thread = threading.Thread(
        target=run_analysis,
        args=(full_url, domain, session_id)
    )
    analysis_thread.daemon = True
    analysis_thread.start()
    
    return redirect(url_for('analysis_status', session_id=session_id))

@app.route('/analysis_status/<session_id>')
def analysis_status(session_id):
    """Show analysis status and progress"""
    if session_id not in active_analyses:
        flash('Analysis session not found', 'error')
        return redirect(url_for('index'))
    
    analysis = active_analyses[session_id]
    
    if analysis['status'] == 'completed':
        return redirect(url_for('view_results', domain=analysis['domain']))
    
    return render_template('analysis_status.html', analysis=analysis, session_id=session_id)

@app.route('/api/analysis_progress/<session_id>')
def analysis_progress(session_id):
    """API endpoint to get analysis progress for AJAX updates"""
    if session_id not in active_analyses:
        return jsonify({
            'status': 'error',
            'message': 'Analysis session not found'
        }), 404
    
    analysis = active_analyses[session_id]
    return jsonify({
        'status': analysis['status'],
        'progress': analysis['progress'],
        'message': analysis['message'],
        'domain': analysis['domain']
    })

@app.route('/results/<domain>')
def view_results(domain):
    """Show analysis results for a domain"""
    domain_dir = os.path.join(SITES_DIR, domain)
    
    if not os.path.exists(domain_dir):
        flash(f'No analysis found for {domain}', 'error')
        return redirect(url_for('index'))
    
    context_file = os.path.join(domain_dir, 'rebuild_context.json')
    
    if not os.path.exists(context_file):
        flash(f'Analysis results not found for {domain}', 'error')
        return redirect(url_for('index'))
    
    try:
        with open(context_file, 'r', encoding='utf-8') as f:
            context = json.load(f)
        
        # Make sure the images list is available in the context
        if 'images' not in context:
            context['images'] = []
            
            # If we have the old format, convert it
            if 'content' in context and 'images' in context['content']:
                for img in context['content']['images']:
                    if 'local_path' in img and img['local_path']:
                        # Build full URL with absolute path to ensure it works correctly
                        site_url = request.url_root.rstrip('/')
                        img['src'] = f'{site_url}/site_content/{domain}/{img["local_path"]}'
                        context['images'].append(img)
        else:
            # Ensure all image URLs have absolute paths
            site_url = request.url_root.rstrip('/')
            for img in context['images']:
                if 'src' in img and img['src']:
                    # If URL is relative (starts with /), make it absolute
                    if img['src'].startswith('/'):
                        img['src'] = f'{site_url}{img["src"]}'
                    # If URL doesn't have http/https and doesn't start with the site URL, add it
                    elif not img['src'].startswith(('http://', 'https://')):
                        img['src'] = f'{site_url}/{img["src"]}'
        
        return render_template('results.html', 
                               domain=domain, 
                               context=context)
    
    except Exception as e:
        flash(f'Error loading analysis results: {str(e)}', 'error')
        return redirect(url_for('index'))

@app.route('/site_content/<domain>/<path:file_path>')
def site_content(domain, file_path):
    """Serve site content files"""
    # Security check to make sure we're not accessing files outside the domain directory
    if '..' in file_path:
        return "Access denied", 403
    
    # Get the directory from the file_path
    directory = os.path.dirname(file_path)
    filename = os.path.basename(file_path)
    
    return send_from_directory(os.path.join(SITES_DIR, domain, directory), filename)

@app.route('/ai_prompt/<domain>')
def ai_prompt_builder(domain):
    """AI prompt builder interface"""
    domain_dir = os.path.join(SITES_DIR, domain)
    
    if not os.path.exists(domain_dir):
        flash(f'No analysis found for {domain}', 'error')
        return redirect(url_for('index'))
    
    context_file = os.path.join(domain_dir, 'rebuild_context.json')
    
    if not os.path.exists(context_file):
        flash(f'Analysis results not found for {domain}', 'error')
        return redirect(url_for('index'))
    
    try:
        with open(context_file, 'r', encoding='utf-8') as f:
            context = json.load(f)
        
        return render_template('ai_prompt_builder.html', 
                               domain=domain, 
                               context=context)
    
    except Exception as e:
        flash(f'Error loading analysis results: {str(e)}', 'error')
        return redirect(url_for('index'))

@app.route('/website_builder')
def website_builder():
    """Website builder interface - analyze multiple sites and show layout data"""
    return render_template('website_builder.html')

@app.route('/website_builder/analyze', methods=['POST'])
def website_builder_analyze():
    """Handle URL submission for website builder and return layout data"""
    url = request.form.get('url', '').strip()
    
    if not url:
        return jsonify({
            'status': 'error',
            'message': 'Please enter a valid URL'
        }), 400
    
    domain, full_url = get_domain_from_url(url)
    
    # Check if we already have analysis for this domain
    domain_dir = os.path.join(SITES_DIR, domain)
    context_file = os.path.join(domain_dir, 'rebuild_context.json')
    
    if os.path.exists(context_file):
        # Load existing analysis
        try:
            with open(context_file, 'r', encoding='utf-8') as f:
                context = json.load(f)
            
            # Extract just the layout data
            layout_data = {
                'domain': domain,
                'url': context.get('site_info', {}).get('url', full_url),
                'title': context.get('site_info', {}).get('title', domain),
                'layout': {
                    'width': context.get('layout', {}).get('normalized_width', 0),
                    'height': context.get('layout', {}).get('normalized_height', 0),
                    'sections': context.get('layout', {}).get('sections', [])
                },
                'asr': context.get('asr', {}) if 'asr' in context else None
            }
            
            return jsonify({
                'status': 'success',
                'data': layout_data
            })
            
        except Exception as e:
            return jsonify({
                'status': 'error',
                'message': f'Error loading existing analysis: {str(e)}'
            }), 500
    
    else:
        # Need to run new analysis - start it in background
        session_id = f"wb_{domain}_{int(time.time())}"
        
        analysis_thread = threading.Thread(
            target=run_analysis,
            args=(full_url, domain, session_id)
        )
        analysis_thread.daemon = True
        analysis_thread.start()
        
        return jsonify({
            'status': 'analyzing',
            'session_id': session_id,
            'domain': domain,
            'url': full_url,
            'message': 'Starting analysis...'
        })

@app.route('/api/website_builder_progress/<session_id>')
def website_builder_progress(session_id):
    """API endpoint to get analysis progress for website builder"""
    if session_id not in active_analyses:
        return jsonify({
            'status': 'error',
            'message': 'Analysis session not found'
        }), 404
    
    analysis = active_analyses[session_id]
    
    if analysis['status'] == 'completed':
        # Analysis is done, return the layout data
        domain = analysis['domain']
        domain_dir = os.path.join(SITES_DIR, domain)
        context_file = os.path.join(domain_dir, 'rebuild_context.json')
        
        try:
            with open(context_file, 'r', encoding='utf-8') as f:
                context = json.load(f)
            
            # Extract just the layout data
            layout_data = {
                'domain': domain,
                'url': context.get('site_info', {}).get('url', analysis['url']),
                'title': context.get('site_info', {}).get('title', domain),
                'layout': {
                    'width': context.get('layout', {}).get('normalized_width', 0),
                    'height': context.get('layout', {}).get('normalized_height', 0),
                    'sections': context.get('layout', {}).get('sections', [])
                },
                'asr': context.get('asr', {}) if 'asr' in context else None
            }
            
            return jsonify({
                'status': 'completed',
                'data': layout_data
            })
            
        except Exception as e:
            return jsonify({
                'status': 'error',
                'message': f'Error loading analysis results: {str(e)}'
            }), 500
    
    else:
        # Still analyzing or failed
        return jsonify({
            'status': analysis['status'],
            'progress': analysis['progress'],
            'message': analysis['message']
        })

@app.route('/api/generate_prompt', methods=['POST'])
def generate_prompt():
    """Generate an AI prompt based on selected elements"""
    data = request.json
    domain = data.get('domain', '')
    selected_elements = data.get('selected_elements', [])
    
    if not domain or not selected_elements:
        return jsonify({
            'status': 'error',
            'message': 'Missing required data'
        }), 400
    
    domain_dir = os.path.join(SITES_DIR, domain)
    context_file = os.path.join(domain_dir, 'rebuild_context.json')
    
    if not os.path.exists(context_file):
        return jsonify({
            'status': 'error',
            'message': 'Analysis results not found'
        }), 404
    
    try:
        with open(context_file, 'r', encoding='utf-8') as f:
            context = json.load(f)
        
        # Build prompt based on selected elements
        prompt = f"Create a Tailwind CSS implementation of a website similar to {context['site_info']['url']}.\n\n"
        
        # Add layout information
        if 'layout' in selected_elements:
            prompt += "## Layout\n"
            prompt += f"- Overall width: {context['layout']['normalized_width']}px\n"
            prompt += f"- Use a responsive design with Tailwind's container class\n"
            
            # Add sections if selected
            if 'sections' in selected_elements:
                prompt += "- Include these sections:\n"
                for section in context['layout']['sections']:
                    prompt += f"  * {section['type']}: {section['content_preview']}\n"
            
            prompt += "\n"
        
        # Add color scheme if selected
        if 'colors' in selected_elements:
            prompt += "## Colors\n"
            prompt += "Use this color scheme:\n"
            colors = context['design']['colors']
            
            # Background colors
            prompt += "- Background colors:\n"
            for color in colors['background'][:3]:  # Limit to top 3
                prompt += f"  * {color}\n"
                
            # Text colors
            prompt += "- Text colors:\n"
            for color in colors['text'][:3]:  # Limit to top 3
                prompt += f"  * {color}\n"
                
            # Accent colors
            prompt += "- Accent colors:\n"
            for color in colors['accent'][:3]:  # Limit to top 3
                prompt += f"  * {color}\n"
                
            prompt += "\n"
        
        # Add typography if selected
        if 'typography' in selected_elements:
            prompt += "## Typography\n"
            typography = context['design']['typography']
            
            if typography['fonts']:
                prompt += f"- Font family: {typography['fonts'][0]}\n"
            
            prompt += "- Heading styles:\n"
            for heading, style in typography['headings'].items():
                size = style.get('fontSize', 'default')
                weight = style.get('fontWeight', 'default')
                prompt += f"  * {heading}: {size}, {weight}\n"
                
            prompt += f"- Body text: {typography['body']['paragraph']['fontSize']} {typography['body']['paragraph']['fontWeight']}\n\n"
        
        # Add specific content if selected
        if 'content' in context and 'content' in selected_elements:
            prompt += "## Content\n"
            
            # Add text content references
            if 'text' in context['content'] and 'text' in selected_elements:
                prompt += "- Include these text elements:\n"
                
                # Add headings
                if 'headings' in context['content']['text']:
                    headings = context['content']['text']['headings']
                    for level in range(1, 4):  # Just show h1-h3
                        key = f'h{level}'
                        if key in headings and headings[key]:
                            prompt += f"  * {key}: {headings[key][0]}\n"
                
                # Add navigation items
                if 'navigation' in context['content']['text']:
                    prompt += "  * Navigation items: "
                    nav_items = [item['text'] for item in context['content']['text']['navigation'][:5]]
                    prompt += ", ".join(nav_items)
                    prompt += "\n"
                    
                prompt += "\n"
            
            # Add image references
            if 'images' in context['content'] and 'images' in selected_elements:
                prompt += "- Include placeholder images with these dimensions and contexts:\n"
                
                # Get a subset of images to keep the prompt manageable
                image_sample = context['content']['images'][:5]
                
                for img in image_sample:
                    img_type = img.get('type', 'regular')
                    context_info = ""
                    
                    if img_type == 'regular':
                        context_info = f"alt: '{img.get('alt', '')}'"
                        if 'parent_tag' in img:
                            context_info += f", in {img.get('parent_tag', 'div')}"
                    else:
                        context_info = f"background image in {img.get('element', 'div')}"
                        
                    prompt += f"  * {img_type} image: {context_info}\n"
                    
                prompt += "\n"
            
            # Add direct image references if available in context
            if 'images' in context and 'images' in selected_elements:
                prompt += "- Use these images (access or save them from these URLs):\n"
                
                # Get a subset of images to keep the prompt manageable
                image_sample = context['images'][:5] if len(context['images']) > 5 else context['images']
                
                for idx, img in enumerate(image_sample):
                    img_type = img.get('type', 'regular')
                    img_alt = img.get('alt', f'Image {idx+1}')
                    img_src = img.get('src', '')
                    
                    prompt += f"  * {img_type} image: {img_src}\n"
                    prompt += f"    Alt text: \"{img_alt}\"\n"
                    
                if len(context['images']) > 5:
                    prompt += f"  * Plus {len(context['images']) - 5} more images available\n"
                    
                prompt += "\n"
        
        # Add implementation notes
        prompt += "## Implementation Notes\n"
        prompt += "- Use Tailwind CSS utility classes for all styling\n"
        prompt += "- Make the design fully responsive using Tailwind's responsive prefixes\n"
        prompt += "- Implement a mobile-friendly navigation that collapses on smaller screens\n"
        prompt += "- Use semantic HTML5 elements for proper document structure\n"
        
        return jsonify({
            'status': 'success',
            'prompt': prompt
        })
    
    except Exception as e:
        return jsonify({
            'status': 'error',
            'message': f'Error generating prompt: {str(e)}'
        }), 500

if __name__ == '__main__':
    port = int(os.environ.get('PORT', 5000))
    app.run(host='0.0.0.0', port=port, debug=True) 