from flask import Blueprint, render_template, redirect, url_for, flash, request, make_response,send_file
from app.forms import RequestQuoteForm, ContactForm, BookingForm
from app.models import Car, Tour, Booking, VehicleCategory, TourType, Contact, Blog, TourParentCategory, TourSubCategory, Blog
from flask_mail import Message
from flask import current_app
from .models import QuoteRequest
from urllib.parse import urljoin
from sqlalchemy.orm import joinedload
from datetime import datetime, timedelta
import xml.etree.ElementTree as ET
from xml.dom import minidom
import logging
from app import mail, db
from sqlalchemy import desc
from flask import jsonify
from sqlalchemy import func, or_  # Ensure this import is present
import os


main = Blueprint('main', __name__)

def get_popular_tours():
    return Tour.query.order_by(Tour.views.desc()).all()

@main.context_processor
def inject_popular_tours():
    return dict(popular_tours=get_popular_tours())

@main.route('/sitemap.xml')
def sitemap():
    try:
        """Generate sitemap.xml. Makes a list of urls and date modified."""
        pages = []
        ten_days_ago = datetime.now() - timedelta(days=10)
        
        # Static routes
        for rule in current_app.url_map.iter_rules():
            if "GET" in rule.methods and len(rule.arguments) == 0:
                # Exclude admin routes and other unwanted routes
                if not rule.rule.startswith('/admin') and not rule.rule.startswith('/static'):
                    pages.append([url_for(rule.endpoint, _external=True), ten_days_ago])

        # Dynamic routes
        tours = Tour.query.all()
        blogs = Blog.query.all()
        tour_categories = TourParentCategory.query.all()

        # Car rentals page
        pages.append([url_for('main.car_rentals', _external=True), ten_days_ago])

        # Tour category pages
        for category in tour_categories:
            url = url_for('main.tour_packages', category_slug=category.slug, _external=True)
            pages.append([url, ten_days_ago])

        # Tour pages
        for tour in tours:
            url = url_for('main.tour_detail', slug=tour.slug, _external=True)
            pages.append([url, ten_days_ago])

        # Blog pages
        for blog in blogs:
            url = url_for('main.blog_detail', slug=blog.slug, _external=True)
            pages.append([url, ten_days_ago])

        # Generate XML sitemap
        urlset = ET.Element("urlset")
        urlset.set("xmlns", "http://www.sitemaps.org/schemas/sitemap/0.9")

        for url, date in pages:
            url_elem = ET.SubElement(urlset, "url")
            loc = ET.SubElement(url_elem, "loc")
            loc.text = url
            lastmod = ET.SubElement(url_elem, "lastmod")
            lastmod.text = date.strftime("%Y-%m-%d")

        xml_content = minidom.parseString(ET.tostring(urlset)).toprettyxml(indent="  ")
        
        response = make_response(xml_content)
        response.headers["Content-Type"] = "application/xml"    

        return response
    except Exception as e:
        current_app.logger.error(f"Error generating sitemap: {str(e)}")
        return "An error occurred while generating the sitemap", 500

# @main.route('/')
# def home():
#     parent_categories = TourParentCategory.query.all()
#     # Fetch cars for all categories
#     cars = Car.query.order_by(Car.category).all()
#     # Fetch the latest 3 blog posts
#     latest_blog_posts = Blog.query.order_by(Blog.created_at.desc()).limit(3).all()
#     initial_tours = Tour.query.limit(12).all()
#     return render_template('home.html', 
#                            parent_categories=parent_categories, 
#                            cars=cars, 
#                            VehicleCategory=VehicleCategory,
#                            latest_blog_posts=latest_blog_posts,
#                            initial_tours=initial_tours)


@main.route('/')
def home():
    # Get parent categories with subcategories and tour counts
    parent_categories = TourParentCategory.query.options(
        joinedload(TourParentCategory.subcategories)
    ).all()
    
    # Add tour count to each subcategory
    for parent in parent_categories:
        for subcategory in parent.subcategories:
            subcategory.tour_count = Tour.query.filter_by(subcategory_id=subcategory.id).count()
    
    # Get featured tours for each category
    featured_tours_by_category = {}
    for parent in parent_categories:
        category_tours = []
        for subcategory in parent.subcategories:
            tours = Tour.query.filter_by(subcategory_id=subcategory.id)\
                            .order_by(Tour.views.desc())\
                            .limit(4)\
                            .all()
            category_tours.extend(tours)
        if category_tours:
            featured_tours_by_category[parent] = category_tours[:4]  # Limit to 4 tours per category
    
    # Get other data
    cars = Car.query.order_by(Car.category).all()
    latest_blog_posts = Blog.query.order_by(Blog.created_at.desc()).limit(3).all()
    initial_tours = Tour.query.limit(12).all()

     # Add filters dictionary
    duration = request.args.get('duration')
    filters = {
        'duration': duration or ''  # Set to empty string if duration is None
    }
    
    return render_template('home.html', 
                         parent_categories=parent_categories,
                         cars=cars,
                         VehicleCategory=VehicleCategory,
                         latest_blog_posts=latest_blog_posts,
                         initial_tours=initial_tours,
                         featured_tours_by_category=featured_tours_by_category,filters=filters)

