from datetime import date
import os
from flask import Flask, abort, render_template, redirect, request, url_for
from flask_login import LoginManager
import jinja_partials
from jinja2_fragments import render_block
from decorators import validate_person, validate_topset, validate_workout
from routes.auth import auth, get_person_by_id
from routes.changelog import changelog_bp
from routes.calendar import calendar_bp # Import the new calendar blueprint
from routes.notes import notes_bp # Import the new notes blueprint
from routes.workout import workout_bp # Import the new workout blueprint
from routes.sql_explorer import sql_explorer_bp # Import the new SQL explorer blueprint
from routes.endpoints import endpoints_bp # Import the new endpoints blueprint
from routes.export import export_bp # Import the new export blueprint
from routes.tags import tags_bp # Import the new tags blueprint
from routes.programs import programs_bp # Import the new programs blueprint
from extensions import db
from utils import convert_str_to_date
from flask_htmx import HTMX
import minify_html
import os
from dotenv import load_dotenv

# Load environment variables from .env file in non-production environments
if os.environ.get('FLASK_ENV') != 'production':
    load_dotenv()

app = Flask(__name__)
app.config.from_pyfile('config.py')
app.secret_key = os.environ.get('SECRET_KEY', '2a661781919643cb8a5a8bc57642d99f')
jinja_partials.register_extensions(app)
htmx = HTMX(app)
login_manager = LoginManager(app)

login_manager.login_view = 'auth.login'
login_manager.login_message_category = 'info'

@login_manager.user_loader
def load_user(person_id):
    return get_person_by_id(person_id)

app.register_blueprint(auth, url_prefix='/auth')
app.register_blueprint(changelog_bp, url_prefix='/changelog')
app.register_blueprint(calendar_bp) # Register the calendar blueprint
app.register_blueprint(notes_bp) # Register the notes blueprint
app.register_blueprint(workout_bp) # Register the workout blueprint
app.register_blueprint(sql_explorer_bp) # Register the SQL explorer blueprint (prefix defined in blueprint file)
app.register_blueprint(endpoints_bp) # Register the endpoints blueprint (prefix defined in blueprint file)
app.register_blueprint(export_bp) # Register the export blueprint (prefix defined in blueprint file)
app.register_blueprint(tags_bp) # Register the tags blueprint (prefix defined in blueprint file)
app.register_blueprint(programs_bp) # Register the programs blueprint (prefix defined in blueprint file)

@app.after_request
def response_minify(response):
    """
    minify html response to decrease site traffic
    """
    if response.content_type == u'text/html; charset=utf-8':
        response.set_data(
            minify_html.minify(response.get_data(
                as_text=True), minify_js=True, remove_processing_instructions=True)
        )

        return response
    return response

@ app.route("/")
def dashboard():
    selected_people_ids = request.args.getlist('person_id', type=int)
    min_date = request.args.get('min_date', type=convert_str_to_date)
    max_date = request.args.get('max_date', type=convert_str_to_date)
    selected_exercise_ids = request.args.getlist('exercise_id', type=int)

    if not selected_people_ids and htmx.trigger_name != 'person_id':
        selected_people_ids = db.dashboard.get_people_ids()

    if not min_date or not max_date:
        db_min_date, db_max_date = db.dashboard.get_earliest_and_latest_workout_dates(selected_people_ids)
        min_date = min_date or db_min_date
        max_date = max_date or db_max_date
    
    if not selected_exercise_ids and htmx.trigger_name != 'exercise_id':
        selected_exercise_ids = db.dashboard.list_of_performed_exercise_ids(selected_people_ids, min_date, max_date)
    
    people = db.dashboard.get_people_with_selection(selected_people_ids)
    exercises = db.dashboard.get_exercises_with_selection(selected_people_ids, min_date, max_date, selected_exercise_ids)
    tags = db.get_tags_for_dashboard()
    dashboard = db.dashboard.get(selected_people_ids, min_date, max_date, selected_exercise_ids)

    # Render the appropriate response for HTMX or full page
    render_args = {
        **dashboard,
        "people": people,
        "exercises": exercises,
        "tags": tags,
        "selected_people_ids": selected_people_ids,
        "max_date": max_date,
        "min_date": min_date,
        "selected_exercise_ids": selected_exercise_ids
    }

    if htmx:
        return render_block(app.jinja_env, 'dashboard.html', 'content', **render_args)
    return render_template('dashboard.html', **render_args)


