import debug                            # pyflakes:ignore
import json
import os
import shutil
from apiclient.discovery import build
from apiclient.http import HttpMock
from mock import patch

from django.conf import settings
from django.urls import reverse

from ietf.doc.models import Document
from ietf.group.models import Group
from ietf.meeting.factories import SessionFactory
from ietf.meeting.models import Session, TimeSlot, SchedTimeSessAssignment
from ietf.meeting.test_data import make_meeting_test_data
from ietf.name.models import SessionStatusName
from ietf.utils.test_data import make_test_data
from ietf.utils.test_utils import TestCase
from ietf.utils.mail import outbox
from ietf.secr.proceedings.proc_utils import (create_proceedings, import_audio_files,
    get_timeslot_for_filename, normalize_room_name, send_audio_import_warning,
    get_or_create_recording_document, create_recording, get_next_sequence,
    get_youtube_playlistid, get_youtube_videos, import_youtube_video_urls,
    _get_session, _get_urls_from_json)


SECR_USER='secretary'

class ProceedingsTestCase(TestCase):
    def test_main(self):
        "Main Test"
        make_test_data()
        url = reverse('ietf.secr.proceedings.views.main')
        self.client.login(username="secretary", password="secretary+password")
        response = self.client.get(url)
        self.assertEqual(response.status_code, 200)
        # test chair access
        self.client.logout()
        self.client.login(username="marschairman", password="marschairman+password")
        response = self.client.get(url)
        self.assertEqual(response.status_code, 200)


class VideoRecordingTestCase(TestCase):
    @patch('ietf.secr.proceedings.proc_utils.get_youtube_videos')
    @patch('ietf.secr.proceedings.proc_utils.get_youtube_playlistid')
    def test_import_youtube_video_urls(self, mock_playlistid, mock_videos):
        meeting = make_meeting_test_data()
        session = Session.objects.filter(meeting=meeting, group__acronym='mars').first()
        title = self._get_video_title_for_session(session)
        url = 'https://youtube.com?v=test'
        mock_playlistid.return_value = 'PLC86T-6ZTP5g87jdxNqdWV5475U-yEE8M'
        mock_videos.return_value = [{'title':title,'url':url}]
        discovery = os.path.join(settings.BASE_DIR, "../test/data/youtube-discovery.json")
        http = HttpMock(discovery, {'status': '200'})
        import_youtube_video_urls(meeting=meeting, http=http)
        doc = Document.objects.get(external_url=url)
        self.assertTrue(doc in session.materials.all())

    def _get_video_title_for_session(self, session):
        '''Returns the youtube video title of a session recording given session'''
        timeslot = session.official_timeslotassignment().timeslot
        return "{prefix}-{group}-{date}".format(
            prefix=session.meeting.type.slug + session.meeting.number,
            group=session.group.acronym,
            date=timeslot.time.strftime('%Y%m%d-%H%M')).upper()

    def test_get_youtube_playlistid(self):
        discovery = os.path.join(settings.BASE_DIR, "../test/data/youtube-discovery.json")
        http = HttpMock(discovery, {'status': '200'})
        youtube = build(settings.YOUTUBE_API_SERVICE_NAME, settings.YOUTUBE_API_VERSION,
            developerKey='',http=http)
        path = os.path.join(settings.BASE_DIR, "../test/data/youtube-playlistid.json")
        http = HttpMock(path, {'status': '200'})
        self.assertEqual(get_youtube_playlistid(youtube, 'IETF98', http=http),'PLC86T-test')
  
    def test_get_youtube_videos(self):
        discovery = os.path.join(settings.BASE_DIR, "../test/data/youtube-discovery.json")
        http = HttpMock(discovery, {'status': '200'})
        youtube = build(settings.YOUTUBE_API_SERVICE_NAME, settings.YOUTUBE_API_VERSION,
            developerKey='',http=http)
        path = os.path.join(settings.BASE_DIR, "../test/data/youtube-playlistitems.json")
        http = HttpMock(path, {'status': '200'})
        videos = get_youtube_videos(youtube, 'PLC86T', http=http)
        self.assertEqual(len(videos),2)

    def test_get_session(self):
        meeting = make_meeting_test_data()
        session = Session.objects.filter(meeting=meeting, group__acronym='mars').first()
        number = meeting.number
        name = session.group.acronym
        date = session.official_timeslotassignment().timeslot.time.strftime('%Y%m%d')
        time = session.official_timeslotassignment().timeslot.time.strftime('%H%M')
        self.assertEqual(_get_session(number,name,date,time),session)

    def test_get_urls_from_json(self):
        path = os.path.join(settings.BASE_DIR, "../test/data/youtube-playlistitems.json")
        with open(path) as f:
            doc = json.load(f)
        urls = _get_urls_from_json(doc)
        self.assertEqual(len(urls),2)
        self.assertEqual(urls[0]['title'],'IETF98 Wrap Up')
        self.assertEqual(urls[0]['url'],'https://www.youtube.com/watch?v=lhYWB5FFkg4&list=PLC86T-6ZTP5jo6kIuqdyeYYhsKv9sUwG1')
        
