#!/usr/bin/env python3
"""
Simple Report Visualizer
View content evaluation reports with images side-by-side
"""

import os
import json
import glob
import zipfile
import uuid
import shutil
import sys
from datetime import datetime
from flask import Flask, render_template, jsonify, send_file, request, flash, redirect, url_for
from werkzeug.utils import secure_filename
from pathlib import Path

# Load environment variables
try:
    from dotenv import load_dotenv
    load_dotenv()
    print("✅ Environment variables loaded from .env file")
except ImportError:
    print("⚠️  python-dotenv not available, using system environment variables only")

# Add src to path for imports
sys.path.insert(0, 'src')

app = Flask(__name__)
app.config['SECRET_KEY'] = os.getenv('SECRET_KEY', 'your-secret-key-change-in-production')
app.config['MAX_CONTENT_LENGTH'] = 50 * 1024 * 1024  # 50MB max file size
app.config['UPLOAD_FOLDER'] = 'uploads'
app.config['PROCESSED_FOLDER'] = 'processed'

# Ensure directories exist
os.makedirs('uploads', exist_ok=True)
os.makedirs('processed', exist_ok=True)
os.makedirs('reviews', exist_ok=True)
os.makedirs('templates', exist_ok=True)
os.makedirs('batch_images', exist_ok=True)  # Persistent storage for batch images

# Import content evaluation modules
try:
    from src.content_evaluator import ContentEvaluator
    from src.report_generator import ReportGenerator
    EVALUATOR_AVAILABLE = True
except ImportError as e:
    print(f"⚠️  Content evaluator not available: {e}")
    EVALUATOR_AVAILABLE = False

# Import Facebook Ad Library client
try:
    from src.facebook_ad_client import create_facebook_client
    FACEBOOK_CLIENT_AVAILABLE = True
    print("✅ Facebook Ad Library client available")
except ImportError as e:
    print(f"⚠️  Facebook Ad Library client not available: {e}")
    FACEBOOK_CLIENT_AVAILABLE = False

ALLOWED_EXTENSIONS = {'zip'}
IMAGE_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif', 'bmp', 'webp'}
VIDEO_EXTENSIONS = {'mp4', 'avi', 'mov', 'mkv', 'webm', 'm4v'}

def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

def is_image_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in IMAGE_EXTENSIONS

