import json
import uuid
from flask import Blueprint, render_template, request, session, current_app, jsonify, Response, stream_with_context, \
    url_for
from sqlalchemy.exc import SQLAlchemyError

from common.extensions import db, content_manager
from common.models.user import Tenant, SpecialistMagicLinkTenant, TenantMake
from common.models.interaction import SpecialistMagicLink, Specialist, ChatSession, Interaction
from common.services.interaction.specialist_services import SpecialistServices
from common.utils.business_event import BusinessEvent
from common.utils.business_event_context import current_event
from common.utils.database import Database
from common.utils.chat_utils import get_default_chat_customisation
from common.utils.execution_progress import ExecutionProgressTracker
from common.extensions import cache_manager

chat_bp = Blueprint('chat_bp', __name__, url_prefix='/chat')

@chat_bp.before_request
def log_before_request():
    current_app.logger.debug(f'Before request: {request.path} =====================================')


@chat_bp.after_request
def log_after_request(response):
    return response


# @chat_bp.before_request
# def before_request():
#     try:
#         mw_before_request()
#     except Exception as e:
#         current_app.logger.error(f'Error switching schema in Document Blueprint: {e}')
#         raise


@chat_bp.route('/')
def index():
    return render_template('error/404.html'), 404


@chat_bp.route('/<magic_link_code>')
def chat(magic_link_code):
    """
    Main chat interface accessed via magic link
    """
    try:
        # Find the tenant using the magic link code
        magic_link_tenant = SpecialistMagicLinkTenant.query.filter_by(magic_link_code=magic_link_code).first()

        if not magic_link_tenant:
            current_app.logger.error(f"Invalid magic link code: {magic_link_code}")
            return render_template('error/404.html'), 404

        # Get tenant information
        tenant_id = magic_link_tenant.tenant_id
        tenant = Tenant.query.get(tenant_id)
        if not tenant:
            current_app.logger.error(f"Tenant not found for ID: {tenant_id}")
            return render_template('error/404.html'), 404
        # Switch to tenant schema
        Database(tenant_id).switch_schema()

        # Get specialist magic link details from tenant schema
        specialist_ml = SpecialistMagicLink.query.filter_by(magic_link_code=magic_link_code).first()
        if not specialist_ml:
            current_app.logger.error(f"Specialist magic link not found in tenant schema: {tenant_id}")
            return render_template('error/404.html'), 404

        # Get relevant TenantMake
        tenant_make = TenantMake.query.get(specialist_ml.tenant_make_id)
        if not tenant_make:
            current_app.logger.error(f"Tenant make not found: {specialist_ml.tenant_make_id}")
            return render_template('error/500.html'), 500

        # Get specialist details
        specialist = Specialist.query.get(specialist_ml.specialist_id)
        if not specialist:
            current_app.logger.error(f"Specialist not found: {specialist_ml.specialist_id}")
            return render_template('error/404.html'), 404

        # Store necessary information in session
        session['tenant'] = tenant.to_dict()
        session['specialist'] = specialist.to_dict()
        session['magic_link'] = specialist_ml.to_dict()
        session['tenant_make'] = tenant_make.to_dict()
        session['chat_session_id'] = SpecialistServices.start_session()

        # Get customisation options with defaults
        current_app.logger.debug(f"Make Customisation Options: {tenant_make.chat_customisation_options}")
        try:
            customisation = get_default_chat_customisation(tenant_make.chat_customisation_options)
            current_app.logger.debug(f"Customisation Options: {customisation}")
        except Exception as e:
            current_app.logger.error(f"Error processing customisation options: {str(e)}")
            # Fallback to default customisation
            customisation = get_default_chat_customisation(None)

        # Start a new chat session
        session['chat_session_id'] = SpecialistServices.start_session()

        # Define settings for the client
        settings = {
            "max_message_length": 2000,
            "auto_scroll": True
        }

        specialist_config = specialist.configuration
        if isinstance(specialist_config, str):
            specialist_config = json.loads(specialist_config)

        static_url = current_app.config.get('STATIC_URL')
        current_app.logger.debug(f"STATIC_URL: {static_url}")
        if not static_url:
            static_url = url_for('static', filename='')

        return render_template('chat.html',
                               tenant=tenant,
                               tenant_make=tenant_make,
                               specialist=specialist,
                               customisation=customisation,
                               messages=[],
                               settings=settings,
                               config=current_app.config,
                               static_url=static_url
                               )

    except Exception as e:
        current_app.logger.error(f"Error in chat view: {str(e)}", exc_info=True)
        return render_template('error/500.html'), 500


