import mimetypes
import urllib.parse
import os
import re
from youtube import local_playlist, watch, search, playlist, channel, comments, post_comment, accounts, util, subscriptions
import settings
YOUTUBE_FILES = (
    "/shared.css",
    '/comments.css',
    '/favicon.ico',
)
get_handlers = {
    'search':           search.get_search_page,
    '':                 search.get_search_page,
    'watch':            watch.get_watch_page,
    'playlist':         playlist.get_playlist_page,

    'channel':          channel.get_channel_page,
    'user':             channel.get_channel_page_general_url,
    'c':                channel.get_channel_page_general_url,

    'playlists':        local_playlist.get_playlist_page,

    'comments':         comments.get_comments_page,
    'post_comment':     post_comment.get_post_comment_page,
    'delete_comment':   post_comment.get_delete_comment_page,
    'login':            accounts.get_account_login_page,

    'subscriptions':            subscriptions.get_subscriptions_page,
    'subscription_manager':     subscriptions.get_subscription_manager_page,
}
post_handlers = {
    'edit_playlist':    local_playlist.edit_playlist,
    'playlists':        local_playlist.path_edit_playlist,

    'login':            accounts.add_account,
    'comments':         post_comment.post_comment,
    'post_comment':     post_comment.post_comment,
    'delete_comment':   post_comment.delete_comment,

    'subscriptions':    subscriptions.post_subscriptions_page,
    'subscription_manager':     subscriptions.post_subscription_manager_page,
    'import_subscriptions':     subscriptions.import_subscriptions,
}

def youtube(env, start_response):
    path, method, query_string = env['PATH_INFO'], env['REQUEST_METHOD'], env['QUERY_STRING']
    env['qs_parameters'] = urllib.parse.parse_qs(query_string)
    env['parameters'] = dict(env['qs_parameters'])

    path_parts = path.rstrip('/').lstrip('/').split('/')
    env['path_parts'] = path_parts

    if method == "GET":
        try:
            handler = get_handlers[path_parts[0]]
        except KeyError:
            pass
        else:
            return handler(env, start_response)

        if path in YOUTUBE_FILES:
            with open("youtube" + path, 'rb') as f:
                mime_type = mimetypes.guess_type(path)[0] or 'application/octet-stream'
                start_response('200 OK',  (('Content-type',mime_type),) )
                return f.read()

        elif path.startswith('/data/playlist_thumbnails/') or path.startswith('/data/subscription_thumbnails/'):
            with open(os.path.join(settings.data_dir, os.path.normpath(path[6:])), 'rb') as f:
                start_response('200 OK',  (('Content-type', "image/jpeg"),) )
                return f.read()

        elif path.startswith("/api/"):
            start_response('200 OK',  [('Content-type', 'text/vtt'),] )
            result = util.fetch_url('https://www.youtube.com' + path + ('?' + query_string if query_string else ''))
            result = result.replace(b"align:start position:0%", b"")
            return result

        elif path == "/opensearch.xml":
            with open("youtube" + path, 'rb') as f:
                mime_type = mimetypes.guess_type(path)[0] or 'application/octet-stream'
                start_response('200 OK',  (('Content-type',mime_type),) )
                return f.read().replace(b'$port_number', str(settings.port_number).encode())

        elif path == "/comment_delete_success":
            start_response('200 OK', [('Content-type', 'text/plain'),] )
            return b'Successfully deleted comment'

        elif path == "/comment_delete_fail":
            start_response('200 OK',  [('Content-type', 'text/plain'),] )
            return b'Failed to deleted comment'

        else:
            return channel.get_channel_page_general_url(env, start_response)

    elif method == "POST":
        content_type = env['CONTENT_TYPE']
        if content_type == 'application/x-www-form-urlencoded':
            post_parameters = urllib.parse.parse_qs(env['wsgi.input'].read().decode())
            env['post_parameters'] = post_parameters
            env['parameters'].update(post_parameters)

        # Ugly hack that will be removed once I clean up this trainwreck and switch to a microframework
        # Only supports a single file with no other fields
        elif content_type.startswith('multipart/form-data'):
            content = env['wsgi.input'].read()

            # find double line break
            file_start = content.find(b'\r\n\r\n')
            if file_start == -1:
                start_response('400 Bad Request', ())
                return b'400 Bad Request'

            file_start += 4

            lines = content[0:file_start].splitlines()
            boundary = lines[0]

            file_end = content.find(boundary, file_start)
            if file_end == -1:
                start_response('400 Bad Request', ())
                return b'400 Bad Request'
            file_end -= 2  # Subtract newlines
            file = content[file_start:file_end]

            properties = dict()
            for line in lines[1:]:
                line = line.decode('utf-8')
                colon = line.find(':')
                if colon == -1:
                    continue
                properties[line[0:colon]] = line[colon+2:]

            mime_type = properties['Content-Type']
            field_name = re.search(r'name="([^"]*)"' , properties['Content-Disposition'])
            if field_name is None:
                start_response('400 Bad Request', ())
                return b'400 Bad Request'
            field_name = field_name.group(1)

            env['post_parameters'] = {field_name: (mime_type, file)}
            env['parameters'][field_name] = (mime_type, file)

        else:
            start_response('400 Bad Request', ())
            return b'400 Bad Request'

        try:
            handler = post_handlers[path_parts[0]]
        except KeyError:
            pass
        else:
            return handler(env, start_response)

        start_response('404 Not Found', [('Content-type', 'text/plain'),])
        return b'404 Not Found'

    else:
        start_response('501 Not Implemented', [('Content-type', 'text/plain'),])
        return b'501 Not Implemented'