import os
import logging
import tempfile
import shutil
from flask import request, jsonify, render_template, redirect, url_for, flash, current_app
from flask_login import login_required, current_user
from flask_jwt_extended import jwt_required, get_jwt_identity
from werkzeug.utils import secure_filename
from app.upload import bp
from app import db
from app.upload.file_handler import get_file_upload_handler
from app.upload.fixture_parser import get_fixture_parser
from app.utils.security import require_active_user, validate_file_type, hash_file_content
from app.utils.logging import log_file_operation, log_upload_progress
from app.upload.forms import FixtureUploadForm, ZipUploadForm

logger = logging.getLogger(__name__)

@bp.route('/fixture', methods=['GET', 'POST'])
@login_required
@require_active_user
def upload_fixture():
    """Upload fixture file (CSV/XLSX) - Web interface"""
    form = FixtureUploadForm()
    
    if form.validate_on_submit():
        try:
            file = form.fixture_file.data
            if not file or not file.filename:
                flash('No file selected', 'error')
                return render_template('upload/fixture.html', form=form)
            
            # Process upload
            file_handler = get_file_upload_handler()
            upload_record, error_message = file_handler.process_upload(
                file, 'fixture', current_user.id
            )
            
            if error_message:
                flash(f'Upload failed: {error_message}', 'error')
                return render_template('upload/fixture.html', form=form)
            
            # Parse fixture file
            fixture_parser = get_fixture_parser()
            success, parse_error, parsed_matches = fixture_parser.parse_fixture_file(
                upload_record.file_path, upload_record.original_filename, current_user.id
            )
            
            if not success:
                flash(f'Fixture parsing failed: {parse_error}', 'error')
                return render_template('upload/fixture.html', form=form)
            
            # Save matches to database
            success, save_error, match_ids = fixture_parser.save_matches_to_database(
                parsed_matches, upload_record.sha1sum
            )
            
            if not success:
                flash(f'Database save failed: {save_error}', 'error')
                return render_template('upload/fixture.html', form=form)
            
            flash(f'Successfully uploaded and parsed {len(match_ids)} matches!', 'success')
            return redirect(url_for('main.matches'))
            
        except Exception as e:
            logger.error(f"Fixture upload error: {str(e)}")
            flash('Upload processing failed', 'error')
    
    return render_template('upload/fixture.html', form=form)

@bp.route('/zip', methods=['POST'])
@login_required
@require_active_user
def upload_zip():
    """Upload ZIP file for specific match - Web interface (from fixture detail page)"""
    try:
        match_id = request.form.get('match_id')
        if not match_id:
            flash('Match ID is required', 'error')
            return redirect(request.referrer or url_for('main.fixtures'))
        
        from app.models import Match
        match = Match.query.get_or_404(int(match_id))
        
        # Check if user owns this match or is admin
        if not current_user.is_admin and match.created_by != current_user.id:
            flash('You can only upload ZIP files for your own matches', 'error')
            return redirect(request.referrer or url_for('main.fixtures'))
        
        if 'zip_file' not in request.files:
            flash('No file selected', 'error')
            return redirect(request.referrer or url_for('main.fixture_detail', fixture_id=match.fixture_id))
        
        file = request.files['zip_file']
        if not file or not file.filename:
            flash('No file selected', 'error')
            return redirect(request.referrer or url_for('main.fixture_detail', fixture_id=match.fixture_id))
        
        # Update match status to uploading
        match.zip_upload_status = 'uploading'
        db.session.commit()
        
        # Process upload
        file_handler = get_file_upload_handler()
        upload_record, error_message = file_handler.process_upload(
            file, 'zip', current_user.id, int(match_id)
        )
        
        if error_message:
            match.zip_upload_status = 'failed'
            db.session.commit()
            flash(f'Upload failed: {error_message}', 'error')
            return redirect(request.referrer or url_for('main.fixture_detail', fixture_id=match.fixture_id))
        
        # Update match with ZIP file information
        match.zip_filename = upload_record.filename
        match.zip_sha1sum = upload_record.sha1sum
        match.zip_upload_status = 'completed'
        match.zip_upload_progress = 100.00
        
        # Set match as active (both fixture and ZIP uploaded)
        match.set_active()
        
        db.session.commit()
        
        flash(f'ZIP file uploaded successfully for Match #{match.match_number}! Match is now active.', 'success')
        return redirect(request.referrer or url_for('main.fixture_detail', fixture_id=match.fixture_id))
        
    except Exception as e:
        logger.error(f"ZIP upload error: {str(e)}")
        flash('Upload processing failed', 'error')
        return redirect(request.referrer or url_for('main.fixtures'))