@main.route('/car-rentals')
def car_rentals():
    parent_categories = TourParentCategory.query.all()
    cars = Car.query.order_by(Car.category, Car.name).all()
    categories = VehicleCategory.__members__.keys()
    return render_template('car_rentals.html', cars=cars, categories=categories, parent_categories=parent_categories)

@main.route('/tour-packages')
@main.route('/tour-packages/<string:category_slug>')
def tour_packages(category_slug=None):
    parent_categories = TourParentCategory.query.options(
        joinedload(TourParentCategory.subcategories).joinedload(TourSubCategory.tours)
    ).all()
    
    if category_slug:
        category = TourParentCategory.query.filter_by(slug=category_slug).first_or_404()
        tours_by_category = {category: []}
        for subcategory in category.subcategories:
            tours_by_category[category].extend(subcategory.tours)
    else:
        category = None
        tours_by_category = {}
        for parent_category in parent_categories:
            category_tours = []
            for subcategory in parent_category.subcategories:
                category_tours.extend(subcategory.tours)
            if category_tours:
                tours_by_category[parent_category] = category_tours

    return render_template('tour_packages.html', 
                           parent_categories=parent_categories,
                           category=category,
                           tours_by_category=tours_by_category)



@main.route('/about')
def about():
    parent_categories = TourParentCategory.query.all()  
    return render_template('about.html', parent_categories=parent_categories)

@main.route('/contact', methods=['GET', 'POST'])
def contact():
    parent_categories = TourParentCategory.query.all()  
    form = ContactForm()
    if form.validate_on_submit():
        contact = Contact(
            name=form.name.data,
            email=form.email.data,
            subject=form.subject.data,
            message=form.message.data
        )
        db.session.add(contact)
        db.session.commit()
        flash('Your message has been sent. We will get back to you soon!', 'success')
        return redirect(url_for('main.contact'))
    return render_template('contact.html', form=form, parent_categories=parent_categories)

@main.route('/request-quote', methods=['GET', 'POST'])
def request_quote():
    parent_categories = TourParentCategory.query.all()  
    form = RequestQuoteForm()
    car_id = request.args.get('car_id')
    tour_id = request.args.get('tour_id')
    car = None
    tour = None
    request_type = None

    if car_id:
        car = Car.query.get_or_404(car_id)
        form.car_id.data = car_id
        form.car_name.data = car.name
        request_type = "car"
    elif tour_id:
        tour = Tour.query.get_or_404(tour_id)
        form.tour_id.data = tour_id
        form.tour_name.data = tour.title
        request_type = "tour"

    if form.validate_on_submit():
        try:
            # Convert empty strings to None for integer fields
            car_id = form.car_id.data
            car_id = int(car_id) if car_id and car_id.isdigit() else None
            
            tour_id = form.tour_id.data
            tour_id = int(tour_id) if tour_id and tour_id.isdigit() else None

            quote_request = QuoteRequest(
                first_name=form.first_name.data,
                last_name=form.last_name.data,
                num_adults=form.num_adults.data,
                num_children=form.num_children.data,
                date_from=form.date_from.data,
                date_to=form.date_to.data,
                country=form.country.data,
                email=form.email.data,
                phone=form.phone.data,
                message=form.message.data,
                car_id=car_id,
                tour_id=tour_id
            )
            
            db.session.add(quote_request)
            db.session.commit()

            # Prepare email message
            sender = ('Lanka Travel Bee', 'info@itint.site')
            msg = Message("New Quote Request",
                          sender=sender,
                          recipients=['info@lankatravelbee.com'])
            
            if form.car_name.data:
                request_type_str = f"Vehicle: {form.car_name.data}"
            elif form.tour_name.data:
                request_type_str = f"Tour: {form.tour_name.data}"
            else:
                request_type_str = "General Inquiry"

            msg.body = f"""
            New Quote Request:
            {request_type_str}
            Name: {form.first_name.data} {form.last_name.data}
            Adults: {form.num_adults.data}
            Children: {form.num_children.data}
            From: {form.date_from.data}
            To: {form.date_to.data}
            Country: {form.country.data}
            Email: {form.email.data}
            Phone: {form.phone.data}
            Message: {form.message.data}
            """
            mail.send(msg)

            flash('Thank you for your quote request. We will contact you shortly!', 'success')
            return redirect(url_for('main.thank_you'))
        
        except Exception as e:
            db.session.rollback()
            flash('An error occurred while processing your request. Please try again.', 'error')
            current_app.logger.error(f'Error in request_quote: {str(e)}')
            return render_template('request_quote.html', form=form, car=car, tour=tour, request_type=request_type, parent_categories=parent_categories)

    elif form.errors:
        for field, errors in form.errors.items():
            for error in errors:
                flash(f"{getattr(form, field).label.text}: {error}", 'error')

    return render_template('request_quote.html', form=form, car=car, tour=tour, request_type=request_type, parent_categories=parent_categories)

