# -*- coding: utf-8 -*-
'''
Created on Apr 10, 2015

@author: ymh
'''

import dateutil.parser
import logging
from optparse import make_option
import re
import time
import urlparse

from django.conf import settings
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group
from django.core.management.base import BaseCommand, CommandError
from guardian.shortcuts import remove_perm

from ldt.ldt_utils.models import Content, Media
from ldt.ldt_utils.stat import update_stat_content
from ldt.ldt_utils.utils import generate_uuid
from ldt.security.cache import cached_assign
from ldt.security.utils import assign_perm_to_obj


logger = logging.getLogger(__name__)


class Command(BaseCommand):

    formats = ["%M:%S", "%H:%M:%S", "%Hh%M", "%Ss", "%Ssec", "%Mmn %Ss"]

    def get_duration(self, value):
        dur = None
        for f in self.formats:
            if f.startswith("%Ss"):
                m = re.search("(\d+)s(?:ec)?", value)
                if m:
                    dur = int(m.group(1))*1000
                    break
            else:
                try:
                    dur = time.strptime(value, f)
                    dur = (dur.tm_hour*3600 + dur.tm_min*60 + dur.tm_sec) * 1000
                    break
                except:
                    pass
        return dur


    help = 'Create a content (and Media)'
    option_list = BaseCommand.option_list + (

        #TODO: source is compulsory
        make_option("-s", "--source",
                  dest="source",
                  action="store",
                  type="string",
                  help="The media source"),
        #TODO: title is compulsory
        make_option("-t", "--title",
                  dest="title",
                  action="store",
                  type="string",
                  help="The content title"),
        #TODO: optional
        make_option("-V", "--videopath",
                  dest="videopath",
                  action="store",
                  type="string",
                  default=settings.STREAM_URL,
                  help="The media videopath"),
        #TODO: optional
        make_option("--media-title",
                  dest="media_title",
                  action="store",
                  type="string",
                  help="The media title. Optional, same as content title"),

        make_option("--description",
                  dest="description",
                  action="store",
                  type="string",
                  default='',
                  help="The description. Optional, same as content title"),

        make_option("--media-description",
                  dest="media_description",
                  action="store",
                  type="string",
                  help="The media description. Optional, same as content description"),

        #TODO: optional
        make_option("-d", "--duration",
                  dest="duration",
                  action="store",
                  type="string",
                  help="Media duration"),

        make_option("-p", "--public",
                    dest="public",
                    action="store_true",
                    default=False,
                    help="Is the media/content public ?"
                    ),

        make_option("-r", "--read",
                    dest="readers",
                    action="store",
                    type="string",
                    default=None,
                    help="comma separated list of user/group with read access"
                    ),
        make_option("-w", "--write",
                    dest="writers",
                    action="store",
                    type="string",
                    default=None,
                    help="comma separated list of user/group with write access"
                    ),

        make_option("-u", "--update",
                    dest='update',
                    action="store_true",
                    default=False,
                    help="update objects when not created"
                    ),

        make_option("-T", "--tags",
                    dest='tags',
                    action="store",
                    type="string",
                    default='',
                    help="comma separated list of tags"
                    ),
        make_option("-c", "--creator",
                    dest='creator',
                    action="store",
                    type="string",
                    default=None,
                    help="The handle for object creator."
                    ),

        make_option("--external-id",
                    dest='external_id',
                    action="store",
                    type="string",
                    default = None,
                    help="The media external id"
                    ),

        make_option("-C", "--creation-date",
                    dest='creation_date',
                    action="store",
                    type="string",
                    default = None,
                    help="The creation date in ISO 8601 format (2008-09-03T20:56:35.450686)"
                    ),


       )


    def handle(self, *args, **options):
        #BaseCommand.handle(self, *args, **options)

        title = options.get('title', '')
        if not title:
            raise CommandError("Title s compulsory")
        title = title.decode("utf-8")

        media_title = options.get('media_title', '')
        media_title = title if not media_title else media_title.decode("utf-8")

        src = options.get('source', None)
        if src:
            src = src.decode("utf-8")

        if not src:
            raise CommandError("Source option is compulsory")
        videopath = options.get('videopath', settings.STREAM_URL)
        url_parts = urlparse.urlparse(src)
        if url_parts.scheme in ['http','rtmp', 'https']:
            videopath = ''
        #TODO : test url is relative path
        duration_str = options.get('duration', '')
        duration = self.get_duration(duration_str)
        if duration is None:
            raise CommandError("Duration %r not recognized" % duration_str)

        description = options.get('description', '')
        if description:
            description  = description.decode("utf-8")

        media_description = options.get('media_description', '')

        if not media_description:
            media_description = description
        else:
            media_description.decode("utf-8")

        public = options.get('public', False)

        tags_str = options.get('tags', '')
        if tags_str:
            tags_str = tags_str.decode("utf-8")

        tags = filter(lambda t: t, [t.strip() for t in tags_str.split(",")]) if tags_str else []

        creator_str = options.get("creator", None)
        User = get_user_model()

        creator = None

        if creator_str:
            try:
                creator = User.objects.get(username=creator_str)
            except User.DoesNotExist:
                raise CommandError("Creator user %s not found" % creator_str)
        else:
            #TODO: replace by first()
            try:
                creator = User.objects.filter(is_superuser=True)[0]
            except IndexError:
                creator = None

        if creator is None:
            raise CommandError("Creator not found")

        readers_str = options.get("readers", "")
        writers_str = options.get("writers", "")

        readers = filter(lambda s: s, [r.strip() for r in  readers_str.split(',')]) if readers_str else []
        writers = filter(lambda s: s, [r.strip() for r in  writers_str.split(',')]) if writers_str else []

        readers_list = set(readers+writers)


        if readers_list:
            read_list = list(User.objects.filter(username__in=readers_list)) + list(Group.objects.filter(name__in=readers_list))
        else:
            read_list = []

        if writers:
            write_list = list(User.objects.filter(username__in = writers)) + list(Group.objects.filter(name__in = writers))
        else:
            write_list = []

        external_id = options.get("external_id", None)

        update_objects = options.get('update', False)

        creation_date_str = options.get('creation_date', None)

        creation_date = dateutil.parser.parse(creation_date_str) if creation_date_str else None

        #TODO: wrap everything in transaction
        defaults_values = {
            'videopath': videopath,
            'title': media_title,
            'duration': duration,
            'description': media_description,
            'creator': creator,
            'external_id': external_id,
            'media_creation_date': creation_date
        }

        media, created = Media.objects.get_or_create(src=src, defaults= defaults_values)

        if not created and update_objects:
            for k,v in defaults_values.items():
                setattr(media, k, v)
            media.save()

        if created or update_objects:
            media.is_public = public
            assign_perm_to_obj(media, read_list, write_list, creator)

        content_uuid = generate_uuid()
        content_iriurl = "%s/%s.iri" % (content_uuid, content_uuid);
        content = Content.objects.create(
            iri_id = content_uuid,
            iriurl = content_iriurl,
            media_obj=media,
            title=title,
            description=description,
            duration=duration,
            content_creation_date=creation_date
        )

        content.tags.add(*tags)

        everyone = Group.objects.get(name=settings.PUBLIC_GROUP_NAME)
        if public:
            cached_assign('view_content', everyone, content)
            cached_assign('view_media', everyone, media)
        else:
            remove_perm('ldt_utils.view_media', everyone, media)
            remove_perm('ldt_utils.view_content', everyone, content)
            assign_perm_to_obj(content, read_list, write_list, creator)
            assign_perm_to_obj(media, read_list, write_list, creator)

        content.is_public = public
        content.save()

        assign_perm_to_obj(content, read_list, write_list, creator)
        update_stat_content(content)

        return content.iri_id