@ app.route("/person/list", methods=['GET'])
def get_person_list():
    people = db.get_people_and_workout_count(-1)
    return render_template('partials/people_link.html', people=people)

@ app.route("/person/<int:person_id>/workout/overview", methods=['GET'])
def person_overview(person_id):
    min_date = request.args.get('min_date', type=convert_str_to_date)
    max_date = request.args.get('max_date', type=convert_str_to_date)
    selected_exercise_ids = request.args.getlist('exercise_id', type=int)

    if not min_date or not max_date:
        db_min_date, db_max_date = db.person_overview.get_earliest_and_latest_workout_dates(person_id)
        min_date = min_date or db_min_date
        max_date = max_date or db_max_date

    if not selected_exercise_ids and htmx.trigger_name != 'exercise_id':
        selected_exercise_ids = db.person_overview.list_of_performed_exercise_ids(person_id, min_date, max_date)
    
    person = db.person_overview.get(person_id, min_date, max_date, selected_exercise_ids)
    exercises = db.person_overview.get_exercises_with_selection(person_id, min_date, max_date, selected_exercise_ids)
    tags = db.get_tags_for_person(person_id)

    # Render the appropriate response for HTMX or full page
    render_args = {
        **person,
        "exercises": exercises,
        "tags": tags,
        "selected_exercise_ids": selected_exercise_ids,
        "max_date": max_date,
        "min_date": min_date
    }

    if htmx:
        return render_block(app.jinja_env, 'person_overview.html', 'content', **render_args), 200, {"HX-Push-Url": url_for('person_overview', person_id=person_id, min_date=min_date, max_date=max_date, exercise_id=selected_exercise_ids), "HX-Trigger": "refreshStats"}

    return render_template('person_overview.html', **render_args), 200, {"HX-Push-Url": url_for('person_overview', person_id=person_id, min_date=min_date, max_date=max_date, exercise_id=selected_exercise_ids), "HX-Trigger": "refreshStats"}

@ app.route("/person", methods=['POST'])
def create_person():
    name = request.form.get("name")
    new_person_id = db.create_person(name)
    return render_template('partials/person.html', person_id=new_person_id, name=name), 200, {"HX-Trigger": "updatedPeople"}


@ app.route("/person/<int:person_id>/delete", methods=['DELETE'])
def delete_person(person_id):
    db.delete_person(person_id)
    return "", 200, {"HX-Trigger": "updatedPeople"}


@ app.route("/person/<int:person_id>/edit_form", methods=['GET'])
def get_person_edit_form(person_id):
    name = db.get_person_name(person_id)
    return render_template('partials/person.html', person_id=person_id, name=name, is_edit=True)


@ app.route("/person/<int:person_id>/name", methods=['PUT'])
def update_person_name(person_id):
    new_name = request.form.get("name")
    db.update_person_name(person_id, new_name)
    return render_template('partials/person.html', person_id=person_id, name=new_name), 200, {"HX-Trigger": "updatedPeople"}


@ app.route("/person/<int:person_id>/name", methods=['GET'])
def get_person_name(person_id):
    name = db.get_person_name(person_id)
    return render_template('partials/person.html', person_id=person_id, name=name)


@ app.route("/exercise", methods=['POST'])
def create_exercise():
    name = request.form.get("name")
    new_exercise_id = db.create_exercise(name)
    return render_template('partials/exercise.html', exercise_id=new_exercise_id, name=name)


@ app.route("/exercise/<int:exercise_id>", methods=['GET'])
def get_exercise(exercise_id):
    exercise = db.get_exercise(exercise_id)
    return render_template('partials/exercise.html', exercise_id=exercise_id, name=exercise.name)


@ app.route("/exercise/<int:exercise_id>/edit_form", methods=['GET'])
def get_exercise_edit_form(exercise_id):
    exercise = db.get_exercise(exercise_id)
    return render_template('partials/exercise.html', exercise_id=exercise_id, name=exercise['name'], is_edit=True)


@ app.route("/exercise/<int:exercise_id>/update", methods=['PUT'])
def update_exercise(exercise_id):
    new_name = request.form.get('name')
    db.update_exercise(exercise_id, new_name)
    return render_template('partials/exercise.html', exercise_id=exercise_id, name=new_name)


""" @ app.route("/exercise/<int:exercise_id>/delete", methods=['DELETE'])
def delete_exercise(exercise_id):
    db.delete_exercise(exercise_id)
    return "" """


