from flask import Blueprint, render_template, request, redirect, url_for, flash, jsonify, session, current_app
from flask_mail import Message
from models.project_model import ProjectModel
from models.survey_model import SurveyModel
from models.feature_model import FeatureModel
from models.question_model import QuestionModel
from models.option_model import OptionModel
from models.people_model import PeopleModel
from models.question_model import QuestionModel
from models.temperament_model import TemperamentModel
from models.report_model import ReportModel
from models.database import execute_update_query, execute_single_query

public_bp = Blueprint('public', __name__)

@public_bp.route('/survey/<slug>')
def survey(slug):
    """Public survey page accessible by project slug"""
    # Get project by slug
    project = ProjectModel.get_project_by_slug(slug)
    if not project:
        return render_template('public/survey_not_found.html'), 404
    
    # Get associated survey
    if not project['survey_id']:
        return render_template('public/survey_not_configured.html'), 404
    
    survey = SurveyModel.get_survey_by_id(project['survey_id'])
    if not survey or not survey['is_active']:
        return render_template('public/survey_not_active.html'), 404
    
    return render_template('public/survey_start.html', project=project, survey=survey)

@public_bp.route('/survey/<slug>/register', methods=['GET', 'POST'])
def register_person(slug):
    """Register person for survey"""
    # Get project by slug
    project = ProjectModel.get_project_by_slug(slug)
    if not project:
        return render_template('public/survey_not_found.html'), 404

    if request.method == 'POST':
        name = request.form.get('name', '').strip()
        email = request.form.get('email', '').strip()
        phone = request.form.get('phone', '').strip()

        # Server-side validation
        if not name or len(name) < 2:
            flash('Name is required and must be at least 2 characters', 'error')
            return render_template('public/register.html', project=project)

        if not email or '@' not in email:
            flash('A valid email address is required', 'error')
            return render_template('public/register.html', project=project)

        # Validate name contains valid characters
        import re
        if not re.match(r'^[a-zA-ZáéíóúÁÉÍÓÚñÑüÜ\s\'-]+$', name):
            flash('Name contains invalid characters', 'error')
            return render_template('public/register.html', project=project)

        # Check if email already exists for this project (prevent duplicates)
        if PeopleModel.email_exists_in_project(email, project['id']):
            flash('This email has already been used for this survey', 'error')
            return render_template('public/register.html', project=project, email_exists=True)

        # Limit length
        if len(name) > 100:
            name = name[:100]
        if len(email) > 100:
            email = email[:100]
        if len(phone) > 20:
            phone = phone[:20]

        # Create person record
        try:
            person_id = PeopleModel.create_person(name, project['id'], phone, email)

            # Store person in session
            session['survey_person_id'] = person_id
            session['survey_project_id'] = project['id']
            session.permanent = True  # Make session persistent

            return redirect(url_for('public.take_survey', slug=slug))
        except Exception as e:
            # Check if it's a duplicate key error
            error_message = str(e)
            if 'Duplicate entry' in error_message or 'idx_unique_email_project' in error_message:
                flash('This email has already been used for this survey', 'error')
                return render_template('public/register.html', project=project, email_exists=True)
            else:
                flash('An error occurred during registration. Please try again.', 'error')
                return render_template('public/register.html', project=project)

    return render_template('public/register.html', project=project)

@public_bp.route('/survey/<slug>/take')
def take_survey(slug):
    """Display survey questions"""
    # Get project by slug
    project = ProjectModel.get_project_by_slug(slug)
    if not project:
        return render_template('public/survey_not_found.html'), 404
    
    # Check if person is registered
    if 'survey_person_id' not in session or session.get('survey_project_id') != project['id']:
        return redirect(url_for('public.register_person', slug=slug))
    
    # Get survey data
    survey = SurveyModel.get_survey_by_id(project['survey_id'])
    features = FeatureModel.get_features_by_survey(survey['id'])
    
    # Get questions for each feature
    survey_data = []
    for feature in features:
        questions = QuestionModel.get_questions_by_feature(feature['id'])
        feature_data = {
            'feature': feature,
            'questions': questions
        }
        survey_data.append(feature_data)
    
    # Get all options ordered by position
    options = OptionModel.get_all_options()
    
    # Get person info
    person = PeopleModel.get_person_by_id(session['survey_person_id'])
    
    return render_template('public/take_survey.html', 
                         project=project, 
                         survey=survey,
                         survey_data=survey_data, 
                         options=options,
                         person=person)