@main.route('/thank-you')
def thank_you():
    return render_template('thank_you.html')

@main.route('/cordelia-cruises')
def cordelia_cruises():
    return render_template('cordelia_cruises.html', popular_tours=get_popular_tours(), TourType=TourType)

@main.route('/tour/<string:slug>')
def tour_detail(slug):
    tour = Tour.query.options(
        joinedload(Tour.tour_days),
        joinedload(Tour.subcategory).joinedload(TourSubCategory.parent_category)
    ).filter_by(slug=slug).first_or_404()
    
    # Handle the case where tour.image might be None
    if tour.image is None:
        tour.image = 'default_tour_image.jpg'  # Set a default image
    
    # Update view count
    if tour.views is None:
        tour.views = 1
    else:
        tour.views += 1
    
    db.session.commit()

    parent_categories = TourParentCategory.query.all()
    return render_template('tour_detail.html', tour=tour, parent_categories=parent_categories)


@main.route('/blog')
def blog_list():
    parent_categories = TourParentCategory.query.all()  
    page = request.args.get('page', 1, type=int)
    blogs = Blog.query.order_by(Blog.created_at.desc()).paginate(page=page, per_page=10)
    return render_template('blog_list.html', blogs=blogs, parent_categories=parent_categories)

@main.route('/blog/<string:slug>')
def blog_detail(slug):
    parent_categories = TourParentCategory.query.all()  
    blog = Blog.query.filter_by(slug=slug).first_or_404()
    return render_template('blog_detail.html', blog=blog, parent_categories=parent_categories)

@main.route('/blog/category/<string:category>')
def blog_category(category):
    parent_categories = TourParentCategory.query.all()  
    page = request.args.get('page', 1, type=int)
    blogs = Blog.query.filter_by(category=category).order_by(Blog.created_at.desc()).paginate(page=page, per_page=10)
    return render_template('blog_category.html', category=category, blogs=blogs, parent_categories=parent_categories)

@main.route('/terms-and-conditions')
def terms_and_conditions():
    return render_template('terms_and_conditions.html')

@main.route('/privacy-policy')
def privacy_policy():
    return render_template('privacy_policy.html')

@main.route('/sitemap')
def sitemap_html():
    return render_template('sitemap.html')

@main.route('/sri-Lanka')
def sri_lanka_html():
    return render_template('sri-lanka.html')

@main.route('/api/tours')
def get_tours():
    page = request.args.get('page', 1, type=int)
    per_page = request.args.get('per_page', 12, type=int)
    tours = Tour.query.paginate(page=page, per_page=per_page, error_out=False)
    return jsonify({
        'tours': [{
            'id': tour.id, 
            'title': tour.title, 
            'description': tour.description[:100] + '...' if len(tour.description) > 100 else tour.description, 
            'image': url_for('static', filename='uploads/' + (tour.image or 'default_tour_image.jpg')),
            'url': url_for('main.tour_detail', slug=tour.slug)
        } for tour in tours.items],
        'has_next': tours.has_next
    })


# @main.route('/filter-tours')
# def filter_tours():
#     parent_category = request.args.get('parentCategory')
#     sub_category = request.args.get('subCategory')
#     duration = request.args.get('duration')
#     location = request.args.get('location')

#     query = Tour.query