@ app.route("/settings")
def settings():
    people = db.get_people()
    exercises = db.get_all_exercises()
    if htmx:
        return render_block(app.jinja_env, "settings.html", "content", people=people, exercises=exercises), 200, {"HX-Trigger": "updatedPeople"}
    return render_template('settings.html', people=people, exercises=exercises)


# Routes moved to routes/tags.py blueprint

@ app.route("/person/<int:person_id>/exercise/<int:exercise_id>/sparkline", methods=['GET'])
def get_exercise_progress_for_user(person_id, exercise_id):
    min_date = convert_str_to_date(request.args.get(
        'min_date'), '%Y-%m-%d')
    max_date = convert_str_to_date(request.args.get(
        'max_date'), '%Y-%m-%d')
    epoch = request.args.get('epoch', default='All')
    degree = request.args.get('degree', type=int, default=1)

    if epoch == 'Custom' and (min_date is None or max_date is None):
        (min_date, max_date) = db.get_exercise_earliest_and_latest_dates(person_id, exercise_id)

    exercise_progress = db.get_exercise_progress_for_user(person_id, exercise_id, min_date, max_date, epoch, degree=degree)

    if not exercise_progress:
        abort(404)
    
    return render_template('partials/sparkline.html', **exercise_progress)

@app.route("/stats", methods=['GET'])
def get_stats():
    selected_people_ids = request.args.getlist('person_id', type=int)
    min_date = request.args.get('min_date', type=convert_str_to_date)
    max_date = request.args.get('max_date', type=convert_str_to_date)
    selected_exercise_ids = request.args.getlist('exercise_id', type=int)
    stats = db.stats.fetch_stats(selected_people_ids, min_date, max_date, selected_exercise_ids)
    return render_template('partials/stats.html', stats=stats, refresh_url=request.full_path)

@app.route("/graphs", methods=['GET'])
def get_people_graphs():
    selected_people_ids = request.args.getlist('person_id', type=int)
    min_date = request.args.get('min_date', type=convert_str_to_date)
    max_date = request.args.get('max_date', type=convert_str_to_date)
    selected_exercise_ids = request.args.getlist('exercise_id', type=int)

    graphs = db.people_graphs.get(selected_people_ids, min_date, max_date, selected_exercise_ids)

    return render_template('partials/people_graphs.html', graphs=graphs, refresh_url=request.full_path)

@app.route("/exercises/get")
def get_exercises():
    query = request.args.get('query')
    person_id = request.args.get('person_id', type=int)
    exercises = db.exercises.get(query)
    return render_template('partials/exercise/exercise_dropdown.html', exercises=exercises, person_id=person_id)

@app.route("/exercise/<int:exercise_id>/edit_name", methods=['GET', 'POST'])
def edit_exercise_name(exercise_id):
    exercise = db.exercises.get_exercise(exercise_id)
    person_id = request.args.get('person_id', type=int)
    if request.method == 'GET':
        return render_template('partials/exercise/edit_exercise_name.html', exercise=exercise, person_id=person_id)
    else:
        updated_name = request.form['name']
        updated_exercise = db.exercises.update_exercise_name(exercise_id, updated_name)
        return render_template('partials/exercise/exercise_list_item.html', exercise=updated_exercise, person_id=person_id)

@app.route("/exercises/add", methods=['POST'])
def add_exercise():
    exercise_name = request.form['query']
    new_exercise = db.exercises.add_exercise(exercise_name)
    person_id = request.args.get('person_id', type=int)
    return render_template('partials/exercise/exercise_list_item.html', exercise=new_exercise, person_id=person_id)

@ app.route("/exercise/<int:exercise_id>/delete", methods=['DELETE'])
def delete_exercise(exercise_id):
    db.exercises.delete_exercise(exercise_id)
    return ""

@app.teardown_appcontext
def closeConnection(exception):
    db.close_connection()

@app.template_filter('strftime')
def strftime(date, format="%b %d %Y"):
    return date.strftime(format)

@ app.context_processor
def my_utility_processor():

    def is_selected_page(url):
        # if htmx:
        #    parsed_url = urlparse(htmx.current_url)
        #    return 'bg-gray-200' if url == parsed_url.path else ''
        if url == request.path:
            return 'bg-gray-200'
        return ''

    def strftime(date, format="%b %d %Y"):
        return date.strftime(format)

    return dict(is_selected_page=is_selected_page, strftime=strftime)


if __name__ == '__main__':
    # Bind to PORT if defined, otherwise default to 5000.
    port = int(os.environ.get('PORT', 5000))
    app.run(host='127.0.0.1', port=port)