def is_video_file_ext(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in VIDEO_EXTENSIONS

def is_media_file(filename):
    return is_image_file(filename) or is_video_file_ext(filename)

def get_available_reports():
    """Get all JSON reports from reviews directory"""
    reports = []
    reviews_dir = Path("reviews")

    if reviews_dir.exists():
        for json_file in reviews_dir.glob("*.json"):
            try:
                with open(json_file, 'r') as f:
                    data = json.load(f)

                # Extract basic info
                if 'evaluation_report' in data:
                    report_data = data['evaluation_report']
                elif 'detailed_evaluation_report' in data:
                    report_data = data['detailed_evaluation_report']
                else:
                    continue

                reports.append({
                    'filename': json_file.name,
                    'path': str(json_file),
                    'timestamp': report_data.get('timestamp', 'Unknown'),
                    'total_images': len(report_data.get('results', [])),
                    'approved': report_data.get('summary', {}).get('approved', 0),
                    'rejected': report_data.get('summary', {}).get('rejected', 0)
                })
            except Exception as e:
                print(f"Error reading {json_file}: {e}")

    return sorted(reports, key=lambda x: x['timestamp'], reverse=True)

@app.route('/')
def index():
    """Main page with report selection"""
    reports = get_available_reports()
    return render_template('ez_viewer.html', reports=reports)

@app.route('/api/report/<filename>')
def get_report(filename):
    """Get report data"""
    filepath = Path("reviews") / filename

    if not filepath.exists():
        return jsonify({'error': 'Report not found'}), 404

    try:
        with open(filepath, 'r') as f:
            data = json.load(f)

        # Normalize the data structure
        if 'evaluation_report' in data:
            report_data = data['evaluation_report']
        elif 'detailed_evaluation_report' in data:
            report_data = data['detailed_evaluation_report']
        else:
            return jsonify({'error': 'Invalid report format'}), 400

        return jsonify(report_data)
    except Exception as e:
        return jsonify({'error': str(e)}), 500

@app.route('/api/image/<path:image_path>')
def serve_image(image_path):
    """Serve image files"""
    import urllib.parse

    # Decode URL encoding
    decoded_path = urllib.parse.unquote(image_path)
    safe_path = Path(decoded_path)

    # If it's already an absolute path that exists, use it
    if safe_path.is_absolute() and safe_path.exists() and safe_path.is_file():
        return send_file(safe_path)

    # If it's a relative path, make it absolute from current working directory
    if not safe_path.is_absolute():
        absolute_path = Path.cwd() / safe_path
        if absolute_path.exists() and absolute_path.is_file():
            return send_file(absolute_path)

    # Try common image directories with absolute paths
    base_dir = Path.cwd()
    possible_paths = [
        base_dir / "examples/images" / safe_path.name,
        base_dir / "images" / safe_path.name,
        base_dir / "batch_images" / safe_path.parent.name / safe_path.name if len(safe_path.parts) > 1 else None,
        base_dir / safe_path.name if not safe_path.is_absolute() else safe_path
    ]

    # Remove None values
    possible_paths = [p for p in possible_paths if p is not None]

    for path in possible_paths:
        if path.exists() and path.is_file():
            return send_file(path)

    return f"Image not found: {decoded_path}", 404

@app.route('/api/batch_image/<session_id>/<filename>')
def serve_batch_image(session_id, filename):
    """Serve images from batch processing"""
    batch_dir = Path('batch_images') / session_id
    image_path = batch_dir / filename

    if image_path.exists() and image_path.is_file():
        return send_file(image_path)

    return f"Batch image not found: {session_id}/{filename}", 404

@app.route('/upload', methods=['GET', 'POST'])
def upload_zip():
    """Handle zip file upload and processing"""
    if request.method == 'GET':
        return render_template('upload.html')

    if 'zipfile' not in request.files:
        flash('No file selected')
        return redirect(request.url)

    file = request.files['zipfile']
    if file.filename == '':
        flash('No file selected')
        return redirect(request.url)

    if file and allowed_file(file.filename):
        # Create unique session ID
        session_id = str(uuid.uuid4())
        session_dir = Path(app.config['PROCESSED_FOLDER']) / session_id
        session_dir.mkdir(parents=True, exist_ok=True)

        # Save zip file
        filename = secure_filename(file.filename)
        zip_path = Path(app.config['UPLOAD_FOLDER']) / f"{session_id}_{filename}"
        file.save(zip_path)

        try:
            # Create batch directory for permanent image storage
            batch_dir = Path('batch_images') / session_id
            batch_dir.mkdir(parents=True, exist_ok=True)

            # Extract zip file to temporary location first
            temp_extract_dir = session_dir / 'temp'
            with zipfile.ZipFile(zip_path, 'r') as zip_ref:
                zip_ref.extractall(temp_extract_dir)

            # Find and copy image files to permanent location
            image_files = []
            processed_files = set()  # Track processed files to avoid duplicates
            image_counter = 1

            print(f"🔍 Scanning extracted files in {temp_extract_dir}")

            for root, dirs, files in os.walk(temp_extract_dir):
                print(f"   Checking directory: {root}")
                for file in files:
                    source_path = Path(root) / file

                    # Skip if already processed (avoid duplicates)
                    if str(source_path) in processed_files:
                        continue

                    if is_media_file(file):
                        media_type = "video" if is_video_file_ext(file) else "image"
                        print(f"   Found {media_type}: {file}")

                        # Create unique filename to avoid conflicts
                        file_ext = Path(file).suffix.lower()
                        prefix = "video" if media_type == "video" else "image"
                        safe_filename = f"{prefix}_{image_counter:03d}{file_ext}"
                        dest_path = batch_dir / safe_filename

                        try:
                            # Verify source file exists and is readable
                            if not source_path.exists():
                                print(f"   ⚠️  Source file doesn't exist: {source_path}")
                                continue

                            # Check file size (skip empty files)
                            if source_path.stat().st_size == 0:
                                print(f"   ⚠️  Empty file skipped: {file}")
                                continue

                            # Validate file based on type
                            if media_type == "image":
                                # Try to open with PIL to verify it's a valid image
                                from PIL import Image
                                with Image.open(source_path) as test_img:
                                    test_img.verify()
                            elif media_type == "video":
                                # Basic video validation - try to open with OpenCV
                                import cv2
                                cap = cv2.VideoCapture(str(source_path))
                                if not cap.isOpened():
                                    raise Exception("Cannot open video file")
                                cap.release()

                            # Copy file to permanent location
                            shutil.copy2(source_path, dest_path)
                            print(f"   ✅ Copied to: {safe_filename}")

                            image_files.append(dest_path)
                            processed_files.add(str(source_path))
                            image_counter += 1

                        except Exception as e:
                            print(f"   ❌ Failed to process {file}: {e}")
                            continue

            # Clean up temporary extraction
            shutil.rmtree(temp_extract_dir, ignore_errors=True)

            print(f"📊 Extraction complete: {len(image_files)} valid images found")

            if not image_files:
                flash('No valid image files found in the zip archive')
                return redirect(url_for('upload_zip'))

            # Process images if evaluator is available
            if EVALUATOR_AVAILABLE:
                try:
                    # Initialize evaluator
                    evaluator = ContentEvaluator('config/suno_guidelines.txt')
                    report_generator = ReportGenerator()

                    # Process images with better error handling
                    results = []
                    print(f"🔄 Processing {len(image_files)} images...")

                    for i, img_path in enumerate(image_files, 1):
                        print(f"   Processing {i}/{len(image_files)}: {img_path.name}")

                        try:
                            # Double-check file exists before processing
                            if not img_path.exists():
                                print(f"   ⚠️  File missing, skipping: {img_path}")
                                continue

                            # Determine if it's a video or image
                            if is_video_file_ext(img_path.name):
                                print(f"   🎬 Processing video: {img_path.name}")
                                result = evaluator.evaluate_video(str(img_path))
                            else:
                                print(f"   🖼️  Processing image: {img_path.name}")
                                result = evaluator.evaluate_image(str(img_path))

                            if result and not result.get('error'):
                                results.append(result)
                                print(f"   ✅ Processed successfully")
                            else:
                                print(f"   ⚠️  Evaluation failed: {result.get('error', 'Unknown error')}")

                        except Exception as e:
                            print(f"   ❌ Error processing {img_path.name}: {e}")
                            continue

                    if results:
                        # Generate summary and report
                        summary = evaluator.generate_summary(results)
                        report_json = report_generator.generate_json_report(results, summary)

                        # Save report with session ID
                        report_filename = f"batch_evaluation_{session_id[:8]}.json"
                        report_path = report_generator.save_report(report_json, f'reviews/{report_filename}')

                        flash(f'Successfully processed {len(results)} out of {len(image_files)} images. Report saved as {report_filename}')
                        return redirect(url_for('view_session', session_id=session_id, report_file=report_filename))
                    else:
                        flash('No images could be processed')
                        return redirect(url_for('upload_zip'))

                except Exception as e:
                    flash(f'Error processing images: {str(e)}')
                    return redirect(url_for('upload_zip'))
            else:
                # If evaluator not available, just show uploaded images
                flash(f'Uploaded {len(image_files)} images (evaluation not available)')
                return redirect(url_for('view_session', session_id=session_id))

        except Exception as e:
            flash(f'Error processing zip file: {str(e)}')
            return redirect(url_for('upload_zip'))
        finally:
            # Clean up zip file
            if zip_path.exists():
                zip_path.unlink()
    else:
        flash('Please upload a valid ZIP file')
        return redirect(url_for('upload_zip'))

@app.route('/session/<session_id>')
def view_session(session_id):
    """View processed session images"""
    session_dir = Path(app.config['PROCESSED_FOLDER']) / session_id

    if not session_dir.exists():
        flash('Session not found')
        return redirect(url_for('index'))

    # Get report file if specified
    report_file = request.args.get('report_file')

    # Find media files in batch storage
    media_files = []
    batch_dir = Path('batch_images') / session_id
    if batch_dir.exists():
        for file_path in batch_dir.glob('*'):
            if file_path.is_file() and is_media_file(file_path.name):
                media_type = "video" if is_video_file_ext(file_path.name) else "image"
                media_files.append({
                    'name': file_path.name,
                    'path': f"{session_id}/{file_path.name}",
                    'full_path': str(file_path),
                    'batch_path': file_path.name,
                    'type': media_type
                })

    return render_template('session_view.html',
                         session_id=session_id,
                         images=media_files,  # Now includes both images and videos
                         report_file=report_file)

@app.route('/api/session_image/<session_id>/<path:image_path>')
def serve_session_image(session_id, image_path):
    """Serve images from a processing session"""
    import urllib.parse

    # Decode URL encoding
    decoded_path = urllib.parse.unquote(image_path)
    session_dir = Path(app.config['PROCESSED_FOLDER']) / session_id
    full_path = session_dir / decoded_path

    # Make sure path is absolute and exists
    absolute_path = full_path.resolve()
    if absolute_path.exists() and absolute_path.is_file():
        return send_file(absolute_path)

    return f"Session image not found: {decoded_path}", 404

@app.route('/facebook-ads')
def facebook_ads():
    """Facebook Ads search interface"""
    if not FACEBOOK_CLIENT_AVAILABLE:
        flash('Facebook Ad Library integration not available. Please check configuration.')
        return redirect(url_for('index'))

    return render_template('facebook_ads.html')

@app.route('/facebook-ads/search', methods=['POST'])
def search_facebook_ads():
    """Handle Facebook ads search request"""
    if not FACEBOOK_CLIENT_AVAILABLE:
        return jsonify({'error': 'Facebook Ad Library integration not available'}), 400

    try:
        # Get search parameters from form
        search_terms = request.form.get('search_terms', '').strip()
        country = request.form.get('country', 'US')
        ad_type = request.form.get('ad_type', 'ALL')
        media_type = request.form.get('media_type', 'ALL')
        start_date = request.form.get('start_date')
        end_date = request.form.get('end_date')
        limit = min(int(request.form.get('limit', 50)), 100)  # Cap at 100 for UI

        print(f"🔍 Facebook ad search request:")
        print(f"   Terms: {search_terms or 'Any'}")
        print(f"   Country: {country}")
        print(f"   Limit: {limit}")

        # Create Facebook client
        fb_client = create_facebook_client()

        # Test connection first
        connection_test = fb_client.test_connection()
        if not connection_test.get('success'):
            return jsonify({
                'error': 'Facebook API connection failed',
                'details': connection_test.get('error', 'Unknown error')
            }), 400

        # Search for ads
        search_results = fb_client.search_ads(
            search_terms=search_terms if search_terms else None,
            ad_reached_countries=country,
            ad_type=ad_type,
            media_type=media_type,
            start_date=start_date if start_date else None,
            end_date=end_date if end_date else None,
            limit=limit
        )

        if 'error' in search_results:
            return jsonify({
                'error': 'Ad search failed',
                'details': search_results.get('error', 'Unknown error')
            }), 400

        ads = search_results.get('data', [])

        # Create session for this search
        session_id = str(uuid.uuid4())
        session_dir = Path('processed') / f"facebook_ads_{session_id}"
        session_dir.mkdir(parents=True, exist_ok=True)

        # Save search metadata
        search_metadata = {
            'session_id': session_id,
            'search_params': {
                'search_terms': search_terms,
                'country': country,
                'ad_type': ad_type,
                'media_type': media_type,
                'start_date': start_date,
                'end_date': end_date,
                'limit': limit
            },
            'results_count': len(ads),
            'search_time': datetime.now().isoformat(),
            'ads': ads[:10]  # Store first 10 for preview
        }

        metadata_file = session_dir / 'search_metadata.json'
        with open(metadata_file, 'w') as f:
            json.dump(search_metadata, f, indent=2)

        flash(f'Found {len(ads)} Facebook ads matching your criteria')
        return jsonify({
            'success': True,
            'session_id': session_id,
            'ads_found': len(ads),
            'ads_preview': ads[:10],  # Send first 10 for display
            'redirect_url': url_for('facebook_ads_results', session_id=session_id)
        })

    except Exception as e:
        print(f"❌ Facebook ads search error: {e}")
        return jsonify({'error': f'Search failed: {str(e)}'}), 500

@app.route('/facebook-ads/results/<session_id>')
def facebook_ads_results(session_id):
    """Display Facebook ads search results"""
    session_dir = Path('processed') / f"facebook_ads_{session_id}"
    metadata_file = session_dir / 'search_metadata.json'

    if not metadata_file.exists():
        flash('Search results not found')
        return redirect(url_for('facebook_ads'))

    try:
        with open(metadata_file, 'r') as f:
            search_data = json.load(f)

        return render_template('facebook_ads_results.html',
                             session_id=session_id,
                             search_data=search_data)

    except Exception as e:
        flash(f'Error loading search results: {e}')
        return redirect(url_for('facebook_ads'))

@app.route('/facebook-ads/process/<session_id>', methods=['POST'])
def process_facebook_ads(session_id):
    """Process selected Facebook ads for evaluation"""
    if not FACEBOOK_CLIENT_AVAILABLE or not EVALUATOR_AVAILABLE:
        return jsonify({'error': 'Required services not available'}), 400

    try:
        session_dir = Path('processed') / f"facebook_ads_{session_id}"
        metadata_file = session_dir / 'search_metadata.json'

        if not metadata_file.exists():
            return jsonify({'error': 'Session not found'}), 404

        # Get selected ad IDs from request
        selected_ads = request.json.get('selected_ads', [])
        if not selected_ads:
            return jsonify({'error': 'No ads selected'}), 400

        # Load search metadata
        with open(metadata_file, 'r') as f:
            search_data = json.load(f)

        # Note: For now, we'll create placeholder evaluations since
        # Facebook API doesn't provide direct creative downloads
        results = []

        for ad_id in selected_ads:
            # Find the ad in our search results
            ad_data = None
            for ad in search_data.get('ads', []):
                if ad.get('id') == ad_id:
                    ad_data = ad
                    break

            if not ad_data:
                continue

            # Create a result entry with available metadata
            result = {
                'approved': True,  # Placeholder - would need actual creative analysis
                'reason': 'Facebook ad metadata processed - creative analysis requires manual review',
                'confidence': 0.5,
                'link': ad_data.get('ad_snapshot_url', ''),
                'facebook_ad_data': {
                    'ad_id': ad_id,
                    'page_name': ad_data.get('page_name', 'Unknown'),
                    'creation_time': ad_data.get('ad_creation_time'),
                    'delivery_start': ad_data.get('ad_delivery_start_time'),
                    'delivery_stop': ad_data.get('ad_delivery_stop_time'),
                    'spend': ad_data.get('spend', {}),
                    'impressions': ad_data.get('impressions', {}),
                    'creative_bodies': ad_data.get('ad_creative_bodies', []),
                    'snapshot_url': ad_data.get('ad_snapshot_url')
                },
                'media_type': 'facebook_ad',
                'text_extracted': ' '.join(ad_data.get('ad_creative_bodies', [])),
                'word_count': len(' '.join(ad_data.get('ad_creative_bodies', [])).split())
            }
            results.append(result)

        if results:
            # Generate report
            report_generator = ReportGenerator()

            # Create summary
            summary = {
                'total_images': len(results),
                'approved': sum(1 for r in results if r.get('approved', False)),
                'rejected': len(results) - sum(1 for r in results if r.get('approved', False)),
                'approval_rate': sum(1 for r in results if r.get('approved', False)) / len(results) if results else 0
            }

            report_json = report_generator.generate_json_report(results, summary)
            report_filename = f"facebook_ads_evaluation_{session_id[:8]}.json"
            report_path = report_generator.save_report(report_json, f'reviews/{report_filename}')

            return jsonify({
                'success': True,
                'processed_count': len(results),
                'report_filename': report_filename,
                'redirect_url': url_for('index')  # Redirect to main dashboard
            })

        return jsonify({'error': 'No ads could be processed'}), 400

    except Exception as e:
        print(f"❌ Facebook ads processing error: {e}")
        return jsonify({'error': f'Processing failed: {str(e)}'}), 500

@app.route('/api/facebook-ads/test')
def test_facebook_connection():
    """Test Facebook API connection"""
    if not FACEBOOK_CLIENT_AVAILABLE:
        return jsonify({'error': 'Facebook client not available'}), 400

    try:
        fb_client = create_facebook_client()
        result = fb_client.test_connection()
        return jsonify(result)
    except Exception as e:
        return jsonify({'error': f'Connection test failed: {str(e)}'}), 500

if __name__ == '__main__':
    print("🚀 Starting EZ Content Evaluation Platform")
    print("📊 Dashboard: http://localhost:3000")
    print("📤 Upload: http://localhost:3000/upload")
    if EVALUATOR_AVAILABLE:
        print("✅ Content evaluation ready")
    else:
        print("⚠️  Content evaluation disabled (missing dependencies)")

    port = int(os.environ.get('PORT', 3000))
    app.run(debug=True, host='0.0.0.0', port=port)