@bp.route('/zip/<int:match_id>', methods=['GET', 'POST'])
@login_required
@require_active_user
def upload_zip_page(match_id):
    """Upload ZIP file for specific match - Web interface (dedicated page)"""
    from app.models import Match
    match = Match.query.get_or_404(match_id)
    
    # Check if ZIP already uploaded
    if match.zip_upload_status == 'completed':
        flash('ZIP file already uploaded for this match', 'info')
        return redirect(url_for('main.match_detail', id=match_id))
    
    form = ZipUploadForm()
    
    if form.validate_on_submit():
        try:
            file = form.zip_file.data
            if not file or not file.filename:
                flash('No file selected', 'error')
                return render_template('upload/zip.html', form=form, match=match)
            
            # Update match status to uploading
            match.zip_upload_status = 'uploading'
            db.session.commit()
            
            # Process upload
            file_handler = get_file_upload_handler()
            upload_record, error_message = file_handler.process_upload(
                file, 'zip', current_user.id, match_id
            )
            
            if error_message:
                match.zip_upload_status = 'failed'
                db.session.commit()
                flash(f'Upload failed: {error_message}', 'error')
                return render_template('upload/zip.html', form=form, match=match)
            
            # Update match with ZIP file information
            match.zip_filename = upload_record.filename
            match.zip_sha1sum = upload_record.sha1sum
            match.zip_upload_status = 'completed'
            match.zip_upload_progress = 100.00
            
            # Set match as active (both fixture and ZIP uploaded)
            match.set_active()
            
            db.session.commit()
            
            flash('ZIP file uploaded successfully! Match is now active.', 'success')
            return redirect(url_for('main.match_detail', id=match_id))
            
        except Exception as e:
            logger.error(f"ZIP upload error: {str(e)}")
            match.zip_upload_status = 'failed'
            db.session.commit()
            flash('Upload processing failed', 'error')
    
    return render_template('upload/zip.html', form=form, match=match)

@bp.route('/zip/<int:match_id>/delete', methods=['POST'])
@login_required
@require_active_user
def delete_zip(match_id):
    """Delete ZIP file for specific match"""
    try:
        from app.models import Match, FileUpload
        match = Match.query.get_or_404(match_id)
        
        # Check if user owns this match or is admin
        if not current_user.is_admin and match.created_by != current_user.id:
            flash('You can only delete ZIP files for your own matches', 'error')
            return redirect(request.referrer or url_for('main.fixtures'))
        
        if match.zip_upload_status != 'completed':
            flash('No ZIP file to delete for this match', 'error')
            return redirect(request.referrer or url_for('main.fixture_detail', fixture_id=match.fixture_id))
        
        # Find and delete the associated file upload record
        zip_upload = FileUpload.query.filter_by(
            match_id=match_id,
            file_type='zip'
        ).first()
        
        if zip_upload:
            # Delete physical file
            file_handler = get_file_upload_handler()
            try:
                if os.path.exists(zip_upload.file_path):
                    os.remove(zip_upload.file_path)
                    logger.info(f"Deleted ZIP file: {zip_upload.file_path}")
            except Exception as e:
                logger.warning(f"Could not delete physical file {zip_upload.file_path}: {str(e)}")
            
            # Delete upload record
            db.session.delete(zip_upload)
        
        # Reset match ZIP status
        match.zip_filename = None
        match.zip_sha1sum = None
        match.zip_upload_status = 'pending'
        match.zip_upload_progress = 0.0
        
        # Set match as inactive since ZIP is removed
        match.active_status = False
        
        db.session.commit()
        
        flash(f'ZIP file deleted successfully for Match #{match.match_number}. Match is now inactive.', 'success')
        return redirect(request.referrer or url_for('main.fixture_detail', fixture_id=match.fixture_id))
        
    except Exception as e:
        logger.error(f"ZIP deletion error: {str(e)}")
        flash('ZIP file deletion failed', 'error')
        return redirect(request.referrer or url_for('main.fixtures'))