@public_bp.route('/survey/<slug>/submit', methods=['POST'])
def submit_survey(slug):
    """Submit survey answers"""
    # Get project by slug
    project = ProjectModel.get_project_by_slug(slug)
    if not project:
        return jsonify({'error': 'Project not found'}), 404
    
    # Check if person is registered
    if 'survey_person_id' not in session or session.get('survey_project_id') != project['id']:
        return jsonify({'error': 'Person not registered'}), 401
    
    person_id = session['survey_person_id']
    project_id = project['id']
    
    # Get form data
    answers_data = request.get_json()
    
    if not answers_data:
        return jsonify({'error': 'No answers provided'}), 400
    
    # Save answers
    answers_saved = 0
    for key, value in answers_data.items():
        # Legacy format: question_<id> -> option_id
        if key.startswith('question_') and value:
            q_id = int(key.replace('question_', ''))
            # Check for existing answer to avoid duplicates
            existing = execute_single_query(
                "SELECT id FROM answers WHERE project_id=%s AND people_id=%s AND question_id=%s LIMIT 1",
                (project_id, person_id, q_id)
            )
            if existing:
                execute_update_query(
                    "UPDATE answers SET option_id=%s WHERE id=%s",
                    (int(value), existing['id'])
                )
            else:
                execute_update_query(
                    "INSERT INTO answers (project_id, people_id, option_id, question_id) VALUES (%s, %s, %s, %s)",
                    (project_id, person_id, int(value), q_id)
                )
            answers_saved += 1
        # New format: feature_<id> -> question_id (single-choice per feature)
        elif key.startswith('feature_') and value:
            q_id = int(value)
            # Look up selected question to capture its linked option_id
            selected_question = QuestionModel.get_question_by_id(q_id)
            linked_option_id = selected_question.get('option_id') if selected_question else None
            # Check for existing answer to avoid duplicates
            existing = execute_single_query(
                "SELECT id FROM answers WHERE project_id=%s AND people_id=%s AND question_id=%s LIMIT 1",
                (project_id, person_id, q_id)
            )
            if existing:
                execute_update_query(
                    "UPDATE answers SET option_id=%s WHERE id=%s",
                    (linked_option_id, existing['id'])
                )
            else:
                execute_update_query(
                    "INSERT INTO answers (project_id, people_id, option_id, question_id) VALUES (%s, %s, %s, %s)",
                    (project_id, person_id, linked_option_id, q_id)
                )
            answers_saved += 1

    # Keep person_id for results page, but mark survey as completed
    session['survey_completed'] = True
    session.modified = True  # Ensure session is saved

    return jsonify({'success': True, 'redirect_url': url_for('public.survey_complete', slug=slug)})

