#!/usr/bin/env python

# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

import argparse
import os
import socket
import sys
import webbrowser

import six
from mozlog import commandline, get_proxy_logger
from mozlog.commandline import add_logging_group

here = os.path.abspath(os.path.dirname(__file__))
LOG = get_proxy_logger("profiler")

if six.PY2:
    # Import for Python 2
    from urllib import quote

    from SimpleHTTPServer import SimpleHTTPRequestHandler
    from SocketServer import TCPServer
else:
    # Import for Python 3
    from http.server import SimpleHTTPRequestHandler
    from socketserver import TCPServer
    from urllib.parse import quote


class ProfileServingHTTPRequestHandler(SimpleHTTPRequestHandler):
    """Extends the basic SimpleHTTPRequestHandler (which serves a directory
    of files) to include request headers required by profiler.firefox.com"""

    def end_headers(self):
        self.send_header("Access-Control-Allow-Origin", "https://profiler.firefox.com")
        SimpleHTTPRequestHandler.end_headers(self)


class ViewGeckoProfile:
    """Container class for ViewGeckoProfile"""

    def __init__(self, gecko_profile_data_path):
        self.gecko_profile_data_path = gecko_profile_data_path
        self.gecko_profile_dir = os.path.dirname(gecko_profile_data_path)
        self.profiler_url = "https://profiler.firefox.com/from-url/"
        self.httpd = None
        self.host = "127.0.0.1"
        self.port = None
        self.oldcwd = os.getcwd()

    def setup_http_server(self):
        # pick a free port
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.bind(("", 0))
        self.port = sock.getsockname()[1]
        sock.close()

        # Temporarily change the directory to the profile directory.
        os.chdir(self.gecko_profile_dir)
        self.httpd = TCPServer((self.host, self.port), ProfileServingHTTPRequestHandler)

    def handle_single_request(self):
        self.httpd.handle_request()
        # Go back to the old cwd, which some infrastructure may be relying on.
        os.chdir(self.oldcwd)

    def encode_url(self):
        # Encode url i.e.: https://profiler.firefox.com/from-url/http...
        file_url = f"http://{self.host}:{self.port}/{os.path.basename(self.gecko_profile_data_path)}"

        self.profiler_url = self.profiler_url + quote(file_url, safe="")
        LOG.info("Temporarily serving the profile from: %s" % file_url)

    def open_profile_in_browser(self):
        # Open the file in the user's preferred browser.
        LOG.info("Opening the profile: %s" % self.profiler_url)
        webbrowser.open_new_tab(self.profiler_url)


def create_parser(mach_interface=False):
    parser = argparse.ArgumentParser()
    add_arg = parser.add_argument

    add_arg(
        "-p",
        "--profile-zip",
        required=True,
        dest="profile_zip",
        help="path to the gecko profiles zip file to open in profiler.firefox.com",
    )

    add_logging_group(parser)
    return parser


def verify_options(parser, args):
    ctx = vars(args)

    if not os.path.isfile(args.profile_zip):
        parser.error("{profile_zip} does not exist!".format(**ctx))


def parse_args(argv=None):
    parser = create_parser()
    args = parser.parse_args(argv)
    verify_options(parser, args)
    return args


def view_gecko_profile(profile_path):
    """
    Open a gecko profile in the user's default browser. This function opens
    up a special URL to profiler.firefox.com and serves up the local profile.
    """
    view_gecko_profile = ViewGeckoProfile(profile_path)

    view_gecko_profile.setup_http_server()
    view_gecko_profile.encode_url()
    view_gecko_profile.open_profile_in_browser()
    view_gecko_profile.handle_single_request()


def start_from_command_line():
    args = parse_args(sys.argv[1:])
    commandline.setup_logging("view-gecko-profile", args, {"tbpl": sys.stdout})

    view_gecko_profile(args.profile_zip)


if __name__ == "__main__":
    start_from_command_line()
