# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
#
# Copyright (C) 2017-2019 Canonical Ltd
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 3 as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
import json
from typing import Any, Dict, List  # noqa
from urllib import parse

from tests import fake_servers


class FakeSnapdRequestHandler(fake_servers.BaseHTTPRequestHandler):

    snaps_result = []  # type: List[Dict[str, Any]]
    snap_details_func = None
    find_result = []  # type: List[Dict[str, Any]]
    find_exit_code = 200  # type: int
    _private_data = {"new_fake_snap_installed": False}

    def do_GET(self):
        parsed_url = parse.urlparse(self.path)
        if parsed_url.path == "/v2/snaps":
            self._handle_snaps()
        elif parsed_url.path.startswith("/v2/snaps/") and parsed_url.path.endswith(
            "file"
        ):
            self._handle_snap_file(parsed_url)
        elif parsed_url.path.startswith("/v2/snaps/"):
            self._handle_snap_details(parsed_url)
        elif parsed_url.path == "/v2/find":
            self._handle_find(parsed_url)
        else:
            self.wfile.write(parsed_url.path.encode())

    def _handle_snaps(self):
        status_code = self.find_exit_code
        params = self.snaps_result
        self.send_response(status_code)
        self.send_header("Content-Type", "text/application+json")
        self.end_headers()
        response = json.dumps({"result": params}).encode()
        self.wfile.write(response)

    def _handle_snap_file(self, parsed_url):
        self.send_response(200)
        self.send_header("Content-Length", len(parsed_url))
        self.send_header("Content-type", "text/plain")
        self.end_headers()
        self.wfile.write(parsed_url.encode())

    def _handle_snap_details(self, parsed_url):
        status_code = 404
        params = {"message": "not found"}
        type_ = "error"
        snap_name = parsed_url.path.split("/")[-1]
        if self.snap_details_func:
            status_code, params = self.snap_details_func(snap_name)
        else:
            for snap in self.snaps_result:
                if snap["name"] == snap_name:
                    status_code = 200
                    type_ = "sync"
                    params = {}
                    for key in (
                        "channel",
                        "revision",
                        "confinement",
                        "id",
                        "tracking-channel",
                    ):
                        if key in snap:
                            params.update({key: snap[key]})
                    break

        self.send_response(status_code)
        self.send_header("Content-Type", "text/application+json")
        self.end_headers()
        response = json.dumps({"result": params, "type": type_}).encode()

        self.wfile.write(response)

    def _handle_find(self, parsed_url):
        query = parse.parse_qs(parsed_url.query)
        snap_name = query["name"][0]
        status_code = 404
        params = {}
        for result in self.find_result:
            if snap_name in result:
                status_code = 200
                params = result[snap_name]
                break
        if snap_name == "new-fake-snap":
            status_code = 200
            params = {"channels": {"latest/stable": {"confinement": "strict"}}}
        elif snap_name in ("core16", "core18"):
            status_code = 200
            params = {
                "channels": {
                    "latest/stable": {"confinement": "strict", "revision": "10"}
                }
            }

        self.send_response(status_code)
        self.send_header("Content-Type", "text/application+json")
        self.end_headers()
        response = json.dumps({"result": [params]}).encode()
        self.wfile.write(response)