@bp.route('/api/fixture', methods=['POST'])
@jwt_required()
def api_upload_fixture():
    """Upload fixture file (CSV/XLSX) - API endpoint"""
    try:
        user_id = get_jwt_identity()
        from app.models import User
        user = User.query.get(user_id)
        
        if not user or not user.is_active:
            return jsonify({'error': 'User not found or inactive'}), 404
        
        if 'file' not in request.files:
            return jsonify({'error': 'No file provided'}), 400
        
        file = request.files['file']
        if not file or not file.filename:
            return jsonify({'error': 'No file selected'}), 400
        
        # Process upload
        file_handler = get_file_upload_handler()
        upload_record, error_message = file_handler.process_upload(
            file, 'fixture', user_id
        )
        
        if error_message:
            return jsonify({'error': error_message}), 400
        
        # Parse fixture file
        fixture_parser = get_fixture_parser()
        success, parse_error, parsed_matches = fixture_parser.parse_fixture_file(
            upload_record.file_path, upload_record.original_filename, user_id
        )
        
        if not success:
            return jsonify({'error': f'Fixture parsing failed: {parse_error}'}), 400
        
        # Save matches to database
        success, save_error, match_ids = fixture_parser.save_matches_to_database(
            parsed_matches, upload_record.sha1sum
        )
        
        if not success:
            return jsonify({'error': f'Database save failed: {save_error}'}), 500
        
        return jsonify({
            'message': 'Fixture uploaded and parsed successfully',
            'upload_record': upload_record.to_dict(),
            'matches_created': len(match_ids),
            'match_ids': match_ids
        }), 200
        
    except Exception as e:
        logger.error(f"API fixture upload error: {str(e)}")
        return jsonify({'error': 'Upload processing failed'}), 500

@bp.route('/api/zip/<int:match_id>', methods=['POST'])
@jwt_required()
def api_upload_zip(match_id):
    """Upload ZIP file for specific match - API endpoint"""
    try:
        user_id = get_jwt_identity()
        from app.models import User, Match
        user = User.query.get(user_id)
        
        if not user or not user.is_active:
            return jsonify({'error': 'User not found or inactive'}), 404
        
        match = Match.query.get(match_id)
        if not match:
            return jsonify({'error': 'Match not found'}), 404
        
        # Check if ZIP already uploaded
        if match.zip_upload_status == 'completed':
            return jsonify({'error': 'ZIP file already uploaded for this match'}), 400
        
        if 'file' not in request.files:
            return jsonify({'error': 'No file provided'}), 400
        
        file = request.files['file']
        if not file or not file.filename:
            return jsonify({'error': 'No file selected'}), 400
        
        # Update match status to uploading
        match.zip_upload_status = 'uploading'
        db.session.commit()
        
        # Process upload
        file_handler = get_file_upload_handler()
        upload_record, error_message = file_handler.process_upload(
            file, 'zip', user_id, match_id
        )
        
        if error_message:
            match.zip_upload_status = 'failed'
            db.session.commit()
            return jsonify({'error': error_message}), 400
        
        # Update match with ZIP file information
        match.zip_filename = upload_record.filename
        match.zip_sha1sum = upload_record.sha1sum
        match.zip_upload_status = 'completed'
        match.zip_upload_progress = 100.00
        
        # Set match as active (both fixture and ZIP uploaded)
        match.set_active()
        
        db.session.commit()
        
        return jsonify({
            'message': 'ZIP file uploaded successfully',
            'upload_record': upload_record.to_dict(),
            'match': match.to_dict()
        }), 200
        
    except Exception as e:
        logger.error(f"API ZIP upload error: {str(e)}")
        if 'match' in locals():
            match.zip_upload_status = 'failed'
            db.session.commit()
        return jsonify({'error': 'Upload processing failed'}), 500

@bp.route('/api/upload-async', methods=['POST'])
@jwt_required()
def api_upload_async():
    """Start asynchronous file upload"""
    try:
        user_id = get_jwt_identity()
        from app.models import User
        user = User.query.get(user_id)
        
        if not user or not user.is_active:
            return jsonify({'error': 'User not found or inactive'}), 404
        
        if 'file' not in request.files:
            return jsonify({'error': 'No file provided'}), 400
        
        file = request.files['file']
        file_type = request.form.get('file_type', 'fixture')
        match_id = request.form.get('match_id')
        
        if not file or not file.filename:
            return jsonify({'error': 'No file selected'}), 400
        
        if file_type not in ['fixture', 'zip']:
            return jsonify({'error': 'Invalid file type'}), 400
        
        if file_type == 'zip' and not match_id:
            return jsonify({'error': 'Match ID required for ZIP uploads'}), 400
        
        # Start async upload
        file_handler = get_file_upload_handler()
        upload_id, error_message = file_handler.upload_file_async(
            file, file_type, user_id, int(match_id) if match_id else None
        )
        
        if error_message:
            return jsonify({'error': error_message}), 400
        
        return jsonify({
            'upload_id': upload_id,
            'message': 'Upload started successfully'
        }), 202
        
    except Exception as e:
        logger.error(f"Async upload start error: {str(e)}")
        return jsonify({'error': 'Upload start failed'}), 500

