
import os
from flask import request, current_app
from flask_restx import Namespace, Resource, fields, reqparse
from werkzeug.datastructures import FileStorage

from app.models.file import File
from app.core.extensions import db

file_namespace = Namespace('files', description='File operations')

file_model = file_namespace.model('File', { 
    'id': fields.Integer(readonly=True, description='The file unique identifier'),
    'name': fields.String(required=True, description='The file name'),
    'extension': fields.String(required=True, description='The file extension'),
    'content_type': fields.String(required=True, description='The file content type'),
    'size': fields.Integer(required=True, description='The file size in bytes'), 
    'filepath': fields.String(readonly=True, description='The file URL'),
    'uploaded_at': fields.DateTime(required=True, description='The file upload timestamp'),
    'updated_at': fields.DateTime(required=True, description='The file last update timestamp'),
})

file_parser = reqparse.RequestParser()
file_parser.add_argument('file', location='files', type=FileStorage, required=True, help='File to be uploaded')

@file_namespace.route('/')
class FileList(Resource):
    @file_namespace.marshal_with(file_model, envelope='files')
    def get(self):
        return File.query.all()

    @file_namespace.expect(file_parser)
    @file_namespace.marshal_with(file_model, code=201)
    def post(self):
        args = file_parser.parse_args()
        file_storage = args['file']

        try:
            # upload_dir = os.path.join(current_app.root_path, current_app.config['UPLOAD_DIR'])
            upload_dir =  current_app.config['UPLOAD_DIR']
            file = File.create(file_storage, upload_dir)
            db.session.add(file)
            db.session.commit()

            # Check if the file was saved successfully
            if os.path.exists(file.filepath):
                # Check if the file was created successfully
                if file:
                    # File was created successfully
                    return file, 201
                else:
                    return {'message': 'File uploaded, but failed to save in the database.'}, 500
            else:
                return {'message': 'Failed to save the file.'}, 500

        except Exception as e:
            print(f"Error saving file: {e}")
            return {'message': 'An error occurred while saving the file.'}, 500
        
    def delete(self):
        try:  
            # Query all files from the database
            files = File.query.all()

            # Loop over each file
            for file in files:
                file_deleted = file.delete(file.id)

                # If file is not deleted, return false
                if not file_deleted:
                    return {'message': f'Failed to delete file: {file.id}'}, 500

            return {'message': 'All files deleted successfully.'}, 200
        except Exception as e:
            print(f"Error deleting files: {e}")
            db.session.rollback()  # Rollback changes if an error occurs
            return {'message': 'An error occurred while deleting files.'}, 500
        
@file_namespace.route('/<int:file_id>')
class SingleFile(Resource):
    @file_namespace.marshal_with(file_model)
    def get(self, file_id):
        file = File.query.get(file_id)
        if not file:
            return {'message': 'File not found'}, 404
        return file, 200

    def delete(self, file_id):
        file = File.query.get(file_id)
        if not file:
            return {'message': 'File not found'}, 404

        try:
            file_deleted = file.delete(file_id) 
            # If file is deleted successfully, commit changes and return success message
            if file_deleted:
                db.session.commit()
                return {'message': 'File deleted successfully'}, 200
            else:
                return {'message': 'Failed to delete file'}, 500
        except Exception as e:
            print(f"Error deleting file: {e}")
            db.session.rollback()
            return {'message': 'An error occurred while deleting the file.'}, 500
    
    @file_namespace.expect(file_model, validate=False)
    @file_namespace.marshal_with(file_model)
    def put(self, file_id):
        try:
            # Retrieve the file object from the database
            file = File.query.get(file_id)
            if not file:
                return {'message': 'File not found'}, 404

            # Extract the new name from the request JSON payload
            data = request.json
            new_name = data.get('name')

            # Update the file name if a new name is provided
            if new_name: 
                file.update(new_name)  # Save changes to the database
                return file, 200
            else:
                return {'message': 'No new name provided'}, 400

        except Exception as e:
            print(f"Error updating file name: {e}")
            return {'message': 'Failed to update file name. Please try again later.'}, 500