from nawah.base_module import BaseModule
from nawah.enums import Event
from nawah.classes import ATTR, PERM, METHOD
from nawah.config import Config
from nawah.registry import Registry
from nawah.utils import _extract_attr, validate_attr

from bson import ObjectId

import base64


class File(BaseModule):
	'''`File` module provides functionality for `File Upload Workflow`.'''

	collection = 'files'
	attrs = {
		'user': ATTR.ID(desc='`_id` of `User` doc file belongs to.'),
		'file': ATTR.FILE(desc='File object.'),
		'create_time': ATTR.DATETIME(
			desc='Python `datetime` ISO format of the doc creation.'
		),
	}
	methods = {
		'read': METHOD(permissions=[PERM(privilege='__sys')]),
		'create': METHOD(
			permissions=[PERM(privilege='create')],
			post_method=True,
		),
		'delete': METHOD(permissions=[PERM(privilege='__sys')]),
	}

	async def on_read(self, results, skip_events, env, query, doc, payload):
		for i in range(len(results['docs'])):
			results['docs'][i]['file']['lastModified'] = int(
				results['docs'][i]['file']['lastModified']
			)
		return (results, skip_events, env, query, doc, payload)

	async def pre_create(self, skip_events, env, query, doc, payload):
		if Config.file_upload_limit != -1 and len(doc['file']) > Config.file_upload_limit:
			raise self.exception(
				status=400,
				msg=f'File size is beyond allowed limit.',
				args={
					'code': 'INVALID_SIZE',
					'attr': doc['__attr'].decode('utf-8'),
					'name': doc['name'].decode('utf-8'),
				},
			)
		if (module := doc['__module'].decode('utf-8')) not in Config.modules.keys():
			raise self.exception(
				status=400,
				msg=f'Invalid module \'{module}\'',
				args={'code': 'INVALID_MODULE'},
			)

		try:
			attr_type = _extract_attr(
				scope=Registry.module(module).attrs,
				attr_path='$__' + (attr := doc['__attr'].decode('utf-8')),
			)
			doc = {
				'file': {
					'name': doc['name'].decode('utf-8'),
					'type': doc['type'].decode('utf-8'),
					'size': len(doc['file']),
					'lastModified': int(doc['lastModified'].decode('utf-8')),
					'content': doc['file'],
				},
			}
			try:
				attr_val = doc['file']
				if attr_type._type == 'LIST':
					attr_val = [doc['file']]
				await validate_attr(
					mode='create', attr_name=attr, attr_type=attr_type, attr_val=attr_val
				)
			except:
				raise self.exception(
					status=400,
					msg=f'Invalid file for \'{attr}\' of module \'{module}\'',
					args={'code': 'INVALID_FILE'},
				)

		except:
			raise self.exception(
				status=400,
				msg=f'Invalid attr \'{attr}\' of module \'{module}\'',
				args={'code': 'INVALID_ATTR'},
			)

		return (skip_events, env, query, doc, payload)