@bp.route('/api/upload-status/<upload_id>', methods=['GET'])
@jwt_required()
def api_upload_status(upload_id):
    """Get status of asynchronous upload"""
    try:
        file_handler = get_file_upload_handler()
        status = file_handler.get_upload_status(upload_id)
        
        return jsonify(status), 200
        
    except Exception as e:
        logger.error(f"Upload status error: {str(e)}")
        return jsonify({'error': 'Status check failed'}), 500

@bp.route('/api/upload-cancel/<upload_id>', methods=['POST'])
@jwt_required()
def api_upload_cancel(upload_id):
    """Cancel asynchronous upload"""
    try:
        file_handler = get_file_upload_handler()
        cancelled = file_handler.cancel_upload(upload_id)
        
        if cancelled:
            return jsonify({'message': 'Upload cancelled successfully'}), 200
        else:
            return jsonify({'error': 'Upload could not be cancelled'}), 400
        
    except Exception as e:
        logger.error(f"Upload cancel error: {str(e)}")
        return jsonify({'error': 'Cancel operation failed'}), 500

@bp.route('/api/progress/<int:upload_id>', methods=['GET'])
@jwt_required()
def api_upload_progress(upload_id):
    """Get upload progress for specific upload record"""
    try:
        user_id = get_jwt_identity()
        
        from app.models import FileUpload
        upload_record = FileUpload.query.filter_by(
            id=upload_id,
            uploaded_by=user_id
        ).first()
        
        if not upload_record:
            return jsonify({'error': 'Upload not found'}), 404
        
        return jsonify({
            'upload_id': upload_record.id,
            'progress': float(upload_record.upload_progress),
            'status': upload_record.upload_status,
            'filename': upload_record.original_filename,
            'file_size': upload_record.file_size,
            'error_message': upload_record.error_message
        }), 200
        
    except Exception as e:
        logger.error(f"Progress check error: {str(e)}")
        return jsonify({'error': 'Progress check failed'}), 500

@bp.route('/api/uploads', methods=['GET'])
@jwt_required()
def api_list_uploads():
    """List user's uploads with pagination"""
    try:
        user_id = get_jwt_identity()
        page = request.args.get('page', 1, type=int)
        per_page = min(request.args.get('per_page', 20, type=int), 100)
        file_type = request.args.get('file_type')
        status = request.args.get('status')
        
        from app.models import FileUpload
        query = FileUpload.query.filter_by(uploaded_by=user_id)
        
        if file_type:
            query = query.filter_by(file_type=file_type)
        
        if status:
            query = query.filter_by(upload_status=status)
        
        uploads = query.order_by(FileUpload.created_at.desc()).paginate(
            page=page, per_page=per_page, error_out=False
        )
        
        return jsonify({
            'uploads': [upload.to_dict() for upload in uploads.items],
            'pagination': {
                'page': page,
                'pages': uploads.pages,
                'per_page': per_page,
                'total': uploads.total,
                'has_next': uploads.has_next,
                'has_prev': uploads.has_prev
            }
        }), 200
        
    except Exception as e:
        logger.error(f"Upload list error: {str(e)}")
        return jsonify({'error': 'Upload list failed'}), 500

@bp.route('/api/statistics', methods=['GET'])
@jwt_required()
def api_upload_statistics():
    """Get upload statistics"""
    try:
        user_id = get_jwt_identity()
        from app.models import User
        user = User.query.get(user_id)
        
        if not user:
            return jsonify({'error': 'User not found'}), 404
        
        file_handler = get_file_upload_handler()
        fixture_parser = get_fixture_parser()
        
        upload_stats = file_handler.get_upload_statistics()
        parsing_stats = fixture_parser.get_parsing_statistics()
        
        # User-specific statistics
        from app.models import FileUpload, Match
        user_uploads = FileUpload.query.filter_by(uploaded_by=user_id).count()
        user_matches = Match.query.filter_by(created_by=user_id).count()
        
        stats = {
            'global': {
                'upload_stats': upload_stats,
                'parsing_stats': parsing_stats
            },
            'user': {
                'total_uploads': user_uploads,
                'total_matches_created': user_matches
            }
        }
        
        return jsonify(stats), 200
        
    except Exception as e:
        logger.error(f"Statistics error: {str(e)}")
        return jsonify({'error': 'Statistics calculation failed'}), 500

