from huey import SqliteHuey
import subprocess
import os
from app.models import db, PrintFile, SystemConfig
from app.utils.conf_parse import ConfParse
import json
import uuid
import configparser


import os

# Ensure instance directory exists
instance_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), '..', 'instance')
os.makedirs(instance_dir, exist_ok=True)
huey_db_path = os.path.join(instance_dir, 'huey_queue.db')

huey = SqliteHuey(filename=huey_db_path)

def get_gcode_dir(app):
    with app.app_context():
        conf = SystemConfig.query.filter_by(key='gcode_upload_folder').first()
        if conf and conf.value and os.path.exists(conf.value):
            return conf.value
    return app.config['UPLOAD_FOLDER']


@huey.task()
def slice_stl_task(file_id, stl_filepath, quality_preset=None, material_preset=None, infill_density=None, support_enable=None, support_pattern=None, delete_stl=False):
    # This is run by the Huey worker
    # We need to create an app context to interact with the database
    from app import create_app
    app = create_app()
    with app.app_context():
        print_file = PrintFile.query.get(file_id)
        if not print_file:
            return

        # Cache variables and commit slicing status
        gcode_filename = print_file.filename.rsplit('.', 1)[0] + '.gcode'
        gcode_filepath = os.path.join(get_gcode_dir(app), gcode_filename)
        print_file.status = 'slicing'
        db.session.commit()
        
        # Remove DB session to avoid locking the sqlite db during long slicing operations
        db.session.remove()
        
        from app.utils.slice_engines import get_slicer_engine
        
        try:
            # Optionally fetch the preferred engine from db conf or just default to cura
            # For now default to cura or whichever is passed via kwargs if implemented later
            conf_engine = SystemConfig.query.filter_by(key='slicer_engine').first()
            engine_name = conf_engine.value if conf_engine and conf_engine.value else "cura"
            db.session.remove()
            
            slicer = get_slicer_engine(engine_name)
            
            success, err_msg = slicer.slice(
                app=app,
                stl_filepath=stl_filepath,
                gcode_filepath=gcode_filepath,
                quality_preset=quality_preset,
                material_preset=material_preset,
                infill_density=infill_density,
                support_enable=support_enable,
                support_pattern=support_pattern
            )
            
            # Re-fetch print_file and update status
            print_file = PrintFile.query.get(file_id)
            if not print_file:
                return

            if success:
                print_file.status = 'sliced'
            else:
                print_file.status = 'failed'
                app.logger.error(f"Slicing Task Failed: {err_msg}")
                
        except Exception as e:
            print_file = PrintFile.query.get(file_id)
            if print_file:
                print_file.status = 'failed'
            app.logger.error(f"Subprocess Exception: {e}")
            
        finally:
            if delete_stl and os.path.exists(stl_filepath):
                try:
                    os.remove(stl_filepath)
                except Exception as e:
                    app.logger.error(f"Failed to delete temp STL {stl_filepath}: {e}")
                    
            db.session.commit()
            db.session.remove()


@huey.task()
def merge_and_slice_task(file_id, inputs, merged_filepath, quality_preset=None, material_preset=None, infill_density=None, support_enable=None, support_pattern=None, delete_stl=False):
    from app import create_app
    app = create_app()
    with app.app_context():
        from app.models import PrintFile, db
        print_file = PrintFile.query.get(file_id)
        if not print_file:
            return

        db.session.remove()
        
        try:
            from app.utils.stl_merger import merge_stls
            merge_stls(inputs, merged_filepath)
            
            # Now trigger the regular slicing task
            # We can just call the slicing logic or enqueue it
            slice_stl_task(file_id, merged_filepath, quality_preset, material_preset, infill_density, support_enable, support_pattern, delete_stl=delete_stl)
        except Exception as e:
            print_file = PrintFile.query.get(file_id)
            if print_file:
                print_file.status = 'failed'
                db.session.commit()
            app.logger.error(f"Merge Exception: {e}")
        finally:
            db.session.remove()

@huey.task()
def simplify_stl_task(file_id, filepath):
    from app import create_app
    app = create_app()
    with app.app_context():
        from app.models import PrintFile, SystemConfig, db
        import os
        from app.utils.stl_simplifier import simplify_stl
        
        print_file = PrintFile.query.get(file_id)
        if not print_file:
            return
            
        try:
            file_size_mb = os.path.getsize(filepath) / (1024 * 1024)
            
            configs = {c.key: c.value for c in SystemConfig.query.all()}
            skip_size = float(configs.get('proxy_skip_size_mb', '5.0'))
            
            proxy_path = filepath + '.proxy.stl'
            
            if file_size_mb <= skip_size:
                # File is small enough, no proxy needed
                print_file.status = 'uploaded'
                db.session.commit()
                return
                
            # Aim for approx 7.5 MB for the proxy
            target_mb = 7.5
            keep_ratio = target_mb / file_size_mb
            if keep_ratio > 1.0:
                keep_ratio = 1.0
            elif keep_ratio < 0.01:
                keep_ratio = 0.01
                
            app.logger.info(f"Simplifying {filepath}... Size: {file_size_mb:.2f}MB, Target Ratio: {keep_ratio:.3f}")
            
            simplify_stl(filepath, proxy_path, keep_ratio=keep_ratio)
            
        except Exception as e:
            app.logger.error(f"Simplify task error: {e}")
            
        # Update status to uploaded regardless of success or failure of proxy generation
        # So the user can still slice or download it
        print_file = PrintFile.query.get(file_id)
        if print_file:
            print_file.status = 'uploaded'
            db.session.commit()
        db.session.remove()