@chat_bp.route('/api/send_message', methods=['POST'])
def send_message():
    """
    API endpoint to send a message to the specialist
    """
    current_app.logger.debug(f"Sending message to specialist: {session.get('specialist', {}).get('id', 'UNKNOWN')}\n"
                             f"with data: {request.json} \n"
                             f"BEFORE TRY")
    try:
        current_app.logger.debug(
            f"Sending message to specialist: {session.get('specialist', {}).get('id', 'UNKNOWN')}\n"
            f"with data: {request.json} \n"
            f"AFTER TRY")

        # Voeg meer debug logging toe om elk stap te traceren
        current_app.logger.debug("Step 1: Getting request data")
        data = request.json
        message = data.get('message', '')
        form_values = data.get('form_values', {})

        current_app.logger.debug(f"Step 2: Parsed message='{message}', form_values={form_values}")

        # Controleer of er ofwel een bericht of formuliergegevens zijn
        if not message and not form_values:
            current_app.logger.debug("Step 3: No message or form data - returning error")
            return jsonify({'error': 'No message or form data provided'}), 400

        current_app.logger.debug("Step 4: Getting session data")
        # Veiliger session toegang met fallbacks
        tenant_data = session.get('tenant', {})
        specialist_data = session.get('specialist', {})

        tenant_id = tenant_data.get('id')
        specialist_id = specialist_data.get('id')
        chat_session_id = session.get('chat_session_id')
        specialist_args = session.get('magic_link', {}).get('specialist_args', {})

        current_app.logger.debug(
            f"Step 5: Session data - tenant_id={tenant_id}, specialist_id={specialist_id}, chat_session_id={chat_session_id}")

        if not all([tenant_id, specialist_id, chat_session_id]):
            current_app.logger.error(
                f"Missing session data: tenant_id={tenant_id}, specialist_id={specialist_id}, chat_session_id={chat_session_id}")
            return jsonify({'error': 'Session expired or invalid'}), 400

        current_app.logger.debug("Step 6: Switching to tenant schema")
        # Switch to tenant schema
        Database(tenant_id).switch_schema()

        current_app.logger.debug("Step 7: Preparing specialist arguments")
        # Add user message to specialist arguments
        if message:
            specialist_args['question'] = message

        # Add form values to specialist arguments if present
        if form_values:
            specialist_args['form_values'] = form_values

        # Add language to specialist arguments if present
        user_language = data.get('language')
        if user_language:
            specialist_args['language'] = user_language

        current_app.logger.debug(f"Step 8: About to execute specialist with args: {specialist_args}")
        current_app.logger.debug(f"Sending message to specialist: {specialist_id} for tenant {tenant_id}\n"
                                 f" with args: {specialist_args}\n"
                                 f"with session ID: {chat_session_id}")

        # Execute specialist
        current_app.logger.debug("Step 9: Calling SpecialistServices.execute_specialist")
        result = SpecialistServices.execute_specialist(
            tenant_id=tenant_id,
            specialist_id=specialist_id,
            specialist_arguments=specialist_args,
            session_id=chat_session_id,
            user_timezone=data.get('timezone', 'UTC')
        )

        current_app.logger.debug(f"Step 10: Specialist execution result: {result}")

        # Store the task ID for polling
        current_app.logger.debug("Step 11: Storing task ID in session")
        session['current_task_id'] = result['task_id']

        current_app.logger.debug("Step 12: Preparing response")
        response_data = {
            'status': 'processing',
            'task_id': result['task_id'],
            'content': 'Verwerking gestart...',
            'type': 'text'
        }

        current_app.logger.debug(f"Step 13: Returning response: {response_data}")
        return jsonify(response_data)

    except Exception as e:
        current_app.logger.error(f"Error sending message: {str(e)}", exc_info=True)
        return jsonify({'error': str(e)}), 500

@chat_bp.route('/api/check_status', methods=['GET'])
def check_status():
    """
    API endpoint to check the status of a task
    """
    try:
        task_id = request.args.get('task_id') or session.get('current_task_id')

        if not task_id:
            return jsonify({'error': 'No task ID provided'}), 400

        tenant_id = session.get('tenant_id')
        if not tenant_id:
            return jsonify({'error': 'Session expired or invalid'}), 400

        # Switch to tenant schema
        Database(tenant_id).switch_schema()

        # Check task status using Celery
        task_result = current_app.celery.AsyncResult(task_id)

        if task_result.state == 'PENDING':
            return jsonify({'status': 'pending'})
        elif task_result.state == 'SUCCESS':
            result = task_result.result

            # Format the response
            specialist_result = result.get('result', {})
            response = {
                'status': 'success',
                'answer': specialist_result.get('answer', ''),
                'citations': specialist_result.get('citations', []),
                'insufficient_info': specialist_result.get('insufficient_info', False),
                'interaction_id': result.get('interaction_id')
            }

            return jsonify(response)
        else:
            return jsonify({
                'status': 'error',
                'message': str(task_result.info)
            })

    except Exception as e:
        current_app.logger.error(f"Error checking status: {str(e)}", exc_info=True)
        return jsonify({'error': str(e)}), 500