@bp.route('/api/cleanup', methods=['POST'])
@jwt_required()
def api_cleanup_uploads():
    """Clean up failed uploads (admin only)"""
    try:
        user_id = get_jwt_identity()
        from app.models import User
        user = User.query.get(user_id)
        
        if not user or not user.is_admin:
            return jsonify({'error': 'Admin privileges required'}), 403
        
        file_handler = get_file_upload_handler()
        file_handler.cleanup_failed_uploads()
        
        return jsonify({'message': 'Cleanup completed successfully'}), 200
        
    except Exception as e:
        logger.error(f"Cleanup error: {str(e)}")
        return jsonify({'error': 'Cleanup failed'}), 500

@bp.route('/api/zip/<int:match_id>/stream', methods=['POST'])
@jwt_required()
def api_upload_zip_stream(match_id):
    """Upload ZIP file for specific match using streaming - API endpoint for large files"""
    try:
        user_id = get_jwt_identity()
        from app.models import User, Match
        user = User.query.get(user_id)
        
        if not user or not user.is_active:
            return jsonify({'error': 'User not found or inactive'}), 404
        
        match = Match.query.get(match_id)
        if not match:
            return jsonify({'error': 'Match not found'}), 404
        
        # Check if ZIP already uploaded
        if match.zip_upload_status == 'completed':
            return jsonify({'error': 'ZIP file already uploaded for this match'}), 400
        
        # Get file info from headers
        content_length = request.headers.get('Content-Length')
        if not content_length:
            return jsonify({'error': 'Content-Length header required for streaming'}), 400
        
        total_size = int(content_length)
        filename = request.headers.get('X-Filename', 'streamed_file.zip')
        
        # Validate file size
        if total_size > current_app.config.get('MAX_CONTENT_LENGTH', 5 * 1024 * 1024 * 1024):
            return jsonify({'error': 'File too large'}), 413
        
        # Update match status to uploading
        match.zip_upload_status = 'uploading'
        db.session.commit()
        
        # Generate secure filename using SHA1 for ZIP files
        from werkzeug.utils import secure_filename
        from datetime import datetime
        import time
        import hashlib
        
        sanitized_name = secure_filename(filename)
        
        # Use SHA1 naming for ZIP files (streaming uploads are typically ZIP files)
        unix_timestamp = str(int(time.time()))
        hash_input = unix_timestamp + filename
        sha1_hash = hashlib.sha1(hash_input.encode('utf-8')).hexdigest()
        
        # Extract file extension from original filename
        import os
        _, ext = os.path.splitext(sanitized_name)
        final_filename = sha1_hash + (ext or '.zip')
        
        # Create upload record
        file_handler = get_file_upload_handler()
        file_handler._ensure_initialized()
        
        file_path = os.path.join(file_handler.upload_folder, final_filename)
        
        from app.models import FileUpload
        upload_record = FileUpload(
            filename=final_filename,
            original_filename=filename,
            file_path=file_path,
            file_size=total_size,
            file_type='zip',
            mime_type='application/zip',
            sha1sum='',  # Will be calculated after upload
            upload_status='uploading',
            match_id=match_id,
            uploaded_by=user_id
        )
        
        db.session.add(upload_record)
        db.session.commit()
        
        # Stream the file
        success = file_handler.save_file_streaming(
            request.stream, file_path, total_size, upload_record
        )
        
        if not success:
            match.zip_upload_status = 'failed'
            db.session.commit()
            return jsonify({'error': 'Streaming upload failed'}), 500
        
        # Calculate SHA1 checksum
        sha1_checksum = file_handler.calculate_sha1(file_path)
        if not sha1_checksum:
            upload_record.mark_failed("Checksum calculation failed")
            match.zip_upload_status = 'failed'
            db.session.commit()
            return jsonify({'error': 'Checksum calculation failed'}), 500
        
        # Update upload record with checksum
        upload_record.sha1sum = sha1_checksum
        upload_record.mark_completed()
        
        # Update match with ZIP file information
        match.zip_filename = upload_record.filename
        match.zip_sha1sum = upload_record.sha1sum
        match.zip_upload_status = 'completed'
        match.zip_upload_progress = 100.00
        
        # Set match as active (both fixture and ZIP uploaded)
        match.set_active()
        
        db.session.commit()
        
        return jsonify({
            'message': 'ZIP file streamed successfully',
            'upload_record': upload_record.to_dict(),
            'match': match.to_dict()
        }), 200
        
    except Exception as e:
        logger.error(f"Streaming ZIP upload error: {str(e)}")
        if 'match' in locals():
            match.zip_upload_status = 'failed'
            db.session.commit()
        return jsonify({'error': 'Streaming upload failed'}), 500