class RecordingTestCase(TestCase):
    def setUp(self):
        self.meeting_recordings_dir = self.tempdir('meeting-recordings')
        self.saved_meeting_recordings_dir = settings.MEETING_RECORDINGS_DIR
        settings.MEETING_RECORDINGS_DIR = self.meeting_recordings_dir

    def tearDown(self):
        shutil.rmtree(self.meeting_recordings_dir)
        settings.MEETING_RECORDINGS_DIR = self.saved_meeting_recordings_dir

    def test_page(self):
        meeting = make_meeting_test_data()
        url = reverse('ietf.secr.proceedings.views.recording', kwargs={'meeting_num':meeting.number})
        self.client.login(username="secretary", password="secretary+password")
        response = self.client.get(url)
        self.assertEqual(response.status_code, 200)

    def test_post(self):
        meeting = make_meeting_test_data()
        group = Group.objects.get(acronym='mars')
        session = Session.objects.filter(meeting=meeting,group=group).first()
        # explicitly set to scheduled for this test
        status = SessionStatusName.objects.get(slug='sched')
        session.status = status
        session.save()
        url = reverse('ietf.secr.proceedings.views.recording', kwargs={'meeting_num':meeting.number})
        data = dict(group=group.acronym,external_url='http://youtube.com/xyz',session=session.pk)
        self.client.login(username="secretary", password="secretary+password")
        response = self.client.post(url,data,follow=True)
        self.assertEqual(response.status_code, 200)
        self.failUnless(group.acronym in response.content)
        
        # now test edit
        doc = session.materials.filter(type='recording').first()
        external_url = 'http://youtube.com/aaa'
        url = reverse('ietf.secr.proceedings.views.recording_edit', kwargs={'meeting_num':meeting.number,'name':doc.name})
        response = self.client.post(url,dict(external_url=external_url),follow=True)
        self.assertEqual(response.status_code, 200)
        self.failUnless(external_url in response.content)
            
    def test_import_audio_files(self):
        meeting = make_meeting_test_data()
        group = Group.objects.get(acronym='mars')
        session = Session.objects.filter(meeting=meeting,group=group).first()
        status = SessionStatusName.objects.get(slug='sched')
        session.status = status
        session.save()
        timeslot = session.official_timeslotassignment().timeslot
        self.create_audio_file_for_timeslot(timeslot)
        import_audio_files(meeting)
        self.assertEqual(session.materials.filter(type='recording').count(),1)

    def create_audio_file_for_timeslot(self, timeslot):
        filename = self.get_filename_for_timeslot(timeslot)
        path = os.path.join(settings.MEETING_RECORDINGS_DIR,'ietf' + timeslot.meeting.number,filename)
        if not os.path.exists(os.path.dirname(path)):
            os.makedirs(os.path.dirname(path))
        with open(path, "w") as f:
            f.write('dummy')

    def get_filename_for_timeslot(self, timeslot):
        '''Returns the filename of a session recording given timeslot'''
        return "{prefix}-{room}-{date}.mp3".format(
            prefix=timeslot.meeting.type.slug + timeslot.meeting.number,
            room=normalize_room_name(timeslot.location.name),
            date=timeslot.time.strftime('%Y%m%d-%H%M'))

    def test_import_audio_files_shared_timeslot(self):
        meeting = make_meeting_test_data()
        mars_session = Session.objects.filter(meeting=meeting,group__acronym='mars').first()
        ames_session = Session.objects.filter(meeting=meeting,group__acronym='ames').first()
        scheduled = SessionStatusName.objects.get(slug='sched')
        mars_session.status = scheduled
        mars_session.save()
        ames_session.status = scheduled
        ames_session.save()
        timeslot = mars_session.official_timeslotassignment().timeslot
        SchedTimeSessAssignment.objects.create(timeslot=timeslot,session=ames_session,schedule=meeting.agenda)
        self.create_audio_file_for_timeslot(timeslot)
        import_audio_files(meeting)
        doc = mars_session.materials.filter(type='recording').first()
        self.assertTrue(doc in ames_session.materials.all())
        self.assertTrue(doc.docalias_set.filter(name='recording-42-mars-1'))
        self.assertTrue(doc.docalias_set.filter(name='recording-42-ames-1'))

    def test_normalize_room_name(self):
        self.assertEqual(normalize_room_name('Test Room'),'testroom')
        self.assertEqual(normalize_room_name('Rome/Venice'), 'rome_venice')

    def test_get_timeslot_for_filename(self):
        meeting = make_meeting_test_data()
        timeslot = TimeSlot.objects.filter(meeting=meeting,type='session').first()
        name = self.get_filename_for_timeslot(timeslot)
        self.assertEqual(get_timeslot_for_filename(name),timeslot)

    def test_get_or_create_recording_document(self):
        meeting = make_meeting_test_data()
        group = Group.objects.get(acronym='mars')
        session = Session.objects.filter(meeting=meeting,group=group).first()
        
        # test create
        filename = 'ietf42-testroom-20000101-0800.mp3'
        docs_before = Document.objects.filter(type='recording').count()
        doc = get_or_create_recording_document(filename,session)
        docs_after = Document.objects.filter(type='recording').count()
        self.assertEqual(docs_after,docs_before + 1)
        self.assertTrue(doc.external_url.endswith(filename))

        # test get
        docs_before = docs_after
        doc2 = get_or_create_recording_document(filename,session)
        docs_after = Document.objects.filter(type='recording').count()
        self.assertEqual(docs_after,docs_before)
        self.assertEqual(doc,doc2)

    def test_create_recording(self):
        meeting = make_meeting_test_data()
        group = Group.objects.get(acronym='mars')
        session = Session.objects.filter(meeting=meeting,group=group).first()
        filename = 'ietf42-testroomt-20000101-0800.mp3'
        url = settings.IETF_AUDIO_URL + 'ietf{}/{}'.format(meeting.number, filename)
        doc = create_recording(session, url)
        self.assertEqual(doc.name,'recording-42-mars-1')
        self.assertEqual(doc.group,group)
        self.assertEqual(doc.external_url,url)
        self.assertTrue(doc in session.materials.all())

    def test_get_next_sequence(self):
        meeting = make_meeting_test_data()
        group = Group.objects.get(acronym='mars')
        sequence = get_next_sequence(group,meeting,'recording')
        self.assertEqual(sequence,1)

    def test_send_audio_import_warning(self):
        length_before = len(outbox)
        send_audio_import_warning(['recording-43-badroom-20000101-0800.mp3'])
        self.assertEqual(len(outbox), length_before + 1)
        self.assertTrue('Audio file import' in outbox[-1]['Subject'])

class OldProceedingsTestCase(TestCase):
    ''' Ensure coverage of fragments of old proceedings generation until those are removed ''' 
    def setUp(self):
        self.session = SessionFactory(meeting__type_id='ietf')
        self.proceedings_dir = self.tempdir('proceedings')

        # This unintuitive bit is a consequence of the surprising implementation of meeting.get_materials_path
        self.saved_agenda_path = settings.AGENDA_PATH
        settings.AGENDA_PATH= self.proceedings_dir

        target_path = self.session.meeting.get_materials_path()
        if not os.path.exists(target_path):
            os.makedirs(target_path)

    def tearDown(self):
        shutil.rmtree(self.proceedings_dir)
        settings.AGENDA_PATH = self.saved_agenda_path

    def test_old_generate(self):
        create_proceedings(self.session.meeting,self.session.group,is_final=True)