#     if parent_category:
#         query = query.filter(Tour.subcategory.has(parent_category_id=parent_category))
#     if sub_category:
#         query = query.filter(Tour.subcategory_id == sub_category)
#     if duration:
#         # You'll need to parse the duration string and filter accordingly
#         pass
#     if location:
#         query = query.filter(Tour.title.ilike(f'%{location}%'))

#     tours = query.all()
#     return jsonify({'tours': [tour.to_dict() for tour in tours]})




# @main.route('/filtered-tours')
# def filtered_tours():
#     # Define a list of valid locations
#     valid_locations = ['Bentota', 'Galle', 'Mirissa',  'Yala',  ]  # Replace with your actual locations

#     parent_category = request.args.get('parentCategory')
#     sub_category = request.args.get('subCategory')
#     duration = request.args.get('duration')
#     location = request.args.get('location')
#     search = request.args.get('search')
#     sort_by_popularity = request.args.get('sort_by_popularity')

#     query = Tour.query

#     if parent_category:
#         query = query.filter(Tour.subcategory.has(TourSubCategory.parent_category.has(TourParentCategory.slug == parent_category)))
#     if sub_category:
#         query = query.filter(Tour.subcategory.has(TourSubCategory.slug == sub_category))
#     if duration:
#         if duration == '1':
#             query = query.filter(Tour.duration == '1 Day')
#         elif '-' in duration:
#             min_days, max_days = map(int, duration.split('-'))
#             query = query.filter(Tour.duration.between(f"{min_days} Days", f"{max_days} Days"))
#         elif duration == '15+':
#             query = query.filter(Tour.duration >= '15 Days')
#     if location:
#         # Ensure the location is being filtered correctly from the itinerary column
#         query = query.filter(Tour.itinerary.ilike(f'%{location}%'))  # Changed from title to itinerary
#     if search:
#         query = query.filter(or_(
#             Tour.title.like(f'%{search.lower()}%'),
#             Tour.description.like(f'%{search.lower()}%')
#         ))
#     if sort_by_popularity:
#         query = query.order_by(Tour.views.desc())

#     filtered_tours = query.all()
    
#     # Get all parent categories and subcategories
#     parent_categories = TourParentCategory.query.all()
#     subcategories = TourSubCategory.query.all()

#     # Get unique locations from tour itineraries
#     locations = db.session.query(func.regexp_replace(Tour.itinerary, '.*(?:in|at|to) ([^,]+).*', '\\1').label('location')) \
#                           .distinct() \
#                           .order_by('location') \
#                           .all()
#     # Clean the result and filter based on valid locations
#     locations = [loc.location.strip() for loc in locations if loc.location and loc.location.strip() in valid_locations]

#     return render_template('filtered_tours.html', 
#                            tours=filtered_tours, 
#                            parent_categories=parent_categories,
#                            subcategories=subcategories,
#                            locations=locations,
#                            filters={
#                                'parent_category': parent_category,
#                                'sub_category': sub_category,
#                                'duration': duration,
#                                'location': location,
#                                'search': search,
#                                'sort_by_popularity': sort_by_popularity
#                            })


@main.route('/filtered-tours')
def filtered_tours():
    duration = request.args.get('duration')
    query = Tour.query

    if duration:
        if duration == '1-day':
            query = query.filter(Tour.duration.ilike('%1 Day%'))
        elif duration == '2-3':
            query = query.filter(or_(
                Tour.duration.ilike('%2 Day%'),
                Tour.duration.ilike('%3 Day%')
            ))
        elif duration == '4-7':
            query = query.filter(or_(
                Tour.duration.ilike('%4 Day%'),
                Tour.duration.ilike('%5 Day%'),
                Tour.duration.ilike('%6 Day%'),
                Tour.duration.ilike('%7 Day%')
            ))
        elif duration == '8-14':
            conditions = [Tour.duration.ilike(f'%{i} Day%') for i in range(8, 15)]
            query = query.filter(or_(*conditions))
        elif duration == '15+':
            conditions = [Tour.duration.ilike('%15 Day%')]
            conditions.extend([Tour.duration.ilike(f'%{i} Day%') for i in range(16, 31)])
            query = query.filter(or_(*conditions))

    filtered_tours = query.all()
    
    if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
        return jsonify({
            'tours': [{
                'id': tour.id,
                'title': tour.title,
                'duration': tour.duration,
                'image': url_for('static', filename='uploads/' + (tour.image or 'default-tour-image.jpg')),
                'slug': tour.slug,
                'description': tour.description[:100] if tour.description else ''
            } for tour in filtered_tours]
        })

    return render_template('filtered_tours.html', 
                         tours=filtered_tours,
                         parent_categories=TourParentCategory.query.all(),
                         filters={'duration': duration or ''})