@bp.route('/api/zip/<int:match_id>/resume', methods=['POST'])
@jwt_required()
def api_upload_zip_resume(match_id):
    """Resume ZIP file upload for specific match - API endpoint"""
    try:
        user_id = get_jwt_identity()
        from app.models import User, Match, FileUpload
        user = User.query.get(user_id)
        
        if not user or not user.is_active:
            return jsonify({'error': 'User not found or inactive'}), 404
        
        match = Match.query.get(match_id)
        if not match:
            return jsonify({'error': 'Match not found'}), 404
        
        # Check if ZIP already uploaded
        if match.zip_upload_status == 'completed':
            return jsonify({'error': 'ZIP file already uploaded for this match'}), 400
        
        # Find existing upload record
        upload_record = FileUpload.query.filter_by(
            match_id=match_id,
            file_type='zip',
            uploaded_by=user_id
        ).order_by(FileUpload.created_at.desc()).first()
        
        if not upload_record:
            return jsonify({'error': 'No previous upload found to resume'}), 404
        
        if 'file' not in request.files:
            return jsonify({'error': 'No file provided'}), 400
        
        file = request.files['file']
        if not file or not file.filename:
            return jsonify({'error': 'No file selected'}), 400
        
        # Update match status to uploading
        match.zip_upload_status = 'uploading'
        upload_record.upload_status = 'uploading'
        db.session.commit()
        
        # Resume upload
        file_handler = get_file_upload_handler()
        success = file_handler.resume_upload(file, upload_record.file_path, upload_record)
        
        if not success:
            match.zip_upload_status = 'failed'
            db.session.commit()
            return jsonify({'error': 'Resume upload failed'}), 500
        
        # Calculate SHA1 checksum
        sha1_checksum = file_handler.calculate_sha1(upload_record.file_path)
        if not sha1_checksum:
            upload_record.mark_failed("Checksum calculation failed")
            match.zip_upload_status = 'failed'
            db.session.commit()
            return jsonify({'error': 'Checksum calculation failed'}), 500
        
        # Update upload record with checksum
        upload_record.sha1sum = sha1_checksum
        upload_record.mark_completed()
        
        # Update match with ZIP file information
        match.zip_filename = upload_record.filename
        match.zip_sha1sum = upload_record.sha1sum
        match.zip_upload_status = 'completed'
        match.zip_upload_progress = 100.00
        
        # Set match as active (both fixture and ZIP uploaded)
        match.set_active()
        
        db.session.commit()
        
        return jsonify({
            'message': 'ZIP file resumed and completed successfully',
            'upload_record': upload_record.to_dict(),
            'match': match.to_dict()
        }), 200
        
    except Exception as e:
        logger.error(f"Resume ZIP upload error: {str(e)}")
        if 'match' in locals():
            match.zip_upload_status = 'failed'
            db.session.commit()
        return jsonify({'error': 'Resume upload failed'}), 500

@bp.route('/api/upload-info/<int:upload_id>', methods=['GET'])
@jwt_required()
def api_upload_info(upload_id):
    """Get detailed upload information including resume capability"""
    try:
        user_id = get_jwt_identity()
        
        from app.models import FileUpload
        upload_record = FileUpload.query.filter_by(
            id=upload_id,
            uploaded_by=user_id
        ).first()
        
        if not upload_record:
            return jsonify({'error': 'Upload not found'}), 404
        
        # Check if file exists and get current size
        current_size = 0
        can_resume = False
        
        if os.path.exists(upload_record.file_path):
            current_size = os.path.getsize(upload_record.file_path)
            can_resume = (current_size > 0 and
                         current_size < upload_record.file_size and
                         upload_record.upload_status in ['failed', 'uploading'])
        
        return jsonify({
            'upload_id': upload_record.id,
            'filename': upload_record.original_filename,
            'file_size': upload_record.file_size,
            'current_size': current_size,
            'progress': float(upload_record.upload_progress),
            'status': upload_record.upload_status,
            'can_resume': can_resume,
            'resume_from': current_size,
            'error_message': upload_record.error_message,
            'created_at': upload_record.created_at.isoformat() if upload_record.created_at else None,
            'updated_at': upload_record.updated_at.isoformat() if upload_record.updated_at else None
        }), 200
        
    except Exception as e:
        logger.error(f"Upload info error: {str(e)}")
        return jsonify({'error': 'Failed to get upload info'}), 500