@public_bp.route('/survey/<slug>/complete')
def survey_complete(slug):
    """Survey completion page with optional results display"""
    project = ProjectModel.get_project_by_slug(slug)
    if not project:
        return render_template('public/survey_not_found.html'), 404

    # Check if person just completed survey
    if 'survey_person_id' not in session or session.get('survey_project_id') != project['id']:
        return render_template('public/survey_complete.html', project=project, show_results=False)

    person_id = session['survey_person_id']
    person = PeopleModel.get_person_by_id(person_id)
    show_results_config = project.get('show_results', 'show_by_admin')

    # Clear session after getting data
    session.pop('survey_person_id', None)
    session.pop('survey_project_id', None)
    session.pop('survey_completed', None)

    # Handle different result display modes
    if show_results_config == 'after_end_survey':
        # Show results immediately on completion page
        temps = TemperamentModel.get_all_temperaments()

        # Enforce preferred order (Sanguine, Choleric, Melancholic, Phlegmatic)
        preferred_order = ['Sanguine', 'Choleric', 'Melancholic', 'Phlegmatic']
        temps_sorted = sorted(temps, key=lambda t: preferred_order.index(t['name']) if t['name'] in preferred_order else 999)

        # Get person's temperament counts
        temp_counts = ReportModel.get_person_temperament_counts(person_id)

        # Build scores dict
        scores = {}
        for tc in temp_counts:
            scores[tc['temperament_id']] = tc['cnt']

        # Get total number of answers (including those without temperaments)
        total_answers_query = "SELECT COUNT(*) as total FROM answers WHERE people_id = %s"
        total_result = execute_single_query(total_answers_query, (person_id,))
        total_answers = total_result['total'] if total_result else 0

        # Find matching recommendation
        recommendation = ReportModel.find_matching_recommendation(person_id)

        return render_template('public/survey_results.html',
                             project=project,
                             person=person,
                             temps=temps_sorted,
                             scores=scores,
                             total_answers=total_answers,
                             recommendation=recommendation,
                             show_results=True)

    elif show_results_config == 'send_by_email':
        # Send results via email
        try:
            _send_results_email(person, project, person_id)
            flash_message = 'Survey completed! Results have been sent to your email.'
        except Exception as e:
            current_app.logger.error(f"Error sending results email: {e}")
            flash_message = 'Survey completed! There was an error sending the email, but your responses have been saved.'

        return render_template('public/survey_complete.html',
                             project=project,
                             show_results=False,
                             email_sent=True,
                             message=flash_message)

    else:  # show_by_admin (default)
        # Just show completion message
        return render_template('public/survey_complete.html',
                             project=project,
                             show_results=False)


def _send_results_email(person, project, person_id):
    """Helper function to send results via email"""
    from app import mail
    import json
    import os

    # Get user's language preference from session or default to 'es'
    lang = session.get('lang', 'es')

    # Load translations for the selected language
    translations_path = os.path.join(current_app.root_path, 'i18n', f'{lang}.json')
    with open(translations_path, 'r', encoding='utf-8') as f:
        translations = json.load(f)

    # Get temperament data
    temps = TemperamentModel.get_all_temperaments()
    preferred_order = ['Sanguine', 'Choleric', 'Melancholic', 'Phlegmatic']
    temps_sorted = sorted(temps, key=lambda t: preferred_order.index(t['name']) if t['name'] in preferred_order else 999)

    temp_counts = ReportModel.get_person_temperament_counts(person_id)
    scores = {}
    for tc in temp_counts:
        scores[tc['temperament_id']] = tc['cnt']

    # Get total number of answers (including those without temperaments)
    total_answers_query = "SELECT COUNT(*) as total FROM answers WHERE people_id = %s"
    from models.database import execute_single_query
    total_result = execute_single_query(total_answers_query, (person_id,))
    total_answers = total_result['total'] if total_result else 0

    recommendation = ReportModel.find_matching_recommendation(person_id)

    # Render email template with translations
    html_body = render_template('emails/survey_results.html',
                               person=person,
                               project=project,
                               temps=temps_sorted,
                               scores=scores,
                               total_answers=total_answers,
                               recommendation=recommendation,
                               lang=lang,
                               translations=translations['public'])

    # Email subject in the selected language
    email_subject = translations['public']['email']['survey_results_title'] + f' - {project["name"]}'

    # Send email
    msg = Message(
        subject=email_subject,
        recipients=[person['email']],
        html=html_body
    )
    mail.send(msg)

@public_bp.route('/api/check-email/<slug>', methods=['POST'])
def check_email(slug):
    """API endpoint to check if email exists for project"""
    project = ProjectModel.get_project_by_slug(slug)
    if not project:
        return jsonify({'error': 'Project not found'}), 404
    
    email = request.json.get('email')
    if not email:
        return jsonify({'error': 'Email required'}), 400
    
    exists = PeopleModel.email_exists_in_project(email, project['id'])
    return jsonify({'exists': exists})
