import os
import logging
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