@bp.route('/fixture/<fixture_id>/zip', methods=['POST'])
@login_required
@require_active_user
def upload_fixture_zip(fixture_id):
    """Upload ZIP file for all matches in a fixture that don't have one - Web interface"""
    try:
        from app.models import Match
        
        # Get all matches for this fixture
        if current_user.is_admin:
            matches = Match.query.filter_by(fixture_id=fixture_id).all()
        else:
            matches = Match.query.filter_by(fixture_id=fixture_id, created_by=current_user.id).all()
        
        if not matches:
            flash('Fixture not found', 'error')
            return redirect(request.referrer or url_for('main.fixtures'))
        
        # Filter matches that don't have ZIP files
        matches_without_zip = [m for m in matches if m.zip_upload_status != 'completed']
        
        if not matches_without_zip:
            flash('All matches in this fixture already have ZIP files', 'info')
            return redirect(request.referrer or url_for('main.fixture_detail', fixture_id=fixture_id))
        
        if 'zip_file' not in request.files:
            flash('No file selected', 'error')
            return redirect(request.referrer or url_for('main.fixture_detail', fixture_id=fixture_id))
        
        file = request.files['zip_file']
        if not file or not file.filename:
            flash('No file selected', 'error')
            return redirect(request.referrer or url_for('main.fixture_detail', fixture_id=fixture_id))
        
        # Update all matches status to uploading
        for match in matches_without_zip:
            match.zip_upload_status = 'uploading'
        db.session.commit()
        
        # Process upload once
        file_handler = get_file_upload_handler()
        upload_record, error_message = file_handler.process_upload(
            file, 'zip', current_user.id
        )
        
        if error_message:
            # Reset all matches to failed
            for match in matches_without_zip:
                match.zip_upload_status = 'failed'
            db.session.commit()
            flash(f'Upload failed: {error_message}', 'error')
            return redirect(request.referrer or url_for('main.fixture_detail', fixture_id=fixture_id))
        
        # Update all matches with the same ZIP file information
        for match in matches_without_zip:
            match.zip_filename = upload_record.filename
            match.zip_sha1sum = upload_record.sha1sum
            match.zip_upload_status = 'completed'
            match.zip_upload_progress = 100.00
            
            # Set match as active (both fixture and ZIP uploaded)
            match.set_active()
        
        db.session.commit()
        
        flash(f'ZIP file uploaded successfully for {len(matches_without_zip)} matches! All matches are now active.', 'success')
        return redirect(request.referrer or url_for('main.fixture_detail', fixture_id=fixture_id))
        
    except Exception as e:
        logger.error(f"Fixture ZIP upload error: {str(e)}")
        flash('Upload processing failed', 'error')
        return redirect(request.referrer or url_for('main.fixtures'))

@bp.route('/chunk', methods=['POST'])
@login_required
@require_active_user
def upload_chunk():
    """Upload a chunk of a file"""
    try:
        chunk = request.files.get('chunk')
        if not chunk:
            return jsonify({'success': False, 'error': 'No chunk provided'}), 400

        chunk_index = int(request.form.get('chunkIndex', 0))
        total_chunks = int(request.form.get('totalChunks', 1))
        upload_id = request.form.get('uploadId')
        file_name = request.form.get('fileName')
        match_id = request.form.get('matchId')

        if not upload_id or not file_name:
            return jsonify({'success': False, 'error': 'Missing upload parameters'}), 400

        # Create temp directory for this upload
        temp_dir = os.path.join(current_app.config['TEMP_UPLOAD_FOLDER'], upload_id)
        os.makedirs(temp_dir, exist_ok=True)

        # Save chunk
        chunk_path = os.path.join(temp_dir, f'chunk_{chunk_index:06d}')
        chunk.save(chunk_path)

        # Check if all chunks are received
        received_chunks = len([f for f in os.listdir(temp_dir) if f.startswith('chunk_')])
        if received_chunks == total_chunks:
            # All chunks received, mark as ready for finalization
            with open(os.path.join(temp_dir, 'metadata.txt'), 'w') as f:
                f.write(f'{file_name}\n{match_id or ""}\n')

        return jsonify({'success': True}), 200

    except Exception as e:
        logger.error(f"Chunk upload error: {str(e)}")
        return jsonify({'success': False, 'error': str(e)}), 500