@main.context_processor
def inject_common_data():
    # Define a list of valid locations
    valid_locations = ['Location1', 'Location2', 'Location3']  # Replace with your actual locations

    parent_categories = TourParentCategory.query.all()
    subcategories = TourSubCategory.query.all()
    
    # Get unique locations from tour itineraries
    locations = db.session.query(func.regexp_replace(Tour.itinerary, '.*(?:in|at|to) ([^,]+).*', '\\1').label('location')) \
                          .distinct() \
                          .order_by('location') \
                          .all()
    # Clean the result and filter based on valid locations
    locations = [loc.location.strip() for loc in locations if loc.location and loc.location.strip() in valid_locations]
    
    return dict(
        parent_categories=parent_categories,
        subcategories=subcategories,
        locations=locations,
        popular_tours=get_popular_tours()
    )
    
@main.route('/special-tours')
def special_tours():
    # Query tours from the special tours parent category
    special_category = TourParentCategory.query.filter_by(name='Special Tours').first()
    
    if special_category:
        tours_by_category = {}
        category_tours = []
        for subcategory in special_category.subcategories:
            category_tours.extend(subcategory.tours)
        if category_tours:
            tours_by_category[special_category] = category_tours
    else:
        tours_by_category = {}

    parent_categories = TourParentCategory.query.all()
    
    return render_template('special_tours.html', 
                         parent_categories=parent_categories,
                         category=special_category,
                         tours_by_category=tours_by_category)

@main.route('/service-worker.js')
def service_worker():
    # Get the path to your service-worker.js file
    sw_path = os.path.join(current_app.root_path, 'static', 'js', 'service-worker.js')
    
    # Create response with the file
    response = make_response(send_file(sw_path))
    
    # Set correct headers
    response.headers['Content-Type'] = 'application/javascript'
    response.headers['Service-Worker-Allowed'] = '/'
    response.headers['Cache-Control'] = 'no-cache'
    
    # Set CORS headers if needed
    response.headers['Access-Control-Allow-Origin'] = '*'
    
    return response

# Route for offline page
@main.route('/offline.html')
def offline():
    return send_file('templates/offline.html')


@main.route('/api/category-tours/<int:category_id>')
def get_category_tours(category_id):
    page = request.args.get('page', 1, type=int)
    per_page = request.args.get('per_page', 8, type=int)
    
    # Get subcategory IDs for this parent category
    subcategory_ids = [sc.id for sc in TourSubCategory.query.filter_by(parent_category_id=category_id).all()]
    
    # Query tours for these subcategories
    tours = Tour.query.filter(Tour.subcategory_id.in_(subcategory_ids))\
                     .paginate(page=page, per_page=per_page, error_out=False)
    
    return jsonify({
        'tours': [{
            'id': tour.id,
            'title': tour.title,
            'duration': tour.duration,
            'description': tour.description[:100] + '...' if tour.description and len(tour.description) > 100 else tour.description,
            'image': url_for('static', filename='uploads/' + (tour.image or 'default_tour_image.jpg')),
            'url': url_for('main.tour_detail', slug=tour.slug),
            'subcategory': tour.subcategory.name if tour.subcategory else None
        } for tour in tours.items],
        'has_next': tours.has_next,
        'total': tours.total
    })


@main.route('/api/search-suggestions')
def search_suggestions():
    query = request.args.get('q', '').lower()
    if not query or len(query) < 2:
        return jsonify([])
    
    # Search in tour titles and descriptions
    tours = Tour.query.filter(
        or_(
            Tour.title.ilike(f'%{query}%'),
            Tour.description.ilike(f'%{query}%')
        )
    ).limit(5).all()
    
    # Search in subcategory names
    subcategories = TourSubCategory.query.filter(
        TourSubCategory.name.ilike(f'%{query}%')
    ).limit(3).all()
    
    suggestions = []
    
    # Add tour suggestions
    suggestions.extend({
        'type': 'tour',
        'title': tour.title,
        'url': url_for('main.tour_detail', slug=tour.slug)
    } for tour in tours)
    
    # Add category suggestions
    suggestions.extend({
        'type': 'category',
        'title': f'Browse {subcategory.name} Tours',
        'url': url_for('main.tour_packages', category_slug=subcategory.parent_category.slug)
    } for subcategory in subcategories)
    
    return jsonify(suggestions)