from couchpotato import get_session
from couchpotato.api import addApiView
from couchpotato.core.event import addEvent
from couchpotato.core.helpers.encoding import toUnicode
from couchpotato.core.helpers.variable import md5, getExt
from couchpotato.core.logger import CPLog
from couchpotato.core.plugins.base import Plugin
from couchpotato.core.plugins.scanner.main import Scanner
from couchpotato.core.settings.model import FileType, File
from couchpotato.environment import Env
from tornado.web import StaticFileHandler
import os.path
import time
import traceback

log = CPLog(__name__)


class FileManager(Plugin):

    def __init__(self):
        addEvent('file.add', self.add)
        addEvent('file.download', self.download)
        addEvent('file.types', self.getTypes)

        addApiView('file.cache/(.*)', self.showCacheFile, static = True, docs = {
            'desc': 'Return a file from the cp_data/cache directory',
            'params': {
                'filename': {'desc': 'path/filename of the wanted file'}
            },
            'return': {'type': 'file'}
        })

        addApiView('file.types', self.getTypesView, docs = {
            'desc': 'Return a list of all the file types and their ids.',
            'return': {'type': 'object', 'example': """{
    'types': [
        {
            "identifier": "poster_original",
            "type": "image",
            "id": 1,
            "name": "Poster_original"
        },
        {
            "identifier": "poster",
            "type": "image",
            "id": 2,
            "name": "Poster"
        },
        etc
    ]
}"""}
        })

        addEvent('app.load', self.cleanup)
        addEvent('app.load', self.init)

    def init(self):

        for type_tuple in Scanner.file_types.values():
            self.getType(type_tuple)

    def cleanup(self):

        # Wait a bit after starting before cleanup
        time.sleep(3)
        log.debug('Cleaning up unused files')

        python_cache = Env.get('cache')._path
        try:
            db = get_session()
            for root, dirs, walk_files in os.walk(Env.get('cache_dir')):
                for filename in walk_files:
                    if os.path.splitext(filename)[1] in ['.png', '.jpg', '.jpeg']:
                        file_path = os.path.join(root, filename)
                        f = db.query(File).filter(File.path == toUnicode(file_path)).first()
                        if not f:
                            os.remove(file_path)
        except:
            log.error('Failed removing unused file: %s', traceback.format_exc())

    def showCacheFile(self, route, **kwargs):
        Env.get('app').add_handlers(".*$", [('%s%s' % (Env.get('api_base'), route), StaticFileHandler, {'path': Env.get('cache_dir')})])


    def download(self, url = '', dest = None, overwrite = False, urlopen_kwargs = None):
        if not urlopen_kwargs: urlopen_kwargs = {}

        if not dest: # to Cache
            dest = os.path.join(Env.get('cache_dir'), '%s.%s' % (md5(url), getExt(url)))

        if not overwrite and os.path.isfile(dest):
            return dest

        try:
            filedata = self.urlopen(url, **urlopen_kwargs)
        except:
            log.error('Failed downloading file %s: %s', (url, traceback.format_exc()))
            return False

        self.createFile(dest, filedata, binary = True)
        return dest

    def add(self, path = '', part = 1, type_tuple = (), available = 1, properties = None):
        if not properties: properties = {}

        type_id = self.getType(type_tuple).get('id')
        db = get_session()

        f = db.query(File).filter(File.path == toUnicode(path)).first()
        if not f:
            f = File()
            db.add(f)

        f.path = toUnicode(path)
        f.part = part
        f.available = available
        f.type_id = type_id

        db.commit()

        file_dict = f.to_dict()

        return file_dict

    def getType(self, type_tuple):

        db = get_session()
        type_type, type_identifier = type_tuple

        ft = db.query(FileType).filter_by(identifier = type_identifier).first()
        if not ft:
            ft = FileType(
                type = toUnicode(type_type),
                identifier = type_identifier,
                name = toUnicode(type_identifier[0].capitalize() + type_identifier[1:])
            )
            db.add(ft)
            db.commit()

        type_dict = ft.to_dict()
        return type_dict

    def getTypes(self):

        db = get_session()

        results = db.query(FileType).all()

        types = []
        for type_object in results:
            types.append(type_object.to_dict())

        return types

    def getTypesView(self, **kwargs):

        return {
            'types': self.getTypes()
        }