@bp.route('/finalize', methods=['POST'])
@login_required
@require_active_user
def finalize_upload():
    """Finalize chunked upload"""
    try:
        data = request.get_json()
        upload_id = data.get('uploadId')
        file_name = data.get('fileName')
        match_id = data.get('matchId')

        if not upload_id or not file_name:
            return jsonify({'success': False, 'error': 'Missing parameters'}), 400

        temp_dir = os.path.join(current_app.config['TEMP_UPLOAD_FOLDER'], upload_id)
        if not os.path.exists(temp_dir):
            return jsonify({'success': False, 'error': 'Upload not found'}), 404

        # Read metadata
        metadata_path = os.path.join(temp_dir, 'metadata.txt')
        if not os.path.exists(metadata_path):
            return jsonify({'success': False, 'error': 'Upload not complete'}), 400

        with open(metadata_path, 'r') as f:
            lines = f.read().strip().split('\n')
            stored_file_name = lines[0]
            stored_match_id = lines[1] if len(lines) > 1 else ''

        # Assemble file
        final_path = os.path.join(temp_dir, secure_filename(file_name))
        with open(final_path, 'wb') as outfile:
            chunk_files = sorted([f for f in os.listdir(temp_dir) if f.startswith('chunk_')])
            for chunk_file in chunk_files:
                chunk_path = os.path.join(temp_dir, chunk_file)
                with open(chunk_path, 'rb') as infile:
                    shutil.copyfileobj(infile, outfile)

        # Now process as normal upload
        file_handler = get_file_upload_handler()

        # Create a file-like object for the assembled file
        class FileLike:
            def __init__(self, path):
                self.path = path
                self.name = file_name

            def save(self, dst):
                shutil.move(self.path, dst)

        mock_file = FileLike(final_path)

        if match_id:
            # ZIP upload for match
            from app.models import Match
            match = Match.query.get_or_404(int(match_id))

            # Check permissions
            if not current_user.is_admin and match.created_by != current_user.id:
                return jsonify({'success': False, 'error': 'Permission denied'}), 403

            # Update match status
            match.zip_upload_status = 'uploading'
            db.session.commit()

            upload_record, error_message = file_handler.process_upload(
                mock_file, 'zip', current_user.id, int(match_id)
            )

            if error_message:
                match.zip_upload_status = 'failed'
                db.session.commit()
                return jsonify({'success': False, 'error': error_message}), 400

            match.zip_filename = upload_record.filename
            match.zip_sha1sum = upload_record.sha1sum
            match.zip_upload_status = 'completed'
            match.zip_upload_progress = 100.00
            match.set_active()
            db.session.commit()

            # Clean up temp files
            shutil.rmtree(temp_dir)

            flash(f'ZIP file uploaded successfully for Match #{match.match_number}! Match is now active.', 'success')
            return jsonify({
                'success': True,
                'redirect': url_for('main.fixture_detail', fixture_id=match.fixture_id)
            }), 200

        else:
            # Fixture upload
            upload_record, error_message = file_handler.process_upload(
                mock_file, 'fixture', current_user.id
            )

            if error_message:
                return jsonify({'success': False, 'error': error_message}), 400

            # Parse fixture
            fixture_parser = get_fixture_parser()
            success, parse_error, parsed_matches = fixture_parser.parse_fixture_file(
                upload_record.file_path, upload_record.original_filename, current_user.id
            )

            if not success:
                return jsonify({'success': False, 'error': parse_error}), 400

            success, save_error, match_ids = fixture_parser.save_matches_to_database(
                parsed_matches, upload_record.sha1sum
            )

            if not success:
                return jsonify({'success': False, 'error': save_error}), 500

            # Clean up temp files
            shutil.rmtree(temp_dir)

            flash(f'Successfully uploaded and parsed {len(match_ids)} matches!', 'success')
            return jsonify({
                'success': True,
                'redirect': url_for('main.matches')
            }), 200

    except Exception as e:
        logger.error(f"Finalize upload error: {str(e)}")
        return jsonify({'success': False, 'error': str(e)}), 500