@chat_bp.route('/api/task_progress/<task_id>')
def task_progress_stream(task_id):
    """
    Server-Sent Events endpoint voor realtime voortgangsupdates
    """
    current_app.logger.debug(f"Streaming updates for task ID: {task_id}")
    try:
        tracker = ExecutionProgressTracker()

        def generate():
            try:
                for update in tracker.get_updates(task_id):
                    current_app.logger.debug(f"Progress update: {update}")
                    yield update
            except Exception as e:
                current_app.logger.error(f"Progress stream error: {str(e)}")
                yield f"data: {{'error': '{str(e)}'}}\n\n"

        return Response(
            stream_with_context(generate()),
            mimetype='text/event-stream',
            headers={
                'Cache-Control': 'no-cache',
                'X-Accel-Buffering': 'no',
                'Connection': 'keep-alive'
            }
        )
    except Exception as e:
        current_app.logger.error(f"Failed to start progress stream: {str(e)}")
        return jsonify({'error': str(e)}), 500

@chat_bp.route('/api/translate', methods=['POST'])
def translate():
    """
    API endpoint om tekst te vertalen naar een doeltaal

    Parameters (JSON):
    - text: de tekst die moet worden vertaald
    - target_lang: de ISO 639-1 taalcode waarnaar moet worden vertaald
    - source_lang: (optioneel) de ISO 639-1 taalcode van de brontaal
    - context: (optioneel) context voor de vertaling

    Returns:
        JSON met vertaalde tekst
    """
    try:
        tenant_id = session.get('tenant', {}).get('id')
        with BusinessEvent('Client Translation Service', tenant_id):
            with current_event.create_span('Front-End Translation'):
                data = request.json

                # Valideer vereiste parameters
                if not data or 'text' not in data or 'target_lang' not in data:
                    return jsonify({
                        'success': False,
                        'error': 'Required parameters missing: text and/or target_lang'
                    }), 400

                text = data.get('text')
                target_lang = data.get('target_lang')
                source_lang = data.get('source_lang')
                context = data.get('context')

                # Controleer of tekst niet leeg is
                if not text.strip():
                    return jsonify({
                        'success': False,
                        'error': 'Text to translate cannot be empty'
                    }), 400

                # Haal tenant_id uit sessie
                tenant_id = session.get('tenant', {}).get('id')
                if not tenant_id:
                    current_app.logger.error("No tenant ID found in session")
                    # Fallback naar huidige app tenant_id
                    tenant_id = getattr(current_app, 'tenant_id', None)

                # Haal vertaling op (uit cache of genereer nieuw)
                translation = cache_manager.translation_cache.get_translation(
                    text=text,
                    target_lang=target_lang,
                    source_lang=source_lang,
                    context=context
                )

                if not translation:
                    return jsonify({
                        'success': False,
                        'error': 'No translation found in cache. Please try again later.'
                    }), 500

                # Retourneer het resultaat
                return jsonify({
                    'success': True,
                    'translated_text': translation.translated_text,
                    'source_language': translation.source_language,
                    'target_language': translation.target_language
                })

    except Exception as e:
        current_app.logger.error(f"Error translating: {str(e)}", exc_info=True)
        return jsonify({
            'success': False,
            'error': f"Error translating: {str(e)}"
        }), 500


@chat_bp.route('/privacy', methods=['GET'])
def privacy_statement():
    """
    Public AJAX endpoint for dpa statement content
    Returns JSON response suitable for modal display
    """
    try:
        # Use content_manager to get the latest dpa content
        content_data = content_manager.read_content('dpa')

        if not content_data:
            current_app.logger.error("Data Privacy Agreement content not found")
            return jsonify({
                'error': 'Data Privacy Agreement not available',
                'message': 'The Data Pdpa Agreement could not be loaded at this time.'
            }), 404

        current_app.logger.debug(f"Content data: {content_data}")

        # Return JSON response for AJAX consumption
        return jsonify({
            'title': 'Data Privacy Agreement',
            'content': content_data['content'],
            'version': content_data['version'],
            'content_type': content_data['content_type']
        }), 200

    except Exception as e:
        current_app.logger.error(f"Error loading Data Privacy Agreement: {str(e)}")
        return jsonify({
            'error': 'Server error',
            'message': 'An error occurred while loading the Data Privacy Agreement.'
        }), 500


@chat_bp.route('/terms', methods=['GET'])
def terms_conditions():
    """
    Public AJAX endpoint for terms & conditions content
    Returns JSON response suitable for modal display
    """
    try:
        # Use content_manager to get the latest terms content
        content_data = content_manager.read_content('terms')

        if not content_data:
            current_app.logger.error("Terms & conditions content not found")
            return jsonify({
                'error': 'Terms & conditions not available',
                'message': 'The terms & conditions could not be loaded at this time.'
            }), 404

        # Return JSON response for AJAX consumption
        return jsonify({
            'title': 'Terms & Conditions',
            'content': content_data['content'],
            'version': content_data['version'],
            'content_type': content_data['content_type']
        }), 200

    except Exception as e:
        current_app.logger.error(f"Error loading terms & conditions: {str(e)}")
        return jsonify({
            'error': 'Server error',
            'message': 'An error occurred while loading the terms & conditions.'
        }), 500